diff --git a/books/models.py b/books/models.py index 1b8cf657..aa539fc8 100644 --- a/books/models.py +++ b/books/models.py @@ -70,6 +70,10 @@ class Book(Resource): def get_tags_manager(self): return self.book_tags + @property + def verbose_category_name(self): + return _("书籍") + class BookMark(Mark): # maybe this is the better solution, for it has less complex index @@ -95,4 +99,4 @@ class BookTag(Tag): class Meta: constraints = [ models.UniqueConstraint(fields=['content', 'mark'], name="unique_bookmark_tag") - ] \ No newline at end of file + ] diff --git a/books/templates/books/create_update.html b/books/templates/books/create_update.html index 02033e1a..e762f09a 100644 --- a/books/templates/books/create_update.html +++ b/books/templates/books/create_update.html @@ -25,6 +25,7 @@
+ {% trans '>>> 试试一键剽取~ <<<' %}
{% csrf_token %} {{ form.media }} diff --git a/common/forms.py b/common/forms.py index 25301801..953680e1 100644 --- a/common/forms.py +++ b/common/forms.py @@ -131,6 +131,12 @@ class TagField(forms.CharField): class MultiSelect(forms.SelectMultiple): template_name = 'widgets/multi_select.html' + class Media: + css = { + 'all': ('lib/css/multiple-select.min.css',) + } + js = ('lib/js/multiple-select.min.js',) + class HstoreInput(forms.Widget): template_name = 'widgets/hstore.html' @@ -154,6 +160,9 @@ class HstoreField(forms.CharField): def to_python(self, value): if not value: return None + # already in python types + if isinstance(value, list): + return value pairs = eval(value) if len(pairs) == 1: pairs = (pairs,) diff --git a/common/models.py b/common/models.py index fd119684..9a1c9238 100644 --- a/common/models.py +++ b/common/models.py @@ -81,21 +81,37 @@ class Resource(models.Model): Since relation between tag and resource is foreign key, and related name has to be unique, this method works like interface. """ - raise NotImplementedError + raise NotImplementedError("Subclass should implement this method.") def get_marks_manager(self): """ Normally this won't be used. There is no ocassion where visitor can simply view all the marks. """ - raise NotImplementedError + raise NotImplementedError("Subclass should implement this method.") def get_revies_manager(self): """ Normally this won't be used. There is no ocassion where visitor can simply view all the reviews. """ - raise NotImplementedError + raise NotImplementedError("Subclass should implement this method.") + + @classmethod + def get_category_mapping_dict(cls): + category_mapping_dict = {} + for subclass in cls.__subclasses__(): + category_mapping_dict[subclass.__name__.lower()] = subclass + return category_mapping_dict + + @property + def category_name(self): + return self.__class__.__name__ + + @property + def verbose_category_name(self): + raise NotImplementedError("Subclass should implement this.") + class UserOwnedEntity(models.Model): is_private = models.BooleanField() diff --git a/common/static/css/boofilsic.css b/common/static/css/boofilsic.css index b7863979..3e290119 100644 --- a/common/static/css/boofilsic.css +++ b/common/static/css/boofilsic.css @@ -510,19 +510,39 @@ select::placeholder { .navbar .navbar__search-box { margin: 0 12% 0 15px; - display: inline-block; + display: -webkit-inline-box; + display: -ms-inline-flexbox; + display: inline-flex; -webkit-box-flex: 1; -ms-flex: 1; flex: 1; } .navbar .navbar__search-box > input[type="search"] { + border-top-right-radius: 0; + border-bottom-right-radius: 0; margin: 0; height: 32px; background-color: white !important; width: 100%; } +.navbar .navbar__search-box .navbar__search-dropdown { + margin: 0; + margin-left: -1px; + padding: 0; + padding-left: 10px; + color: #606c76; + -webkit-appearance: auto; + -moz-appearance: auto; + appearance: auto; + background-color: white; + height: 32px; + width: 80px; + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + .navbar .navbar__dropdown-btn { display: none; padding: 0; @@ -578,6 +598,11 @@ select::placeholder { height: 26px; padding: 4px 6px; } + .navbar .navbar__search-box .navbar__search-dropdown { + height: 26px; + width: 80px; + padding-left: 5px; + } } @media (max-width: 991.98px) { @@ -1128,6 +1153,13 @@ select::placeholder { display: block; } +.entity-list .entity-list__entity-category { + color: #bbb; + margin-left: 5px; + position: relative; + top: -1px; +} + .entity-list .entity-list__entity-info { max-width: 73%; white-space: nowrap; @@ -1635,6 +1667,13 @@ select::placeholder { margin-bottom: 8px; } +.add-entity-entries .add-entity-entries__button { + line-height: unset; + height: unset; + padding: 4px 15px; + margin: 0 5px; +} + .action-panel { margin-bottom: 20px; } @@ -1866,6 +1905,7 @@ select::placeholder { } .add-entity-entries .add-entity-entries__button { width: 100%; + margin: 5px 0 5px 0; } .aside-section-wrapper:first-child { margin-right: 0 !important; @@ -1987,6 +2027,16 @@ select::placeholder { overflow: auto; } +.single-section-wrapper .single-section-wrapper__link--secondary { + display: inline-block; + color: #ccc; + margin-bottom: 20px; +} + +.single-section-wrapper .single-section-wrapper__link--secondary:hover { + color: #00a1cc; +} + .entity-form, .review-form { overflow: auto; } diff --git a/common/static/lib/css/multiple-select.min.css b/common/static/lib/css/multiple-select.min.css new file mode 100644 index 00000000..5a6f1b19 --- /dev/null +++ b/common/static/lib/css/multiple-select.min.css @@ -0,0 +1,10 @@ +/** + * multiple-select - Multiple select is a jQuery plugin to select multiple elements with checkboxes :). + * + * @version v1.5.2 + * @homepage http://multiple-select.wenzhixin.net.cn + * @author wenzhixin (http://wenzhixin.net.cn/) + * @license MIT + */ + +@charset "UTF-8";.ms-offscreen{clip:rect(0 0 0 0)!important;width:1px!important;height:1px!important;border:0!important;margin:0!important;padding:0!important;overflow:hidden!important;position:absolute!important;outline:0!important;left:auto!important;top:auto!important}.ms-parent{display:inline-block;position:relative;vertical-align:middle}.ms-choice{display:block;width:100%;height:26px;padding:0;overflow:hidden;cursor:pointer;border:1px solid #aaa;text-align:left;white-space:nowrap;line-height:26px;color:#444;text-decoration:none;border-radius:4px;background-color:#fff}.ms-choice.disabled{background-color:#f4f4f4;background-image:none;border:1px solid #ddd;cursor:default}.ms-choice>span{position:absolute;top:0;left:0;right:20px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:block;padding-left:8px}.ms-choice>span.placeholder{color:#999}.ms-choice>div.icon-close{position:absolute;top:0;right:16px;height:100%;width:16px}.ms-choice>div.icon-close:before{content:'×';color:#888;font-weight:bold;position:absolute;top:50%;margin-top:-14px}.ms-choice>div.icon-close:hover:before{color:#333}.ms-choice>div.icon-caret{position:absolute;width:0;height:0;top:50%;right:8px;margin-top:-2px;border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px}.ms-choice>div.icon-caret.open{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px}.ms-drop{width:auto;min-width:100%;overflow:hidden;display:none;margin-top:-1px;padding:0;position:absolute;z-index:1000;background:#fff;color:#000;border:1px solid #aaa;border-radius:4px}.ms-drop.bottom{top:100%;box-shadow:0 4px 5px rgba(0,0,0,0.15)}.ms-drop.top{bottom:100%;box-shadow:0 -4px 5px rgba(0,0,0,0.15)}.ms-search{display:inline-block;margin:0;min-height:26px;padding:2px;position:relative;white-space:nowrap;width:100%;z-index:10000;box-sizing:border-box}.ms-search input{width:100%;height:auto!important;min-height:24px;padding:0 5px;margin:0;outline:0;font-family:sans-serif;border:1px solid #aaa;border-radius:5px;box-shadow:none}.ms-drop ul{overflow:auto;margin:0;padding:0}.ms-drop ul>li{list-style:none;display:list-item;background-image:none;position:static;padding:.25rem 8px}.ms-drop ul>li .disabled{font-weight:normal!important;opacity:.35;filter:Alpha(Opacity=35);cursor:default}.ms-drop ul>li.multiple{display:block;float:left}.ms-drop ul>li.group{clear:both}.ms-drop ul>li.multiple label{width:100%;display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ms-drop ul>li label{position:relative;padding-left:1.25rem;margin-bottom:0;font-weight:normal;display:block;white-space:nowrap;cursor:pointer}.ms-drop ul>li label.optgroup{font-weight:bold}.ms-drop ul>li.hide-radio{padding:0}.ms-drop ul>li.hide-radio:focus,.ms-drop ul>li.hide-radio:hover{background-color:#f8f9fa}.ms-drop ul>li.hide-radio.selected{color:#fff;background-color:#007bff}.ms-drop ul>li.hide-radio label{margin-bottom:0;padding:5px 8px}.ms-drop ul>li.hide-radio input{display:none}.ms-drop ul>li.option-level-1 label{padding-left:28px}.ms-drop input[type="radio"],.ms-drop input[type="checkbox"]{position:absolute;margin-top:.3rem;margin-left:-1.25rem}.ms-drop .ms-no-results{display:none} \ No newline at end of file diff --git a/common/static/lib/js/multiple-select.min.js b/common/static/lib/js/multiple-select.min.js new file mode 100644 index 00000000..7bffe99d --- /dev/null +++ b/common/static/lib/js/multiple-select.min.js @@ -0,0 +1,10 @@ +/** + * multiple-select - Multiple select is a jQuery plugin to select multiple elements with checkboxes :). + * + * @version v1.5.2 + * @homepage http://multiple-select.wenzhixin.net.cn + * @author wenzhixin (http://wenzhixin.net.cn/) + * @license MIT + */ + +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(require("jquery")):"function"==typeof define&&define.amd?define(["jquery"],e):e((t=t||self).jQuery)}(this,(function(t){"use strict";function e(t){return(e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function n(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t,e){for(var n=0;n0?ct:at)(t)},ft=Math.min,pt=function(t){return t>0?ft(ht(t),9007199254740991):0},dt=Math.max,vt=Math.min,gt=function(t,e){var n=ht(t);return n<0?dt(n+e,0):vt(n,e)},yt=function(t){return function(e,n,i){var r,u=D(e),o=pt(u.length),s=gt(i,o);if(t&&n!=n){for(;o>s;)if((r=u[s++])!=r)return!0}else for(;o>s;s++)if((t||s in u)&&u[s]===n)return t||s||0;return!t&&-1}},Et={includes:yt(!0),indexOf:yt(!1)},bt=Et.indexOf,mt=function(t,e){var n,i=D(t),r=0,u=[];for(n in i)!$(Q,n)&&$(i,n)&&u.push(n);for(;e.length>r;)$(i,n=e[r++])&&(~bt(u,n)||u.push(n));return u},At=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"],Ft=At.concat("length","prototype"),St={f:Object.getOwnPropertyNames||function(t){return mt(t,Ft)}},Ct={f:Object.getOwnPropertySymbols},kt=lt("Reflect","ownKeys")||function(t){var e=St.f(R(t)),n=Ct.f;return n?e.concat(n(t)):e},Dt=function(t,e){for(var n=kt(e),i=P.f,r=I.f,u=0;uu;)P.f(t,n=i[u++],e[n]);return t},Gt=lt("document","documentElement"),Ut=J("IE_PROTO"),Wt=function(){},Vt=function(){var t,e=T("iframe"),n=At.length;for(e.style.display="none",Gt.appendChild(e),e.src=String("javascript:"),(t=e.contentWindow.document).open(),t.write(" diff --git a/movies/templates/movies/create_update_review.html b/movies/templates/movies/create_update_review.html index edf47be6..40cbc37f 100644 --- a/movies/templates/movies/create_update_review.html +++ b/movies/templates/movies/create_update_review.html @@ -42,14 +42,12 @@ {% if movie.season %} {{ movie.title }} {% trans '第' %}{{ movie.season|apnumber }}{% trans '季' %} {{ movie.orig_title }} Season {{ movie.season }} - - ({{ movie.year }}) - + + {% if movie.year %}({{ movie.year }}){% endif %} + {% else %} {{ movie.title }} {{ movie.orig_title }} - - ({{ movie.year }}) - + {% if movie.year %}({{ movie.year }}){% endif %} {% endif %}
{% if movie.director %}{% trans '导演:' %} diff --git a/movies/templates/movies/delete.html b/movies/templates/movies/delete.html index 18b0b132..7f11e198 100644 --- a/movies/templates/movies/delete.html +++ b/movies/templates/movies/delete.html @@ -44,14 +44,10 @@ {% if movie.season %} {{ movie.title }} {% trans '第' %}{{ movie.season|apnumber }}{% trans '季' %} {{ movie.orig_title }} Season {{ movie.season }} - - ({{ movie.year }}) - + {% if movie.year %}({{ movie.year }}){% endif %} {% else %} {{ movie.title }} {{ movie.orig_title }} - - ({{ movie.year }}) - + {% if movie.year %}({{ movie.year }}){% endif %} {% endif %} diff --git a/movies/templates/movies/detail.html b/movies/templates/movies/detail.html index 9eec9ee6..3f607cec 100644 --- a/movies/templates/movies/detail.html +++ b/movies/templates/movies/detail.html @@ -63,12 +63,12 @@ {% if movie.season %} {{ movie.title }} {% trans '第' %}{{ movie.season|apnumber }}{% trans '季' %} {{ movie.orig_title }} Season {{ movie.season }} - ({{ movie.year }}) + {% if movie.year %}({{ movie.year }}){% endif %} {% else %} {{ movie.title }} {{ movie.orig_title }} - ({{ movie.year }}) + {% if movie.year %}({{ movie.year }}){% endif %} {% endif %} @@ -331,9 +331,9 @@
{% trans '标记这部电影' %}
{% endif %}
- - - + + +
{% endif %} diff --git a/movies/templates/movies/mark_list.html b/movies/templates/movies/mark_list.html index c5fc3d7f..3e828d62 100644 --- a/movies/templates/movies/mark_list.html +++ b/movies/templates/movies/mark_list.html @@ -112,14 +112,10 @@ {% if movie.season %} {{ movie.title }} {% trans '第' %}{{ movie.season|apnumber }}{% trans '季' %} {{ movie.orig_title }} Season {{ movie.season }} - - ({{ movie.year }}) - + {% if movie.year %}({{ movie.year }}){% endif %} {% else %} {{ movie.title }} {{ movie.orig_title }} - - ({{ movie.year }}) - + {% if movie.year %}({{ movie.year }}){% endif %} {% endif %} diff --git a/movies/templates/movies/review_detail.html b/movies/templates/movies/review_detail.html index a6e8e998..29aae0a2 100644 --- a/movies/templates/movies/review_detail.html +++ b/movies/templates/movies/review_detail.html @@ -91,14 +91,10 @@ {% if movie.season %} {{ movie.title }} {% trans '第' %}{{ movie.season|apnumber }}{% trans '季' %} {{ movie.orig_title }} Season {{ movie.season }} - - ({{ movie.year }}) - + {% if movie.year %}({{ movie.year }}){% endif %} {% else %} {{ movie.title }} {{ movie.orig_title }} - - ({{ movie.year }}) - + {% if movie.year %}({{ movie.year }}){% endif %} {% endif %} diff --git a/movies/templates/movies/review_list.html b/movies/templates/movies/review_list.html index fca9832d..d9c705fb 100644 --- a/movies/templates/movies/review_list.html +++ b/movies/templates/movies/review_list.html @@ -98,14 +98,10 @@ {% if movie.season %} {{ movie.title }} {% trans '第' %}{{ movie.season|apnumber }}{% trans '季' %} {{ movie.orig_title }} Season {{ movie.season }} - - ({{ movie.year }}) - + {% if movie.year %}({{ movie.year }}){% endif %} {% else %} {{ movie.title }} {{ movie.orig_title }} - - ({{ movie.year }}) - + {% if movie.year %}({{ movie.year }}){% endif %} {% endif %} diff --git a/books/templates/books/list.html b/users/templates/users/book_list.html similarity index 100% rename from books/templates/books/list.html rename to users/templates/users/book_list.html diff --git a/movies/templates/movies/list.html b/users/templates/users/movie_list.html similarity index 91% rename from movies/templates/movies/list.html rename to users/templates/users/movie_list.html index 3d854710..1f591e34 100644 --- a/movies/templates/movies/list.html +++ b/users/templates/users/movie_list.html @@ -57,27 +57,14 @@ {% if mark.movie.season %} {{ mark.movie.title }} {% trans '第' %}{{ mark.movie.season|apnumber }}{% trans '季' %} {{ mark.movie.orig_title }} Season {{ mark.movie.season }} - - ({{ mark.movie.year }}) - + {% if mark.movie.year %}({{ mark.movie.year }}){% endif %} + {% else %} {{ mark.movie.title }} {{ mark.movie.orig_title }} - - ({{ mark.movie.year }}) - + {% if mark.movie.year %}({{ mark.movie.year }}){% endif %} {% endif %}
- {% comment %} - - {% endcomment %} @@ -104,7 +91,7 @@ {% for actor in mark.movie.actor %} 5 %}style="display: none;" {% endif %}>{{ actor }} {% if forloop.counter <= 5 %} - {% if not forloop.last %} / {% endif %} + {% if not forloop.counter == 5 %} / {% endif %} {% endif %} {% endfor %} {% endif %} diff --git a/users/views.py b/users/views.py index b525174c..fe5e7e07 100644 --- a/users/views.py +++ b/users/views.py @@ -336,7 +336,7 @@ def book_list(request, id, status): list_title = str(BookMarkStatusTranslator(MarkStatusEnum[status.upper()])) + str(_("的书")) return render( request, - 'books/list.html', + 'users/book_list.html', { 'marks': marks, 'user': user, @@ -393,7 +393,7 @@ def movie_list(request, id, status): list_title = str(MovieMarkStatusTranslator(MarkStatusEnum[status.upper()])) + str(_("的电影和剧集")) return render( request, - 'movies/list.html', + 'users/movie_list.html', { 'marks': marks, 'user': user,