diff --git a/README.rst b/README.rst index 19196e6..6ef6eed 100644 --- a/README.rst +++ b/README.rst @@ -40,11 +40,11 @@ Requirements * defusedxml * requests * celery -* jQuery (>= 1.7.2) +* jQuery (>= 2.1.1) * underscore.js (>= 1.5.2) * backbone.js (>= 1.1.0) * JSON in JavaScript -* Twitter bootstrap (>= 2.0.2) +* Twitter bootstrap (>= 3.2.0) Recommends ---------- @@ -64,7 +64,7 @@ Shiori depends on as following.:: $ sudo apt-get install python-django python-djangorestframework \ python-django-shortuuidfield python-django-auth-openid python-celery \ python-lxml python-defusedxml python-netaddr python-django-south \ - libjs-jquery libjs-underscore libjs-json libjs-twitter-bootstrap \ + libjs-jquery libjs-underscore libjs-json \ libxml2-dev libxslt1-dev python-requests python-dev libpython2.7-dev \ python-django-jsonfield diff --git a/docs/HISTORY.rst b/docs/HISTORY.rst index 9d9e5cf..636398c 100644 --- a/docs/HISTORY.rst +++ b/docs/HISTORY.rst @@ -1,6 +1,15 @@ History ------- + +0.4.0 (2014-07-13) +^^^^^^^^^^^^^^^^^^ + +* Applied Bootstrap 3. +* Fixed link of category and tag. +* Fixed jslint violations. +* Improved loading bookmark. + 0.3.4 (2014-06-02) ^^^^^^^^^^^^^^^^^^ diff --git a/requirements.txt b/requirements.txt index bb3a0fb..3607b47 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,9 +1,9 @@ pep8>=1.3 pytest -django >= 1.6 +Django >= 1.6 djangorestframework shortuuid == 0.3.2 -django-shortuuidfield +django_shortuuidfield django-jsonfield python-openid south @@ -11,6 +11,7 @@ celery lxml defusedxml requests +pyquery netaddr -e bzr+http://bazaar.launchpad.net/~andrewsomething/django-openid-auth/1252445#egg=django-openid-auth closure-linter diff --git a/setup.py b/setup.py index b20a498..6f909d7 100755 --- a/setup.py +++ b/setup.py @@ -59,15 +59,18 @@ def run_tests(self): 'shortuuid == 0.3.2', 'django_shortuuidfield', 'django-jsonfield', + 'south', + 'celery', 'python-openid', 'django-openid-auth', 'lxml', 'defusedxml', 'requests', + 'pyquery', 'netaddr'] setup(name='shiori', - version='0.3.4', + version='0.4.0', description='bookmarking tool based on Web UI and JSON REST API', long_description=long_description, author='Kouhei Maeda', diff --git a/shiori/api/serializers.py b/shiori/api/serializers.py index 4aca2d8..bc62550 100644 --- a/shiori/api/serializers.py +++ b/shiori/api/serializers.py @@ -28,7 +28,7 @@ class Meta(object): class BookmarkSerializer(serializers.ModelSerializer): """ Serializer for shiori.bookmark.models.Bookmark """ - + title = serializers.Field(source='title') category = serializers.SlugRelatedField(many=False, slug_field='category') category_id = serializers.Field(source='category.id') tags = serializers.SlugRelatedField(many=True, slug_field='tag', diff --git a/shiori/bookmark/models.py b/shiori/bookmark/models.py index 1394221..dba87fb 100644 --- a/shiori/bookmark/models.py +++ b/shiori/bookmark/models.py @@ -5,6 +5,7 @@ from django.contrib.auth.models import User from shortuuidfield import ShortUUIDField import jsonfield +from pyquery import PyQuery from shiori.bookmark.agents.feed_parser import FeedParser from shiori.bookmark import validators @@ -67,6 +68,24 @@ def get_absolute_url(self): return "/shiori/b/%s" % self.id +def retrieve_title(sender, instance, **kwargs): + """ Retreive title of specified url. + + Arguments: + sender: :model (Bookmark) + instance: Bookmark instance + **kwargs: not use + """ + if instance.title: + return instance.title + else: + if validators.validate_url(instance.url): + data = PyQuery(instance.url) + instance.title = data('head title').text() + +pre_save.connect(retrieve_title, sender=Bookmark) + + class BookmarkTag(models.Model): """ BookmarkTag model """ id = models.AutoField(primary_key=True) diff --git a/shiori/bookmark/validators.py b/shiori/bookmark/validators.py index b19fa23..f0b90be 100644 --- a/shiori/bookmark/validators.py +++ b/shiori/bookmark/validators.py @@ -7,7 +7,7 @@ else: from urlparse import urlparse from netaddr import IPAddress, AddrFormatError -from socket import gaierror, gethostbyname, getaddrinfo, AF_INET6 +import socket from shiori.core.settings import FEED_EXCLUDE_FQDN @@ -46,15 +46,17 @@ def getaddr(hostname): """ addresses = [] try: - addresses.append(gethostbyname(hostname)) + addresses.append(socket.gethostbyname(hostname)) except TypeError as error: print(error) - except gaierror as error: + except socket.gaierror as error: print(error) try: - addresses.append(getaddrinfo(hostname, None, AF_INET6)[0][4][0]) + addresses.append(socket.getaddrinfo(hostname, + None, + socket.AF_INET6)[0][4][0]) except TypeError as error: print(error) - except gaierror as error: + except socket.gaierror as error: print(error) return addresses diff --git a/shiori/static/css/main.css b/shiori/static/css/main.css index 2273996..a908daf 100644 --- a/shiori/static/css/main.css +++ b/shiori/static/css/main.css @@ -1,4 +1,6 @@ div.row { margin-top: 3em; } span.help { color: #757575; } div.footer { position: absolute; bottom: 0; color: #555;} -div.footer a { color: #f66; } \ No newline at end of file +div.footer a { color: #f66; } +a.btn { margin-bottom: 3px } +ul.profile { list-style-type: none; } \ No newline at end of file diff --git a/shiori/static/js/main.js b/shiori/static/js/main.js index 905a803..609d513 100644 --- a/shiori/static/js/main.js +++ b/shiori/static/js/main.js @@ -8,23 +8,25 @@ $(function() { if (tags == undefined) { return ''; } else { - return '

