diff options
author | Arun <engineerarun@gmail.com> | 2024-10-22 22:47:24 +0530 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-10-22 22:47:24 +0530 |
commit | 48bf29e0f03b754c5d2810a101911e02708b277f (patch) | |
tree | df370cf051cc74fa9df75a46f423d3ff13311101 | |
parent | 1f6c1a8fe168314d38651e500e5cf0584f3657a1 (diff) | |
parent | de8bc94b4095c9ca18f4e26a6a58b3f7d7f28551 (diff) |
Merge pull request #789 from LeXofLeviafan/swap-indices
Bookmark index swapping
-rw-r--r-- | README.md | 19 | ||||
-rw-r--r-- | auto-completion/bash/buku-completion.bash | 3 | ||||
-rw-r--r-- | auto-completion/fish/buku.fish | 2 | ||||
-rw-r--r-- | auto-completion/zsh/_buku | 2 | ||||
-rwxr-xr-x | buku | 57 | ||||
-rw-r--r-- | buku.1 | 12 | ||||
-rw-r--r-- | bukuserver/forms.py | 5 | ||||
-rw-r--r-- | bukuserver/templates/bukuserver/bookmarks_list.html | 48 | ||||
-rw-r--r-- | bukuserver/translations/de/LC_MESSAGES/messages.po | 62 | ||||
-rw-r--r-- | bukuserver/translations/fr/LC_MESSAGES/messages.po | 62 | ||||
-rw-r--r-- | bukuserver/translations/ru/LC_MESSAGES/messages.mo | bin | 11514 -> 12190 bytes | |||
-rw-r--r-- | bukuserver/translations/ru/LC_MESSAGES/messages.po | 62 | ||||
-rw-r--r-- | bukuserver/views.py | 6 | ||||
-rw-r--r-- | tests/test_bukuDb.py | 9 |
14 files changed, 293 insertions, 56 deletions
@@ -191,6 +191,7 @@ EDIT OPTIONS: clears description, if no arguments --immutable N disable web-fetch during auto-refresh N=0: mutable (default), N=1: immutable + --swap N M swap two records at specified indices SEARCH OPTIONS: -s, --sany [...] find records with ANY matching keyword @@ -290,12 +291,24 @@ SYMBOLS: PROMPT KEYS: 1-N browse search result indices and/or ranges + R [N] print out N random search results + (or random bookmarks if negative or N/A) + ^ id1 id2 swap two records at specified indices O [id|range [...]] open search results/indices in GUI browser toggle try GUI browser if no arguments a open all results in browser s keyword [...] search for records with ANY keyword S keyword [...] search for records with ALL keywords d match substrings ('pen' matches 'opened') + m search with markers - search string is split + into keywords by prefix markers, which determine + what field the keywords is searched in: + '.', '>' or ':' - title, description or URL + '#'/'#,' - tags (comma-separated, partial/full match) + '*' - all fields (can be omitted in the 1st keyword) + note: tag marker is not affected by 'd' (deep search) + v fields change sorting order (default is '+index') + multiple comma/space separated fields can be specified r expression run a regex search t [tag, ...] search by tags; show taglist, if no args g taglist id|range [...] [>>|>|<<] [record id|range ...] @@ -548,7 +561,11 @@ PROMPT KEYS: $ buku --random -S kernel debugging --export random.md -46. More **help**: +46. Swap positions of records #4 and #5: + + $ buku --swap 4 5 + +47. More **help**: $ buku -h $ man buku diff --git a/auto-completion/bash/buku-completion.bash b/auto-completion/bash/buku-completion.bash index 9bf9257..1b3f64d 100644 --- a/auto-completion/bash/buku-completion.bash +++ b/auto-completion/bash/buku-completion.bash @@ -39,11 +39,13 @@ _buku () { --order -p --print -r --sreg + --random --replace -s --sany -S --sall --shorten --suggest + --swap -t --stag --tacit --tag @@ -76,6 +78,7 @@ _buku () { -s --sany -S --sall --shorten + --swap --threads --url -x --exclude diff --git a/auto-completion/fish/buku.fish b/auto-completion/fish/buku.fish index b013c5c..529d19f 100644 --- a/auto-completion/fish/buku.fish +++ b/auto-completion/fish/buku.fish @@ -32,11 +32,13 @@ complete -c buku -l offline --description 'add a bookmark without connec complete -c buku -l order -r --description 'order by fields (+/- prefix for direction)' complete -c buku -s p -l print --description 'show bookmark details' complete -c buku -s r -l sreg -r --description 'match a regular expression' +complete -c buku -l random --description 'random subset (of 1 or given amount)' complete -c buku -l replace -r --description 'replace a tag' complete -c buku -s s -l sany -r --description 'match any keyword' complete -c buku -s S -l sall -r --description 'match all keywords' complete -c buku -l shorten -r --description 'shorten a URL using tny.im' complete -c buku -l suggest --description 'show a list of similar tags' +complete -c buku -l swap -r --description 'swap 2 given bookmark indices' complete -c buku -s t -l stag --description 'search by tag or show tags' complete -c buku -l tacit --description 'reduce verbosity' complete -c buku -l tag --description 'set tags, use + to append, - to remove' diff --git a/auto-completion/zsh/_buku b/auto-completion/zsh/_buku index f99a486..d0a2423 100644 --- a/auto-completion/zsh/_buku +++ b/auto-completion/zsh/_buku @@ -37,11 +37,13 @@ args=( '(--order)--order[order by fields (+/- prefix for direction)]:fields' '(-p --print)'{-p,--print}'[show bookmark details]' '(-r --sreg)'{-r,--sreg}'[match a regular expression]:regex' + '(--random)--random[random subset (of 1 or given amount)]::amount' '(--replace)--replace[replace a tag]:tag to replace' '(-s --sany)'{-s,--sany}'[match any keyword]:keyword(s)' '(-S --sall)'{-S,--sall}'[match all keywords]:keyword(s)' '(--shorten)--shorten[shorten a URL using tny.im]:index/url' '(--suggest)--suggest[show a list of similar tags]' + '(--swap)--swap[swap 2 given bookmark indices]:index1 index2' '(-t --stag)'{-t,--stag}'[search by tag or show tags]' '(--tacit)--tacit[reduce verbosity]' '(--tag)--tag[set tags, use + to append, - to remove]' @@ -1791,6 +1791,40 @@ class BukuDb: return search_results return filter_from(search_results, self.searchdb(without, deep=deep, markers=markers), exclude=True) + def swap_recs(self, index1: int, index2: int, *, lock: bool = True, delay_commit: bool = False): + """Swaps two records with given indices + + Parameters + ---------- + index1 : int + Index of the 1st record to be exchanged. + index2 : int + Index of the 2nd record to be exchanged. + lock : bool + Whether to restrict concurrent access (True by default). + delay_commit : bool + True if record should not be committed to the DB, + leaving commit responsibility to caller. Default is False. + + Returns + ------- + bool + True on success, False on failure. + """ + if lock: + with self.lock: + return self.swap_recs(index1, index2, lock=False, delay_commit=delay_commit) + + max_id = self.get_max_id() + if not max_id or index1 == index2 or not all(0 < x <= max_id for x in [index1, index2]): + return False + + self.cur.executemany('UPDATE bookmarks SET id = ? WHERE id = ?', + [(max_id+1, index1), (index1, index2), (index2, max_id+1)]) + if not delay_commit: + self.conn.commit() + return True + def compactdb(self, index: int, delay_commit: bool = False): """When an entry at index is deleted, move the last entry in DB to index, if index is lesser. @@ -3362,6 +3396,7 @@ PROMPT KEYS: 1-N browse search result indices and/or ranges R [N] print out N random search results (or random bookmarks if negative or N/A) + ^ id1 id2 swap two records at specified indices O [id|range [...]] open search results/indices in GUI browser toggle try GUI browser if no arguments a open all results in browser @@ -4705,7 +4740,7 @@ def prompt(obj, results, noninteractive=False, deep=False, listtags=False, sugge if nav == 'n': continue - if (m := re.match(r'^R(?: (-)?([0-9]+))?$', nav)) and (n := int(m[2] or 1)) > 0: + if (m := re.match(r'^R(?: (-)?([0-9]+))?$', nav.rstrip())) and (n := int(m[2] or 1)) > 0: skip_print = True if results and not m[1]: # from search results picked = random.sample(results, min(n, len(results))) @@ -4716,6 +4751,14 @@ def prompt(obj, results, noninteractive=False, deep=False, listtags=False, sugge print_single_rec(row, columns=columns) continue + if (m := re.match(r'^\^ ([1-9][0-9]*) ([1-9][0-9]*)$', nav.rstrip())): + index1, index2 = map(int, m.group(1, 2)) + if bdb.swap_recs(index1, index2): + bdb.print_rec({index1, index2}) + else: + print('Failed to swap records #%d and #%d' % (index1, index2)) + continue + # search ANY match with new keywords if nav.startswith('s '): keywords = (nav[2:].split() if not markers else split_by_marker(nav[2:])) @@ -5881,13 +5924,15 @@ POSITIONAL ARGUMENTS: -c, --comment [...] notes or description of the bookmark clears description, if no arguments --immutable N disable web-fetch during auto-refresh - N=0: mutable (default), N=1: immutable''') + N=0: mutable (default), N=1: immutable + --swap N M swap two records at specified indices''') addarg = edit_grp.add_argument addarg('--url', nargs=1, help=hide) addarg('--tag', nargs='*', help=hide) addarg('--title', nargs='*', help=hide) addarg('-c', '--comment', nargs='*', help=hide) addarg('--immutable', type=int, choices={0, 1}, help=hide) + addarg('--swap', nargs=2, type=int, help=hide) _bool = lambda x: x if x is None else bool(x) _immutable = lambda args: _bool(args.immutable) @@ -6181,6 +6226,14 @@ POSITIONAL ARGUMENTS: colorize=not args.nc ) + if args.swap: + index1, index2 = args.swap + if bdb.swap_recs(index1, index2): + bdb.print_rec({index1, index2}) + else: + LOGERR('Failed to swap records #%d and #%d', index1, index2) + bdb.close_quit(0) + # Editor mode if args.write is not None: if not is_editor_valid(args.write): @@ -56,6 +56,7 @@ Bookmarks with immutable titles are listed with '(L)' after the title. - If --url is passed (and --title is omitted), update the title from web using the URL. Description is updated (if --comment is omitted). Tags remain untouched. - If indices are passed without any other options (--url, --title, --tag, --comment and --immutable), read the URLs from DB and update titles, description and append tags from web. Bookmarks marked immutable are skipped. - Can update bookmarks matching a search, when combined with any of the search options and no arguments to update are passed. + - Additionally, --swap allows to modify records order (standalone operation). .PP .IP 7. 4 \fBDelete\fR operation: @@ -143,6 +144,9 @@ Add notes or description of the bookmark, works with --add, --update. Clears the .TP .BI \--immutable " N" Set the title, description and tags of a bookmark immutable during autorefresh. Works with --add, --update. N=1 sets the immutable flag, N=0 removes it. If omitted, bookmarks are added with N=0. +.TP +.BI \--swap " N M" +Swap two records at specified indices. This is a standalone operation (cannot be invoked along with any other). .SH SEARCH OPTIONS .TP .BI \-s " " \--sany " keyword [...]" @@ -957,6 +961,14 @@ Print out a single \fBrandom\fR bookmark matching \fBsearch\fR criteria, and \fB .B buku --random -S kernel debugging --export random.md .EE .PP +.IP 46. 4 +Swap positions of records #4 and #5: +.PP +.EX +.IP +.B buku --swap 4 5 +.EE +.PP .SH AUTHOR diff --git a/bukuserver/forms.py b/bukuserver/forms.py index b9c60d2..6280f48 100644 --- a/bukuserver/forms.py +++ b/bukuserver/forms.py @@ -42,6 +42,11 @@ class BookmarkForm(FlaskForm): fetch = HiddenField(filters=[bool]) +class SwapForm(FlaskForm): + id1 = HiddenField(filters=[int]) + id2 = HiddenField(filters=[int]) + + class ApiTagForm(FlaskForm): class Meta: csrf = False diff --git a/bukuserver/templates/bukuserver/bookmarks_list.html b/bukuserver/templates/bukuserver/bookmarks_list.html index 18db15f..7325cc7 100644 --- a/bukuserver/templates/bukuserver/bookmarks_list.html +++ b/bukuserver/templates/bukuserver/bookmarks_list.html @@ -4,16 +4,62 @@ {% block head %} {{ super() }} {{ buku.close_if_popup() }} + <script> + function promptSwap(input, rowId, maxId={{count|tojson}}) { + let _id = input.value = prompt({{ _('Swap record #{} with record #')|tojson }}.replace('{}', rowId), rowId) || ""; + let error = (!_id ? "" : + !/^[1-9][0-9]*$/.test(_id) ? {{ _("Not a valid record index: '{}'")|tojson }}.replace('{}', _id) : + _id > maxId ? {{ _('There are only {} records in total!')|tojson }}.replace('{}', maxId) : + _id == `${rowId}` ? {{ _('Swapping a record with itself has no effect!')|tojson }} : null); + error && alert(error); + return (error == null); + } + </script> {% endblock %} {% block model_menu_bar_before_filters %} {{ super() }} {% if data %} - {% set _random = url_for('bookmark.details_view', modal=True, id='random', url=return_url, **(request.args|flt)) %} + {% set _random = url_for('.details_view', modal=True, id='random', url=return_url, **(request.args|flt)) %} <li><a id="random" data-target="#fa_modal_window" data-toggle="modal" href="{{ _random }}">{{ _('Random') }}</a></li> {% endif %} {% endblock %} +{% macro swap_rows_action(icon, row_id, step=None) %} {# based on admin/model/row_actions.delete_row() #} +<form class="icon" method="POST" action="{{ get_url('.swap') }}"> + {% if csrf_token %} + <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/> + {% endif %} + {% set _input = 'swap' + row_id|string %} + <input type="hidden" name="url" value="{{ return_url }}"/> + <input type="hidden" name="id1" value="{{ row_id }}"/> + <input type="hidden" name="id2"{% if step %} value="{{ row_id + step }}"{% else %} id="{{ _input }}"{% endif %}/> + <button title="{{ _('Swap with…') if not step else _('Move down') if step > 0 else _('Move up') }}" + {%- if not step %} onclick="return promptSwap({{_input}}, {{row_id}})"{% endif %}> + <span class="fa fa-{{icon}} glyphicon glyphicon-{{icon}}"></span> + </button> +</form> +{% endmacro %} + +{% block list_row_actions scoped %} + {% for action in list_row_actions %} + {{ action.render_ctx(get_pk_value(row), row) }} + {% endfor %} + {% if request.args|flt|length == 0 %} {# only shown when filters/ordering are disabled #} + <div class="swap-toolbar" style="margin-left: 10px"> + {% if row.id < 2 %} + <div style="display: inline-block; width: 14px"><!-- placeholder for the 1st row button --></div> + {% else %} + {{ swap_rows_action('arrow-up', row.id, -1) }} + {% endif %} + {{ swap_rows_action('transfer', row.id) }} + {% if row.id < count %} + {{ swap_rows_action('arrow-down', row.id, +1) }} + {% endif %} + </div> + {% endif %} +{% endblock %} + {% block tail %} {{ buku.fix_translations('bookmarks') }} {{ super() }} diff --git a/bukuserver/translations/de/LC_MESSAGES/messages.po b/bukuserver/translations/de/LC_MESSAGES/messages.po index a6ac1f2..a922f9b 100644 --- a/bukuserver/translations/de/LC_MESSAGES/messages.po +++ b/bukuserver/translations/de/LC_MESSAGES/messages.po @@ -158,11 +158,11 @@ msgstr "Schilder" msgid "Description" msgstr "" -#: /home/lex/Work/buku/bukuserver/forms.py:57 +#: /home/lex/Work/buku/bukuserver/forms.py:62 msgid "List of tags expected." msgstr "" -#: /home/lex/Work/buku/bukuserver/forms.py:84 +#: /home/lex/Work/buku/bukuserver/forms.py:89 msgid "Delete tags list from existing tags" msgstr "" @@ -206,7 +206,7 @@ msgid "Failed to create record." msgstr "" #: /home/lex/Work/buku/bukuserver/views.py:245 -#: /home/lex/Work/buku/bukuserver/views.py:546 +#: /home/lex/Work/buku/bukuserver/views.py:552 msgid "Failed to delete record." msgstr "" @@ -214,55 +214,55 @@ msgstr "" msgid "Invalid search mode combination" msgstr "" -#: /home/lex/Work/buku/bukuserver/views.py:342 +#: /home/lex/Work/buku/bukuserver/views.py:348 msgid "netloc match" msgstr "" -#: /home/lex/Work/buku/bukuserver/views.py:375 +#: /home/lex/Work/buku/bukuserver/views.py:381 msgid "contain" msgstr "" -#: /home/lex/Work/buku/bukuserver/views.py:376 +#: /home/lex/Work/buku/bukuserver/views.py:382 msgid "not contain" msgstr "" -#: /home/lex/Work/buku/bukuserver/views.py:377 +#: /home/lex/Work/buku/bukuserver/views.py:383 msgid "number equal" msgstr "" -#: /home/lex/Work/buku/bukuserver/views.py:378 +#: /home/lex/Work/buku/bukuserver/views.py:384 msgid "number not equal" msgstr "" -#: /home/lex/Work/buku/bukuserver/views.py:379 +#: /home/lex/Work/buku/bukuserver/views.py:385 msgid "number greater than" msgstr "" -#: /home/lex/Work/buku/bukuserver/views.py:380 +#: /home/lex/Work/buku/bukuserver/views.py:386 msgid "number smaller than" msgstr "" -#: /home/lex/Work/buku/bukuserver/views.py:406 -#: /home/lex/Work/buku/bukuserver/views.py:564 +#: /home/lex/Work/buku/bukuserver/views.py:412 +#: /home/lex/Work/buku/bukuserver/views.py:570 msgid "Failed to update record." msgstr "" -#: /home/lex/Work/buku/bukuserver/views.py:421 +#: /home/lex/Work/buku/bukuserver/views.py:427 msgid "<UNTAGGED>" msgstr "" -#: /home/lex/Work/buku/bukuserver/views.py:427 -#: /home/lex/Work/buku/bukuserver/views.py:464 +#: /home/lex/Work/buku/bukuserver/views.py:433 +#: /home/lex/Work/buku/bukuserver/views.py:470 msgctxt "tag" msgid "Name" msgstr "" -#: /home/lex/Work/buku/bukuserver/views.py:427 +#: /home/lex/Work/buku/bukuserver/views.py:433 msgctxt "tag" msgid "Usage Count" msgstr "" -#: /home/lex/Work/buku/bukuserver/views.py:527 +#: /home/lex/Work/buku/bukuserver/views.py:533 msgid "top most common" msgstr "" @@ -270,10 +270,38 @@ msgstr "" msgid "Pick another" msgstr "" +#: /home/lex/Work/buku/bukuserver/templates/bukuserver/bookmarks_list.html:9 +msgid "Swap record #{} with record #" +msgstr "" + +#: /home/lex/Work/buku/bukuserver/templates/bukuserver/bookmarks_list.html:11 +msgid "Not a valid record index: '{}'" +msgstr "" + +#: /home/lex/Work/buku/bukuserver/templates/bukuserver/bookmarks_list.html:12 +msgid "There are only {} records in total!" +msgstr "" + #: /home/lex/Work/buku/bukuserver/templates/bukuserver/bookmarks_list.html:13 +msgid "Swapping a record with itself has no effect!" +msgstr "" + +#: /home/lex/Work/buku/bukuserver/templates/bukuserver/bookmarks_list.html:24 msgid "Random" msgstr "Zufälliger" +#: /home/lex/Work/buku/bukuserver/templates/bukuserver/bookmarks_list.html:37 +msgid "Swap with…" +msgstr "" + +#: /home/lex/Work/buku/bukuserver/templates/bukuserver/bookmarks_list.html:37 +msgid "Move down" +msgstr "" + +#: /home/lex/Work/buku/bukuserver/templates/bukuserver/bookmarks_list.html:37 +msgid "Move up" +msgstr "" + #: /home/lex/Work/buku/bukuserver/templates/bukuserver/home.html:14 msgid "Search bookmark" msgstr "" diff --git a/bukuserver/translations/fr/LC_MESSAGES/messages.po b/bukuserver/translations/fr/LC_MESSAGES/messages.po index 1bc6d84..ac6c8e7 100644 --- a/bukuserver/translations/fr/LC_MESSAGES/messages.po +++ b/bukuserver/translations/fr/LC_MESSAGES/messages.po @@ -158,11 +158,11 @@ msgstr "Étiquettes" msgid "Description" msgstr "" -#: /home/lex/Work/buku/bukuserver/forms.py:57 +#: /home/lex/Work/buku/bukuserver/forms.py:62 msgid "List of tags expected." msgstr "" -#: /home/lex/Work/buku/bukuserver/forms.py:84 +#: /home/lex/Work/buku/bukuserver/forms.py:89 msgid "Delete tags list from existing tags" msgstr "" @@ -206,7 +206,7 @@ msgid "Failed to create record." msgstr "" #: /home/lex/Work/buku/bukuserver/views.py:245 -#: /home/lex/Work/buku/bukuserver/views.py:546 +#: /home/lex/Work/buku/bukuserver/views.py:552 msgid "Failed to delete record." msgstr "" @@ -214,55 +214,55 @@ msgstr "" msgid "Invalid search mode combination" msgstr "" -#: /home/lex/Work/buku/bukuserver/views.py:342 +#: /home/lex/Work/buku/bukuserver/views.py:348 msgid "netloc match" msgstr "" -#: /home/lex/Work/buku/bukuserver/views.py:375 +#: /home/lex/Work/buku/bukuserver/views.py:381 msgid "contain" msgstr "" -#: /home/lex/Work/buku/bukuserver/views.py:376 +#: /home/lex/Work/buku/bukuserver/views.py:382 msgid "not contain" msgstr "" -#: /home/lex/Work/buku/bukuserver/views.py:377 +#: /home/lex/Work/buku/bukuserver/views.py:383 msgid "number equal" msgstr "" -#: /home/lex/Work/buku/bukuserver/views.py:378 +#: /home/lex/Work/buku/bukuserver/views.py:384 msgid "number not equal" msgstr "" -#: /home/lex/Work/buku/bukuserver/views.py:379 +#: /home/lex/Work/buku/bukuserver/views.py:385 msgid "number greater than" msgstr "" -#: /home/lex/Work/buku/bukuserver/views.py:380 +#: /home/lex/Work/buku/bukuserver/views.py:386 msgid "number smaller than" msgstr "" -#: /home/lex/Work/buku/bukuserver/views.py:406 -#: /home/lex/Work/buku/bukuserver/views.py:564 +#: /home/lex/Work/buku/bukuserver/views.py:412 +#: /home/lex/Work/buku/bukuserver/views.py:570 msgid "Failed to update record." msgstr "" -#: /home/lex/Work/buku/bukuserver/views.py:421 +#: /home/lex/Work/buku/bukuserver/views.py:427 msgid "<UNTAGGED>" msgstr "" -#: /home/lex/Work/buku/bukuserver/views.py:427 -#: /home/lex/Work/buku/bukuserver/views.py:464 +#: /home/lex/Work/buku/bukuserver/views.py:433 +#: /home/lex/Work/buku/bukuserver/views.py:470 msgctxt "tag" msgid "Name" msgstr "" -#: /home/lex/Work/buku/bukuserver/views.py:427 +#: /home/lex/Work/buku/bukuserver/views.py:433 msgctxt "tag" msgid "Usage Count" msgstr "" -#: /home/lex/Work/buku/bukuserver/views.py:527 +#: /home/lex/Work/buku/bukuserver/views.py:533 msgid "top most common" msgstr "" @@ -270,10 +270,38 @@ msgstr "" msgid "Pick another" msgstr "" +#: /home/lex/Work/buku/bukuserver/templates/bukuserver/bookmarks_list.html:9 +msgid "Swap record #{} with record #" +msgstr "" + +#: /home/lex/Work/buku/bukuserver/templates/bukuserver/bookmarks_list.html:11 +msgid "Not a valid record index: '{}'" +msgstr "" + +#: /home/lex/Work/buku/bukuserver/templates/bukuserver/bookmarks_list.html:12 +msgid "There are only {} records in total!" +msgstr "" + #: /home/lex/Work/buku/bukuserver/templates/bukuserver/bookmarks_list.html:13 +msgid "Swapping a record with itself has no effect!" +msgstr "" + +#: /home/lex/Work/buku/bukuserver/templates/bukuserver/bookmarks_list.html:24 msgid "Random" msgstr "Aléatoire" +#: /home/lex/Work/buku/bukuserver/templates/bukuserver/bookmarks_list.html:37 +msgid "Swap with…" +msgstr "" + +#: /home/lex/Work/buku/bukuserver/templates/bukuserver/bookmarks_list.html:37 +msgid "Move down" +msgstr "" + +#: /home/lex/Work/buku/bukuserver/templates/bukuserver/bookmarks_list.html:37 +msgid "Move up" +msgstr "" + #: /home/lex/Work/buku/bukuserver/templates/bukuserver/home.html:14 msgid "Search bookmark" msgstr "" diff --git a/bukuserver/translations/ru/LC_MESSAGES/messages.mo b/bukuserver/translations/ru/LC_MESSAGES/messages.mo Binary files differindex 67ae319..f909f5a 100644 --- a/bukuserver/translations/ru/LC_MESSAGES/messages.mo +++ b/bukuserver/translations/ru/LC_MESSAGES/messages.mo diff --git a/bukuserver/translations/ru/LC_MESSAGES/messages.po b/bukuserver/translations/ru/LC_MESSAGES/messages.po index 6f18bbe..c3c2f1f 100644 --- a/bukuserver/translations/ru/LC_MESSAGES/messages.po +++ b/bukuserver/translations/ru/LC_MESSAGES/messages.po @@ -158,11 +158,11 @@ msgstr "Теги" msgid "Description" msgstr "Описание" -#: /home/lex/Work/buku/bukuserver/forms.py:57 +#: /home/lex/Work/buku/bukuserver/forms.py:62 msgid "List of tags expected." msgstr "Список ожидаемых тегов" -#: /home/lex/Work/buku/bukuserver/forms.py:84 +#: /home/lex/Work/buku/bukuserver/forms.py:89 msgid "Delete tags list from existing tags" msgstr "Удалить список тегов из существующих" @@ -206,7 +206,7 @@ msgid "Failed to create record." msgstr "Ошибка создания записи." #: /home/lex/Work/buku/bukuserver/views.py:245 -#: /home/lex/Work/buku/bukuserver/views.py:546 +#: /home/lex/Work/buku/bukuserver/views.py:552 msgid "Failed to delete record." msgstr "Ошибка удаления записи." @@ -214,55 +214,55 @@ msgstr "Ошибка удаления записи." msgid "Invalid search mode combination" msgstr "Некорректная комбинация фильтров поиска" -#: /home/lex/Work/buku/bukuserver/views.py:342 +#: /home/lex/Work/buku/bukuserver/views.py:348 msgid "netloc match" msgstr "на сайт" -#: /home/lex/Work/buku/bukuserver/views.py:375 +#: /home/lex/Work/buku/bukuserver/views.py:381 msgid "contain" msgstr "содержат" -#: /home/lex/Work/buku/bukuserver/views.py:376 +#: /home/lex/Work/buku/bukuserver/views.py:382 msgid "not contain" msgstr "не содержат" -#: /home/lex/Work/buku/bukuserver/views.py:377 +#: /home/lex/Work/buku/bukuserver/views.py:383 msgid "number equal" msgstr "количество равно" -#: /home/lex/Work/buku/bukuserver/views.py:378 +#: /home/lex/Work/buku/bukuserver/views.py:384 msgid "number not equal" msgstr "количество не равно" -#: /home/lex/Work/buku/bukuserver/views.py:379 +#: /home/lex/Work/buku/bukuserver/views.py:385 msgid "number greater than" msgstr "количество больше чем" -#: /home/lex/Work/buku/bukuserver/views.py:380 +#: /home/lex/Work/buku/bukuserver/views.py:386 msgid "number smaller than" msgstr "количество меньше чем" -#: /home/lex/Work/buku/bukuserver/views.py:406 -#: /home/lex/Work/buku/bukuserver/views.py:564 +#: /home/lex/Work/buku/bukuserver/views.py:412 +#: /home/lex/Work/buku/bukuserver/views.py:570 msgid "Failed to update record." msgstr "Ошибка обновления записи." -#: /home/lex/Work/buku/bukuserver/views.py:421 +#: /home/lex/Work/buku/bukuserver/views.py:427 msgid "<UNTAGGED>" msgstr "<БЕЗ ТЕГОВ>" -#: /home/lex/Work/buku/bukuserver/views.py:427 -#: /home/lex/Work/buku/bukuserver/views.py:464 +#: /home/lex/Work/buku/bukuserver/views.py:433 +#: /home/lex/Work/buku/bukuserver/views.py:470 msgctxt "tag" msgid "Name" msgstr "Тег" -#: /home/lex/Work/buku/bukuserver/views.py:427 +#: /home/lex/Work/buku/bukuserver/views.py:433 msgctxt "tag" msgid "Usage Count" msgstr "Число закладок" -#: /home/lex/Work/buku/bukuserver/views.py:527 +#: /home/lex/Work/buku/bukuserver/views.py:533 msgid "top most common" msgstr "самое распространённое" @@ -270,10 +270,38 @@ msgstr "самое распространённое" msgid "Pick another" msgstr "Показать другую" +#: /home/lex/Work/buku/bukuserver/templates/bukuserver/bookmarks_list.html:9 +msgid "Swap record #{} with record #" +msgstr "Поменять местами запись #{} с записью #" + +#: /home/lex/Work/buku/bukuserver/templates/bukuserver/bookmarks_list.html:11 +msgid "Not a valid record index: '{}'" +msgstr "Некорректный номер строки: '{}'" + +#: /home/lex/Work/buku/bukuserver/templates/bukuserver/bookmarks_list.html:12 +msgid "There are only {} records in total!" +msgstr "Всего существует только {} записей!" + #: /home/lex/Work/buku/bukuserver/templates/bukuserver/bookmarks_list.html:13 +msgid "Swapping a record with itself has no effect!" +msgstr "Попытка поменять запись местами саму с собой ничего не даст!" + +#: /home/lex/Work/buku/bukuserver/templates/bukuserver/bookmarks_list.html:24 msgid "Random" msgstr "Случайная" +#: /home/lex/Work/buku/bukuserver/templates/bukuserver/bookmarks_list.html:37 +msgid "Swap with…" +msgstr "Поменять местами с…" + +#: /home/lex/Work/buku/bukuserver/templates/bukuserver/bookmarks_list.html:37 +msgid "Move down" +msgstr "Сдвинуть вниз" + +#: /home/lex/Work/buku/bukuserver/templates/bukuserver/bookmarks_list.html:37 +msgid "Move up" +msgstr "Сдвинуть вверх" + #: /home/lex/Work/buku/bukuserver/templates/bukuserver/home.html:14 msgid "Search bookmark" msgstr "Искать закладку" diff --git a/bukuserver/views.py b/bukuserver/views.py index 8c37c8a..733de6e 100644 --- a/bukuserver/views.py +++ b/bukuserver/views.py @@ -297,6 +297,12 @@ class BookmarkModelView(BaseModelView, ApplyFiltersMixin): def get_pk_value(self, model): return model.id + @expose('/swap', methods=['POST']) + def swap(self): + form = forms.SwapForm() + self.bukudb.swap_recs(form.id1.data, form.id2.data) + return redirect(request.form.get('url', url_for('bookmark.index_view'))) + def scaffold_list_columns(self): return [x.name.lower() for x in BookmarkField] diff --git a/tests/test_bukuDb.py b/tests/test_bukuDb.py index 4c036fb..55a4a00 100644 --- a/tests/test_bukuDb.py +++ b/tests/test_bukuDb.py @@ -208,8 +208,15 @@ class TestBukuDb(unittest.TestCase): for pair in zip(from_db[1:], bookmark): self.assertEqual(*pair) - # TODO: tags should be passed to the api as a sequence... + def test_swap_recs(self): + for bookmark in self.bookmarks: + _add_rec(self.bdb, *bookmark) + for id1, id2 in [(0, 1), (1, 4), (1, 1)]: + self.assertFalse(self.bdb.swap_recs(id1, id2), 'Not a valid index pair: (%d, %d)' % (id1, id2)) + self.assertTrue(self.bdb.swap_recs(1, 3), 'This one should be valid') # 3, 2, 1 + self.assertEqual([x[0] for x in reversed(self.bookmarks)], [x.url for x in self.bdb.get_rec_all()]) + # TODO: tags should be passed to the api as a sequence... def test_suggest_tags(self): for bookmark in self.bookmarks: _add_rec(self.bdb, *bookmark) |