edit mark
This commit is contained in:
parent
c706c7f10e
commit
744413b2fc
12 changed files with 350 additions and 174 deletions
|
@ -10,7 +10,7 @@ from simple_history.models import HistoricalRecords
|
|||
import uuid
|
||||
from .utils import DEFAULT_ITEM_COVER, item_cover_path
|
||||
from .mixins import SoftDeleteMixin
|
||||
# from django.conf import settings
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
class SiteName(models.TextChoices):
|
||||
|
@ -229,6 +229,10 @@ class Item(SoftDeleteMixin, PolymorphicModel):
|
|||
def url(self):
|
||||
return f'/{self.url_path}/{self.uuid}/'
|
||||
|
||||
@property
|
||||
def absolute_url(self):
|
||||
return settings.APP_WEBSITE + self.url
|
||||
|
||||
@property
|
||||
def api_url(self):
|
||||
return '/api' + self.url
|
||||
|
|
|
@ -96,7 +96,7 @@
|
|||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if item.last_editor and item.last_editor.preference.show_last_edit or user.is_staff %}
|
||||
{% if item.last_editor and item.last_editor.preference.show_last_edit %}
|
||||
<div>{% trans '最近编辑者:' %}<a href="{% url 'users:home' item.last_editor.mastodon_username %}">{{ item.last_editor | default:"" }}</a></div>
|
||||
{% endif %}
|
||||
|
||||
|
|
|
@ -33,7 +33,8 @@
|
|||
{% include "partial/_common_libs.html" with jquery=1 %}
|
||||
|
||||
<script src="{% static 'lib/js/rating-star.js' %}"></script>
|
||||
<script src="{% static 'js/detail.js' %}"></script>
|
||||
<script src="{% static 'lib/js/tag-input.js' %}"></script>
|
||||
<link href="{% static 'lib/css/tag-input.css' %}" type="text/css" media="all" rel="stylesheet">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
@ -68,7 +69,7 @@
|
|||
<div class="entity-detail__fields">
|
||||
<div class="entity-detail__rating">
|
||||
{% if item.rating %}
|
||||
<span class="entity-detail__rating-star rating-star" data-rating-score="{{ item.rating | floatformat:"0" }}"></span>
|
||||
<span class="entity-detail__rating-star rating-star" data-rating-score="{{ item.rating | floatformat:'0' }}"></span>
|
||||
<span class="entity-detail__rating-score"> {{ item.rating }} </span>
|
||||
<small>({{ item.rating_count }}人评分)</small>
|
||||
{% else %}
|
||||
|
@ -166,13 +167,13 @@
|
|||
<div class="mark-panel">
|
||||
<span class="mark-panel__status">{% trans '我' %}{% trans mark.shelf_label %}</span>
|
||||
{% if mark.rating %}
|
||||
<span class="mark-panel__rating-star rating-star" data-rating-score="{{ mark.rating | floatformat:"0" }}"></span>
|
||||
<span class="mark-panel__rating-star rating-star" data-rating-score="{{ mark.rating | floatformat:'0' }}"></span>
|
||||
{% endif %}
|
||||
{% if mark.visibility > 0 %}
|
||||
<span class="icon-lock"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M17,8.48h-.73V6.27a6.27,6.27,0,1,0-12.53,0V8.48H3a.67.67,0,0,0-.67.67V19.33A.67.67,0,0,0,3,20H17a.67.67,0,0,0,.67-.67V9.15A.67.67,0,0,0,17,8.48ZM6.42,6.27h0a3.57,3.57,0,0,1,7.14,0h0V8.48H6.42Z"/></svg></span>
|
||||
{% endif %}
|
||||
<span class="mark-panel__actions">
|
||||
<a href="" class="edit">{% trans '修改' %}</a>
|
||||
<a href="#" hx-get="{% url 'journal:mark' item.uuid %}" class="edit" hx-target="body" hx-swap="beforeend">{% trans '修改' %}</a>
|
||||
<form action="{% url 'books:delete_mark' mark.id %}" method="post">
|
||||
{% csrf_token %}
|
||||
<a href="" class="delete">{% trans '删除' %}</a>
|
||||
|
@ -180,7 +181,13 @@
|
|||
</span>
|
||||
<div class="mark-panel__clear"></div>
|
||||
|
||||
<div class="mark-panel__time">{{ mark.created_time }}</div>
|
||||
<div class="mark-panel__time">
|
||||
{% if mark.metadata.shared_link %}
|
||||
<a href="{{ mark.metadata.shared_link }}">{{ mark.created_time }}</a>
|
||||
{% else %}
|
||||
{{ mark.created_time }}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if mark.text %}
|
||||
<p class="mark-panel__text">{{ mark.text }}</p>
|
||||
|
@ -245,23 +252,25 @@
|
|||
{% endblock %}
|
||||
|
||||
{% block sidebar_collection %}
|
||||
{% if collection_list %}
|
||||
<div class="aside-section-wrapper">
|
||||
<div class="action-panel">
|
||||
<div class="action-panel__label">{% trans '相关收藏单' %}</div>
|
||||
<div >
|
||||
{% if collection_list %}
|
||||
{% for c in collection_list %}
|
||||
<p>
|
||||
<a href="{% url 'collection:retrieve' c.id %}">{{ c.title }}</a>
|
||||
</p>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if request.user.is_authenticated %}
|
||||
<div class="action-panel__button-group action-panel__button-group--center">
|
||||
<button class="action-panel__button add-to-list" hx-get="{% url 'collection:add_to_list' 'book' item.id %}" hx-target="body" hx-swap="beforeend">{% trans '添加到收藏单' %}</button>
|
||||
<button class="action-panel__button add-to-list" hx-get="{% url 'journal:add_to_collection' item.uuid %}" hx-target="body" hx-swap="beforeend">{% trans '添加到收藏单' %}</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -269,97 +278,44 @@
|
|||
</div>
|
||||
{% include "partial/_footer.html" %}
|
||||
</div>
|
||||
<script>
|
||||
// readonly star rating of detail display section
|
||||
let ratingLabels = $("#main .rating-star");
|
||||
$(ratingLabels).each( function(index, value) {
|
||||
let ratingScore = $(this).data("rating-score") / 2;
|
||||
$(this).starRating({
|
||||
initialRating: ratingScore,
|
||||
readOnly: true,
|
||||
});
|
||||
});
|
||||
// readonly star rating at aside section
|
||||
ratingLabels = $("#aside .rating-star");
|
||||
$(ratingLabels).each( function(index, value) {
|
||||
let ratingScore = $(this).data("rating-score") / 2;
|
||||
$(this).starRating({
|
||||
initialRating: ratingScore,
|
||||
readOnly: true,
|
||||
starSize: 15,
|
||||
});
|
||||
});
|
||||
// hide long text
|
||||
$(".entity-desc__content").each(function() {
|
||||
let copy = $(this).clone()
|
||||
.addClass('entity-desc__content--folded')
|
||||
.css("visibility", "hidden");
|
||||
$(this).after(copy);
|
||||
if ($(this).height() > copy.height()) {
|
||||
$(this).addClass('entity-desc__content--folded');
|
||||
$(this).siblings(".entity-desc__unfold-button").removeClass("entity-desc__unfold-button--hidden");
|
||||
}
|
||||
copy.remove();
|
||||
});
|
||||
|
||||
<div id="modals">
|
||||
<div class="mark-modal modal">
|
||||
<div class="mark-modal__head">
|
||||
{% if not mark %}
|
||||
<style>
|
||||
.mark-modal__title::after {
|
||||
content: "{% trans item.demonstrative %}";
|
||||
}
|
||||
</style>
|
||||
<span class="mark-modal__title"></span>
|
||||
{% else %}
|
||||
<span class="mark-modal__title">{% trans '我的标记' %}</span>
|
||||
{% endif %}
|
||||
|
||||
<span class="mark-modal__close-button modal-close">
|
||||
<span class="icon-cross">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
|
||||
<polygon
|
||||
points="20 2.61 17.39 0 10 7.39 2.61 0 0 2.61 7.39 10 0 17.39 2.61 20 10 12.61 17.39 20 20 17.39 12.61 10 20 2.61">
|
||||
</polygon>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="mark-modal__body">
|
||||
<form action="{% url 'books:create_update_mark' %}" method="post">
|
||||
{{ mark_form.media }}
|
||||
{% csrf_token %}
|
||||
{{ mark_form.id }}
|
||||
{{ mark_form.book }}
|
||||
{% if mark.rating %}
|
||||
{% endif %}
|
||||
|
||||
<div class="mark-modal__rating-star rating-star-edit"></div>
|
||||
{{ mark_form.rating }}
|
||||
<div id="statusSelection" class="mark-modal__status-radio" {% if not mark %}hidden{% endif %}>
|
||||
{{ mark_form.status }}
|
||||
</div>
|
||||
|
||||
<div class="mark-modal__clear"></div>
|
||||
|
||||
{{ mark_form.text }}
|
||||
|
||||
<div class="mark-modal__tag">
|
||||
<label>{{ mark_form.tags.label }}</label>
|
||||
{{ mark_form.tags }}
|
||||
</div>
|
||||
|
||||
<div class="mark-modal__option">
|
||||
<div class="mark-modal__visibility-radio">
|
||||
<span>{{ mark_form.visibility.label }}:
|
||||
{{ mark_form.visibility }}</span>
|
||||
</div>
|
||||
<div class="mark-modal__share-checkbox">
|
||||
{{ mark_form.share_to_mastodon }}{{ mark_form.share_to_mastodon.label }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="mark-modal__confirm-button">
|
||||
<input type="submit" class="button float-right" value="{% trans '提交' %}">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="confirm-modal modal">
|
||||
<div class="confirm-modal__head">
|
||||
<span class="confirm-modal__title">{% trans '确定要删除你的标记吗?' %}</span>
|
||||
<span class="confirm-modal__close-button modal-close">
|
||||
<span class="icon-cross">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
|
||||
<polygon
|
||||
points="20 2.61 17.39 0 10 7.39 2.61 0 0 2.61 7.39 10 0 17.39 2.61 20 10 12.61 17.39 20 20 17.39 12.61 10 20 2.61">
|
||||
</polygon>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="confirm-modal__body">
|
||||
<div class="confirm-modal__confirm-button">
|
||||
<input type="submit" class="button float-right" value="{% trans '确认' %}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-mask"></div>
|
||||
|
||||
<script>
|
||||
|
||||
</script>
|
||||
// expand hidden long text
|
||||
$(".entity-desc__unfold-button a").on('click', function() {
|
||||
$(this).parent().siblings(".entity-desc__content").removeClass('entity-desc__content--folded');
|
||||
$(this).parent(".entity-desc__unfold-button").remove();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
|
||||
</html>
|
||||
|
|
|
@ -11,9 +11,6 @@ from django.core.paginator import Paginator
|
|||
from mastodon import mastodon_request_included
|
||||
from mastodon.models import MastodonApplication
|
||||
from mastodon.api import share_mark, share_review
|
||||
from common.utils import PageLinksGenerator
|
||||
from common.views import PAGE_LINK_NUMBER, jump_or_scrape, go_relogin
|
||||
from common.models import SourceSiteEnum
|
||||
from .models import *
|
||||
# from .forms import *
|
||||
# from .forms import BookMarkStatusTranslator
|
||||
|
@ -22,6 +19,7 @@ from collection.models import CollectionItem
|
|||
from common.scraper import get_scraper_by_url, get_normalized_url
|
||||
from django.utils.baseconv import base62
|
||||
from journal.models import Mark
|
||||
from journal.models import query_visible
|
||||
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
@ -48,65 +46,9 @@ def retrieve(request, item_path, item_uid):
|
|||
mark_form = None
|
||||
if request.user.is_authenticated:
|
||||
mark = Mark(request.user, item)
|
||||
_logger.info(mark.rating)
|
||||
review = mark.review
|
||||
|
||||
# # retreive tags
|
||||
# book_tag_list = book.book_tags.values('content').annotate(
|
||||
# tag_frequency=Count('content')).order_by('-tag_frequency')[:TAG_NUMBER]
|
||||
|
||||
# # retrieve user mark and initialize mark form
|
||||
# try:
|
||||
# if request.user.is_authenticated:
|
||||
# mark = BookMark.objects.get(owner=request.user, book=book)
|
||||
# except ObjectDoesNotExist:
|
||||
# mark = None
|
||||
# if mark:
|
||||
# mark_tags = mark.bookmark_tags.all()
|
||||
# mark.get_status_display = BookMarkStatusTranslator(mark.status)
|
||||
# mark_form = BookMarkForm(instance=mark, initial={
|
||||
# 'tags': mark_tags
|
||||
# })
|
||||
# else:
|
||||
# mark_form = BookMarkForm(initial={
|
||||
# 'book': book,
|
||||
# 'visibility': request.user.get_preference().default_visibility if request.user.is_authenticated else 0,
|
||||
# 'tags': mark_tags
|
||||
# })
|
||||
|
||||
# # retrieve user review
|
||||
# try:
|
||||
# if request.user.is_authenticated:
|
||||
# review = BookReview.objects.get(owner=request.user, book=book)
|
||||
# except ObjectDoesNotExist:
|
||||
# review = None
|
||||
|
||||
# # retrieve other related reviews and marks
|
||||
# if request.user.is_anonymous:
|
||||
# # hide all marks and reviews for anonymous user
|
||||
# mark_list = None
|
||||
# review_list = None
|
||||
# mark_list_more = None
|
||||
# review_list_more = None
|
||||
# else:
|
||||
# mark_list = BookMark.get_available_for_identicals(book, request.user)
|
||||
# review_list = BookReview.get_available_for_identicals(book, request.user)
|
||||
# mark_list_more = True if len(mark_list) > MARK_NUMBER else False
|
||||
# mark_list = mark_list[:MARK_NUMBER]
|
||||
# for m in mark_list:
|
||||
# m.get_status_display = BookMarkStatusTranslator(m.status)
|
||||
# review_list_more = True if len(
|
||||
# review_list) > REVIEW_NUMBER else False
|
||||
# review_list = review_list[:REVIEW_NUMBER]
|
||||
# all_collections = CollectionItem.objects.filter(book=book).annotate(num_marks=Count('collection__collection_marks')).order_by('-num_marks')[:20]
|
||||
# collection_list = filter(lambda c: c.is_visible_to(request.user), map(lambda i: i.collection, all_collections))
|
||||
|
||||
# def strip_html_tags(text):
|
||||
# import re
|
||||
# regex = re.compile('<.*?>')
|
||||
# return re.sub(regex, '', text)
|
||||
|
||||
# for r in review_list:
|
||||
# r.content = strip_html_tags(r.content)
|
||||
collection_list = item.collections.all().filter(query_visible(request.user)).annotate(like_counts=Count('likes')).order_by('-like_counts')
|
||||
|
||||
return render(request, item.class_name + '.html', {
|
||||
'item': item,
|
||||
|
|
|
@ -19,6 +19,11 @@ import math
|
|||
import uuid
|
||||
from catalog.common.utils import DEFAULT_ITEM_COVER, item_cover_path
|
||||
from django.utils.baseconv import base62
|
||||
from django.db.models import Q
|
||||
|
||||
|
||||
def query_visible(user):
|
||||
return Q(visibility=0) | Q(owner_id__in=user.following, visibility__lt=2) | Q(owner_id=user.id)
|
||||
|
||||
|
||||
class Piece(PolymorphicModel, UserOwnedObjectMixin):
|
||||
|
@ -276,14 +281,16 @@ ShelfTypeNames = [
|
|||
[ItemCategory.Game, ShelfType.WISHLIST, _('想玩')],
|
||||
[ItemCategory.Game, ShelfType.PROGRESS, _('在玩')],
|
||||
[ItemCategory.Game, ShelfType.COMPLETE, _('玩过')],
|
||||
[ItemCategory.Collection, ShelfType.WISHLIST, _('关注')],
|
||||
# TODO add more combinations
|
||||
]
|
||||
|
||||
|
||||
class ShelfMember(ListMember):
|
||||
parent = models.ForeignKey('Shelf', related_name='members', on_delete=models.CASCADE)
|
||||
|
||||
@cached_property
|
||||
def mark(self):
|
||||
return Mark(self.owner, self.item)
|
||||
|
||||
|
||||
class Shelf(List):
|
||||
class Meta:
|
||||
|
@ -487,6 +494,11 @@ class TagManager:
|
|||
tag = Tag.objects.filter(owner=user, title=title).first()
|
||||
tag.remove_item(item)
|
||||
|
||||
@staticmethod
|
||||
def get_item_tags_by_user(item, user):
|
||||
current_titles = [m.parent.title for m in TagMember.objects.filter(owner=user, item=item)]
|
||||
return current_titles
|
||||
|
||||
@staticmethod
|
||||
def add_tag_by_user(item, tag_title, user, default_visibility=0):
|
||||
title = Tag.cleanup_title(tag_title)
|
||||
|
@ -535,6 +547,10 @@ class Mark:
|
|||
def id(self):
|
||||
return self.shelfmember.id if self.shelfmember else None
|
||||
|
||||
@property
|
||||
def shelf(self):
|
||||
return self.shelfmember.parent if self.shelfmember else None
|
||||
|
||||
@property
|
||||
def shelf_type(self):
|
||||
return self.shelfmember.parent.shelf_type if self.shelfmember else None
|
||||
|
@ -575,7 +591,8 @@ class Mark:
|
|||
def review(self):
|
||||
return Review.objects.filter(owner=self.owner, item=self.item).first()
|
||||
|
||||
def update(self, shelf_type, comment_text, rating_grade, visibility, metadata=None, created_time=None):
|
||||
def update(self, shelf_type, comment_text, rating_grade, visibility, metadata=None, created_time=None, share_to_mastodon=False):
|
||||
share = share_to_mastodon and shelf_type is not None and (shelf_type != self.shelf_type or comment_text != self.text or rating_grade != self.rating)
|
||||
if shelf_type != self.shelf_type or visibility != self.visibility:
|
||||
self.shelfmember = self.owner.shelf_manager.move_item(self.item, shelf_type, visibility=visibility, metadata=metadata)
|
||||
if self.shelfmember and created_time:
|
||||
|
@ -586,3 +603,17 @@ class Mark:
|
|||
if rating_grade != self.rating or visibility != self.visibility:
|
||||
Rating.rate_item_by_user(self.item, self.owner, rating_grade, visibility)
|
||||
self.rating = rating_grade
|
||||
if share:
|
||||
# this is a bit hacky but let's keep it until move to implement ActivityPub,
|
||||
# by then, we'll just change this to boost
|
||||
from mastodon.api import share_mark
|
||||
self.shared_link = self.shelfmember.metadata.get('shared_link') if self.shelfmember.metadata else None
|
||||
self.translated_status = self.shelf_label
|
||||
self.save = lambda **args: None
|
||||
if not share_mark(self):
|
||||
raise ValueError("sharing failed")
|
||||
if not self.shelfmember.metadata:
|
||||
self.shelfmember.metadata = {}
|
||||
if self.shelfmember.metadata.get('shared_link') != self.shared_link:
|
||||
self.shelfmember.metadata['shared_link'] = self.shared_link
|
||||
self.shelfmember.save()
|
||||
|
|
45
journal/templates/add_to_collection.html
Normal file
45
journal/templates/add_to_collection.html
Normal file
|
@ -0,0 +1,45 @@
|
|||
{% load static %}
|
||||
{% load i18n %}
|
||||
{% load l10n %}
|
||||
{% load humanize %}
|
||||
{% load admin_url %}
|
||||
{% load mastodon %}
|
||||
{% load oauth_token %}
|
||||
{% load truncate %}
|
||||
{% load highlight %}
|
||||
{% load thumb %}
|
||||
|
||||
<div id="modal" _="on closeModal add .closing then wait for animationend then remove me">
|
||||
<div class="modal-underlay" _="on click trigger closeModal"></div>
|
||||
<div class="modal-content">
|
||||
<div class="add-to-list-modal__head">
|
||||
<span class="add-to-list-modal__title">{% trans '添加到收藏单' %}</span>
|
||||
<span class="add-to-list-modal__close-button modal-close" _="on click trigger closeModal">
|
||||
<span class="icon-cross">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
|
||||
<polygon
|
||||
points="20 2.61 17.39 0 10 7.39 2.61 0 0 2.61 7.39 10 0 17.39 2.61 20 10 12.61 17.39 20 20 17.39 12.61 10 20 2.61">
|
||||
</polygon>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="add-to-list-modal__body">
|
||||
<form action="{% url 'journal:add_to_collection' item.uuid %}" method="post">
|
||||
{% csrf_token %}
|
||||
<select name="collection_id">
|
||||
{% for collection in collections %}
|
||||
<option value="{{ collection.id }}">{{ collection.title }}{% if collection.visibility > 0 %}🔒{% endif %}</option>
|
||||
{% endfor %}
|
||||
<option value="0">新建收藏单</option>
|
||||
</select>
|
||||
<div>
|
||||
<textarea type="text" name="comment" placeholder="条目备注"></textarea>
|
||||
</div>
|
||||
<div class="add-to-list-modal__confirm-button">
|
||||
<input type="submit" class="button float-right" value="{% trans '提交' %}">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
128
journal/templates/mark.html
Normal file
128
journal/templates/mark.html
Normal file
|
@ -0,0 +1,128 @@
|
|||
{% load static %}
|
||||
{% load i18n %}
|
||||
{% load l10n %}
|
||||
{% load humanize %}
|
||||
{% load admin_url %}
|
||||
{% load mastodon %}
|
||||
{% load oauth_token %}
|
||||
{% load truncate %}
|
||||
{% load highlight %}
|
||||
{% load thumb %}
|
||||
|
||||
<div id="modal" _="on closeModal add .closing then wait for animationend then remove me">
|
||||
<div class="modal-underlay" _="on click trigger closeModal"></div>
|
||||
<div class="modal-content">
|
||||
<div class="add-to-list-modal__head">
|
||||
<span class="add-to-list-modal__title">{% trans '标记' %} {{ item.title }}</span>
|
||||
<span class="add-to-list-modal__close-button modal-close" _="on click trigger closeModal">
|
||||
<span class="icon-cross">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
|
||||
<polygon
|
||||
points="20 2.61 17.39 0 10 7.39 2.61 0 0 2.61 7.39 10 0 17.39 2.61 20 10 12.61 17.39 20 20 17.39 12.61 10 20 2.61">
|
||||
</polygon>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="add-to-list-modal__body">
|
||||
<form action="{% url 'journal:mark' item.uuid %}" method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
<div id="statusSelection" class="mark-modal__status-radio float-right">
|
||||
<ul id="id_status">
|
||||
{% for k, v in shelf_types %}
|
||||
<li><label for="id_status_{{ k }}"><input type="radio" name="status" value="{{ k }}" required="" id="id_status_{{ k }}" {% if mark.shelf_type == k %}checked=""{% endif %}> {{ v }}</label></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="mark-modal__rating-star rating-star-edit"></div>
|
||||
<input type="hidden" name="rating" id="id_rating" value="{{ mark.rating }}">
|
||||
|
||||
<div class="mark-modal__clear"></div>
|
||||
|
||||
<textarea name="text" cols="40" rows="10" placeholder="超过360字部分实例可能无法显示" maxlength="360" id="id_text">{{ mark.text }}</textarea>
|
||||
|
||||
<div class="mark-modal__tag">
|
||||
<label>标签</label>
|
||||
<div class="tag-input">
|
||||
<input name="tags" type="text" placeholder="回车增加标签" id="id_tags" value="">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mark-modal__share-checkbox float-right">
|
||||
<input type="checkbox" name="share_to_mastodon" id="id_share_to_mastodon" value="1" checked>分享到联邦网络
|
||||
</div>
|
||||
|
||||
<div class="mark-modal__option">
|
||||
<div class="mark-modal__visibility-radio">
|
||||
<span>可见性:
|
||||
<ul id="id_visibility">
|
||||
<li><label for="id_visibility_0"><input type="radio" name="visibility" value="0" required="" id="id_visibility_0" {% if mark.visibility == 0 %}checked{% endif %}> 公开</label> </li>
|
||||
<li><label for="id_visibility_1"><input type="radio" name="visibility" value="1" required="" id="id_visibility_1" {% if mark.visibility == 1 %}checked{% endif %}> 仅关注者</label> </li>
|
||||
<li><label for="id_visibility_2"><input type="radio" name="visibility" value="2" required="" id="id_visibility_2" {% if mark.visibility == 2 %}checked{% endif %}> 仅自己</label> </li>
|
||||
</ul>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="mark-modal__confirm-button">
|
||||
<input type="submit" class="button float-right" value="保存">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<script>
|
||||
(function(){
|
||||
new inputTags({
|
||||
container: document.getElementsByClassName("tag-input")[0],
|
||||
tags : "{{ tags }}".split(","),
|
||||
allowDuplicateTags : false,
|
||||
duplicateTime: 300,
|
||||
onTagRemove : function (tag) {},
|
||||
});
|
||||
// editable rating star in modal
|
||||
ratingLabels = $("#modal .rating-star-edit");
|
||||
$(ratingLabels).each( function(index, value) {
|
||||
let ratingScore = $("input[type='hidden'][name='rating']").val() / 2;
|
||||
let label = $(this);
|
||||
label.starRating({
|
||||
initialRating: ratingScore,
|
||||
starSize: 20,
|
||||
onHover: function(currentIndex, currentRating, $el){
|
||||
$("input[type='hidden'][name='rating']").val(currentIndex);
|
||||
},
|
||||
onLeave: function(currentIndex, currentRating, $el){
|
||||
$("input[type='hidden'][name='rating']").val(currentRating * 2);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// hide rating star when select wish
|
||||
const WISH_CODE = "wishlist";
|
||||
if ($("#statusSelection input[type='radio']:checked").val() == WISH_CODE) {
|
||||
$("#model .rating-star-edit").hide();
|
||||
}
|
||||
$("#statusSelection input[type='radio']").on('click', function() {
|
||||
if ($(this).val() == WISH_CODE) {
|
||||
$("#model .rating-star-edit").hide();
|
||||
} else {
|
||||
$("#model .rating-star-edit").show();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// show confirm modal
|
||||
$("#model a.delete").on('click', function(e) {
|
||||
e.preventDefault();
|
||||
$(".confirm-modal").show();
|
||||
$(".bg-mask").show();
|
||||
});
|
||||
|
||||
// confirm modal
|
||||
$(".confirm-modal input[type='submit']").on('click', function(e) {
|
||||
e.preventDefault();
|
||||
$("#model form").submit();
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</div>
|
|
@ -6,4 +6,6 @@ app_name = 'journal'
|
|||
urlpatterns = [
|
||||
path('wish/<str:item_uuid>', wish, name='wish'),
|
||||
path('like/<str:piece_uuid>', like, name='like'),
|
||||
path('mark/<str:item_uuid>', mark, name='mark'),
|
||||
path('add_to_collection/<str:item_uuid>', add_to_collection, name='add_to_collection'),
|
||||
]
|
||||
|
|
|
@ -19,6 +19,7 @@ from management.models import Announcement
|
|||
from django.utils.baseconv import base62
|
||||
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
PAGE_SIZE = 10
|
||||
|
||||
|
||||
|
@ -44,3 +45,61 @@ def like(request, piece_uuid):
|
|||
return HttpResponse("✔️")
|
||||
else:
|
||||
return HttpResponseBadRequest("invalid request")
|
||||
|
||||
|
||||
@login_required
|
||||
def add_to_collection(request, item_uuid):
|
||||
item = get_object_or_404(Item, uid=base62.decode(item_uuid))
|
||||
if request.method == 'GET':
|
||||
collections = Collection.objects.filter(owner=request.user)
|
||||
return render(
|
||||
request,
|
||||
'add_to_collection.html',
|
||||
{
|
||||
'item': item,
|
||||
'collections': collections,
|
||||
}
|
||||
)
|
||||
else:
|
||||
cid = int(request.POST.get('collection_id', default=0))
|
||||
if not cid:
|
||||
cid = Collection.objects.create(owner=request.user, title=f'{request.user.username}的收藏单').id
|
||||
collection = Collection.objects.get(owner=request.user, id=cid)
|
||||
collection.append_item(item, metadata={'comment': request.POST.get('comment')})
|
||||
return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
|
||||
|
||||
|
||||
def go_relogin(request):
|
||||
return render(request, 'common/error.html', {
|
||||
'url': reverse("users:connect") + '?domain=' + request.user.mastodon_site,
|
||||
'msg': _("信息已保存,但是未能分享到联邦网络"),
|
||||
'secondary_msg': _("可能是你在联邦网络(Mastodon/Pleroma/...)的登录状态过期了,正在跳转到联邦网络重新登录😼")})
|
||||
|
||||
|
||||
@login_required
|
||||
def mark(request, item_uuid):
|
||||
item = get_object_or_404(Item, uid=base62.decode(item_uuid))
|
||||
mark = Mark(request.user, item)
|
||||
if request.method == 'GET':
|
||||
tags = TagManager.get_item_tags_by_user(item, request.user)
|
||||
shelf_types = [(n[1], n[2]) for n in iter(ShelfTypeNames) if n[0] == item.category]
|
||||
return render(request, 'mark.html', {
|
||||
'item': item,
|
||||
'mark': mark,
|
||||
'tags': ','.join(tags),
|
||||
'shelf_types': shelf_types,
|
||||
})
|
||||
elif request.method == 'POST':
|
||||
visibility = int(request.POST.get('visibility', default=0))
|
||||
rating = int(request.POST.get('rating', default=0))
|
||||
status = ShelfType(request.POST.get('status'))
|
||||
text = request.POST.get('text')
|
||||
tags = request.POST.get('tags')
|
||||
tags = tags.split(',') if tags else []
|
||||
share_to_mastodon = bool(request.POST.get('share_to_mastodon', default=False))
|
||||
TagManager.tag_item_by_user(item, request.user, tags, visibility)
|
||||
try:
|
||||
mark.update(status, text, rating, visibility, share_to_mastodon=share_to_mastodon)
|
||||
except Exception:
|
||||
go_relogin(request)
|
||||
return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
|
||||
|
|
|
@ -108,7 +108,6 @@ class DefaultActivityProcessor:
|
|||
'template': self.template,
|
||||
'action_object': self.action_object,
|
||||
}
|
||||
print(params)
|
||||
LocalActivity.objects.create(**params)
|
||||
|
||||
def updated(self):
|
||||
|
|
|
@ -45,17 +45,14 @@
|
|||
{% endfor %}
|
||||
</div>
|
||||
<p class="entity-list__entity-brief">
|
||||
{% if activity.review %}
|
||||
{% if activity.action_object.review %}
|
||||
<a href="{{ activity.review.url }}">{{ activity.review.title }}</a>
|
||||
{% endif %}
|
||||
{% if activity.mark %}
|
||||
{% if activity.mark.rating %}
|
||||
<span class="entity-marks__rating-star rating-star" data-rating-score="{{ activity.mark.rating | floatformat:"0" }}" style=""></span>
|
||||
{% endif %}
|
||||
|
||||
{% if activity.mark.text %}
|
||||
<p class="entity-marks__mark-content">{{ activity.mark.text }}</p>
|
||||
{% if activity.action_object.mark.rating %}
|
||||
<span class="entity-marks__rating-star rating-star" data-rating-score="{{ activity.action_object.mark.rating }}" style=""></span>
|
||||
{% endif %}
|
||||
{% if activity.action_object.mark.text %}
|
||||
<p class="entity-marks__mark-content">{{ activity.action_object.mark.text }}</p>
|
||||
{% endif %}
|
||||
</p>
|
||||
</div>
|
|
@ -78,3 +78,16 @@ hx-swap="outerHTML">
|
|||
{% empty %}
|
||||
<div>{% trans '目前没有更多内容了' %}</div>
|
||||
{% endfor %}
|
||||
<script>
|
||||
// readonly star rating at aside section
|
||||
ratingLabels = $(".rating-star");
|
||||
$(ratingLabels).each( function(index, value) {
|
||||
console.log($(this).data("rating-score"))
|
||||
let ratingScore = $(this).data("rating-score") / 2;
|
||||
$(this).starRating({
|
||||
initialRating: ratingScore,
|
||||
readOnly: true,
|
||||
starSize: 15,
|
||||
});
|
||||
});
|
||||
</script>
|
Loading…
Add table
Reference in a new issue