' + tags + '

'; + return '

' + + ' ' + tags + '

'; } } function protect(state) { if (state) { - return ' '; + return ' '; } else { return ''; } } function get_page(url) { + var s; if (url) { - var s = url.split('?')[1]; + s = url.split('?')[1]; } else { - var s = location.search.substring(1); + s = location.search.substring(1); } var page; if (s) { @@ -146,7 +148,9 @@ $(function() { } else { $(this.el) .append('' + + item.get('id') + + '?is_all=' + is_all() + + '">' + html_sanitize(item.get('category'), urlX, idX) + ' '); } @@ -164,17 +168,18 @@ $(function() { this.bookmarks = new BookmarkList(); this.listenTo(this.bookmarks, 'add', this.appendItem); this.listenTo(this.model, 'change', this.render); - this.model.fetch(); + this.model.fetch({data: {'page': get_page(), + 'is_all': is_all()}}); }, events: { - 'mouseover a.btn': 'loadBookmark' + 'click a.btn': 'loadBookmark' }, render: function() { var category = this.model.get('category'); $('h4', this.el).append(category); this.bookmarks.fetch({data: {'page': get_page(), 'is_all': is_all(), - 'categor': category}}); + 'category': category}}); return this; }, appendItem: function(item) { @@ -206,14 +211,13 @@ $(function() { content: elem('' + item.get('url') + '', - 'icon-share') + - elem(item.get('description'), 'icon-comment') + - elem(item.get('tags'), 'icon-tags'), + 'link') + + elem(item.get('description'), 'comment') + + elem(item.get('tags'), 'tags'), trigger: 'manual', delay: {show: 100, hide: 100} - }).click(function(e) { - $(this).popover('toggle'); }); + $('a#' + item.id, this.el).popover('toggle'); }, pagination: function(meta) { $('ul.pager').append(render_pagination(meta)); @@ -294,7 +298,9 @@ $(function() { } else { $(this.el) .append('' + + item.get('id') + + '?is_all=' + is_all() + + '">' + html_sanitize(item.get('tag'), urlX, idX) + ' '); } @@ -312,10 +318,10 @@ $(function() { this.bookmarks = new BookmarkList(); this.listenTo(this.bookmarks, 'add', this.appendItem); this.listenTo(this.model, 'change', this.render); - this.model.fetch(); + this.model.fetch({data: {'is_all': is_all()}}); }, events: { - 'mouseover a.btn': 'loadBookmark' + 'click a.btn': 'loadBookmark' }, render: function() { var that = this; @@ -360,17 +366,15 @@ $(function() { content: elem('' + item.get('url') + '', - 'icon-share') + + 'link') + elem(html_sanitize(item.get('description'), urlX, idX), - 'icon-comment') + + 'comment') + elem(html_sanitize(item.get('category'), urlX, idX), - 'icon-book'), + 'book'), trigger: 'manual', - delay: {show: 100, hide: 100} - }).click(function(e) { - $(this).popover('toggle'); - }); + delay: {show: 100, hide: 100}}); + $('a#' + item.id, this.el).popover('toggle'); } }); @@ -411,7 +415,7 @@ $(function() { 'search': search_word()}}); }, events: { - 'mouseover a.btn': 'loadBookmark' + 'click a.btn': 'loadBookmark' }, appendItem: function(item) { if (item.get('meta')) { @@ -444,23 +448,22 @@ $(function() { content: elem('' + item.get('url') + '', - 'icon-share') + + 'link') + elem(html_sanitize(item.get('description'), urlX, idX), - 'icon-comment') + + 'comment') + elem('' + html_sanitize(item.get('category'), urlX, idX) + '', - 'icon-book') + + 'book') + elem(html_sanitize(item.get('tags'), urlX, idX), - 'icon-tags'), + 'tags'), trigger: 'manual', delay: {show: 100, hide: 100} - }).click(function(e) { - $(this).popover('toggle'); }); + $('a#' + item.id, this.el).popover('toggle'); } }); @@ -568,10 +571,11 @@ $(function() { var description = html_sanitize( this.$('textarea#description').val(), urlX, idX); + var is_hide; if (this.$('input#is_hide').prop('checked')) { - var is_hide = true; + is_hide = true; } else { - var is_hide = false; + is_hide = false; } this.bookmarks.create({ @@ -594,7 +598,15 @@ $(function() { }, error: function(_coll, xhr, options) { console.log(xhr.responseText); - display_message(this.el, xhr.responseText, 'alert-error'); + if (xhr.responseText.search('IntegrityError') == 0) { + display_message(this.el, + 'Input title why cannot get title.', + 'alert-error'); + } else { + display_message(this.el, + xhr.responseText, + 'alert-error'); + } } }); }, @@ -846,7 +858,7 @@ $(function() { 'click a#profile': 'profile', 'click a#categories': 'categories', 'click a#tags': 'tags', - 'click span#search-btn': 'search', + 'click button#search-btn': 'search', 'click input#is_all': 'toggle_view' }, initialize: function() { @@ -902,9 +914,10 @@ $(function() { return false; }, render: function() { - $('div#submenu', this.el) - .append('Categories') - .append('Tags'); + $('div#submenu ul', this.el) + .append('
  • ' + + 'Categories
  • ') + .append('
  • Tags
  • '); if (is_all() == 'true') { $('input#is_all').attr('checked', true); } else { @@ -951,7 +964,6 @@ $(function() { categories: function() { window.App.render(); var categoriesListView = new CategoriesListView(); - categoriesListView.render(); }, category: function(id) { window.App.render(); diff --git a/shiori/templates/bookmark/edit.html b/shiori/templates/bookmark/edit.html index 235a4a3..41616a0 100644 --- a/shiori/templates/bookmark/edit.html +++ b/shiori/templates/bookmark/edit.html @@ -7,40 +7,36 @@
    {% csrf_token %}
    -
    - -
    - - required -
    - -
    - - required -
    - -
    - - retrieve web page title automatically in default. -
    - -
    - - add a new tag when keydown "Enter" key. -
    - -
    - -
    - -
    - - public mode when not check in default. +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    +
    -
    - - +
    + +
    diff --git a/shiori/templates/bookmark/feed_subscription.html b/shiori/templates/bookmark/feed_subscription.html index 1ded67d..bc03060 100644 --- a/shiori/templates/bookmark/feed_subscription.html +++ b/shiori/templates/bookmark/feed_subscription.html @@ -16,42 +16,44 @@ - diff --git a/shiori/templates/bookmark/profile.html b/shiori/templates/bookmark/profile.html index 4cce3e5..dc19e70 100644 --- a/shiori/templates/bookmark/profile.html +++ b/shiori/templates/bookmark/profile.html @@ -2,13 +2,11 @@ {% block content %}
    -
    -
    username
    {{ user.username }}
    -
    Full name
    {{ user.first_name }} {{ user.last_name }}
    -
    email
    {{ user.email }}
    -
    date joined
    {{ user.date_joined }}
    -
    last login
    {{ user.last_login }}
    -
    +
    {% endblock %} diff --git a/shiori/templates/layout.html b/shiori/templates/layout.html index 1bbfc16..cd3fcfd 100644 --- a/shiori/templates/layout.html +++ b/shiori/templates/layout.html @@ -2,9 +2,14 @@ - - - + + + + + + + + @@ -20,42 +25,36 @@
    -