From 1c64c03bd096ac6c92bee4361926611be3d22259 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=C5=81ukasz=20Rekucki?= Date: Fri, 4 Sep 2009 13:06:59 +0200 Subject: [PATCH 01/16] Przyciski do zmiany czcionki. --- apps/toolbar/templates/toolbar/toolbar.html | 2 +- dump_toolbar.sh | 1 + fixtures/przyciski.xml | 11 +++++++++- .../templates/explorer/panels/xmleditor.html | 22 +------------------ 4 files changed, 13 insertions(+), 23 deletions(-) create mode 100755 dump_toolbar.sh diff --git a/apps/toolbar/templates/toolbar/toolbar.html b/apps/toolbar/templates/toolbar/toolbar.html index 29528c16..21135305 100644 --- a/apps/toolbar/templates/toolbar/toolbar.html +++ b/apps/toolbar/templates/toolbar/toolbar.html @@ -21,7 +21,7 @@ ui:action-params="{{ button.params|escape }}" {% if button.key %}ui:hotkey="{{ button.key|keycode }}"{% endif %} {% if button.tooltip %}ui:tooltip="{{ button.tooltip }}"{% endif %} > - {{ button.label }} + {{ button.label|safe }} {% endfor %}

diff --git a/dump_toolbar.sh b/dump_toolbar.sh new file mode 100755 index 00000000..3bac9fe6 --- /dev/null +++ b/dump_toolbar.sh @@ -0,0 +1 @@ +./project/manage.py dumpdata --format=xml toolbar > fixtures/przyciski.xml diff --git a/fixtures/przyciski.xml b/fixtures/przyciski.xml index a8ad2c19..287a0cc9 100644 --- a/fixtures/przyciski.xml +++ b/fixtures/przyciski.xml @@ -1,5 +1,5 @@ -Autokorektaautokorekta0Formatowanieformatowanie0Novelpagesnovelpages({exprs: [ +Autokorektaautokorekta0Formatowanieformatowanie0Widokdisplay_options2A<sup>+</sup>increase_font_size({change: 2})codemirror_fontsize+Zwiększ rozmiar czcionki.A<sup>-</sup>descrease_font_size({change: -2})codemirror_fontsize-Zmniejsz rozmiar czcionki.A<sup>=</sup>reset_font_size({fontSize: 13})codemirror_fontsize=Przywróć orginalny rozmiar czcionki.Novelpagesnovelpages({exprs: [ ["\\,\\.\\.|\\.\\,\\.|\\.\\.\\,", "..."], ["„", ",,"] /* DOUBLE LOW-9 QUOTATION MARK */ ]}) @@ -50,4 +50,13 @@ else { cm.setLineContent(line, content); line = cm.nextLine(line); } while( !(line === false) ); +}var texteditor = panel.texteditor; +var frameBody = $('body', $(texteditor.frame).contents()); + +if(params.fontSize) { + frameBody.css('font-size', params.fontSize); +} +else { + var old_size = parseInt(frameBody.css('font-size')); + frameBody.css('font-size', old_size + (params.change || 0) ); } diff --git a/project/templates/explorer/panels/xmleditor.html b/project/templates/explorer/panels/xmleditor.html index 39a05e52..76018ca7 100644 --- a/project/templates/explorer/panels/xmleditor.html +++ b/project/templates/explorer/panels/xmleditor.html @@ -1,15 +1,9 @@ {% load toolbar_tags %} -
-
A-
-
A+
-
-
- {% toolbar %} -- 2.20.1 From 8790d8f9a2625432093c1e78ceb69da83fff9d3e Mon Sep 17 00:00:00 2001 From: =?utf8?q?=C5=81ukasz=20Rekucki?= Date: Fri, 4 Sep 2009 16:44:01 +0200 Subject: [PATCH 03/16] Fixed upload. --- apps/explorer/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/explorer/views.py b/apps/explorer/views.py index d2ba7f79..cb6988ae 100644 --- a/apps/explorer/views.py +++ b/apps/explorer/views.py @@ -71,7 +71,7 @@ def file_upload(request, repo): def upload_action(): print 'Adding file: %s' % f.name - repo._add_file(f.name, f.read().decode('utf-8')) + repo._add_file(f.name, decoded) repo._commit( message="File %s uploaded from platform by %s" %\ (f.name, request.user.username), \ -- 2.20.1 From c94e18af76ba34ec6d4b3bcedb44c486e101f2b2 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=C5=81ukasz=20Rekucki?= Date: Fri, 4 Sep 2009 16:47:48 +0200 Subject: [PATCH 04/16] Fixed mercurial paths encoding. --- apps/explorer/views.py | 2 +- lib/hg.py | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/apps/explorer/views.py b/apps/explorer/views.py index cb6988ae..7d186887 100644 --- a/apps/explorer/views.py +++ b/apps/explorer/views.py @@ -71,7 +71,7 @@ def file_upload(request, repo): def upload_action(): print 'Adding file: %s' % f.name - repo._add_file(f.name, decoded) + repo._add_file(f.name, decoded.encode('utf-8') ) repo._commit( message="File %s uploaded from platform by %s" %\ (f.name, request.user.username), \ diff --git a/lib/hg.py b/lib/hg.py index 6dd6e0cb..18a8d18a 100644 --- a/lib/hg.py +++ b/lib/hg.py @@ -7,7 +7,8 @@ import mercurial.merge, mercurial.error encoding.encoding = 'utf-8' - +def clearpath(path): + return unicode(path).encode("utf-8") class Repository(object): """Abstrakcja repozytorium Mercurial. Działa z Mercurial w wersji 1.3.1.""" @@ -44,6 +45,8 @@ class Repository(object): return self.in_branch(lambda: self._get_file(path), branch) def _get_file(self, path): + path = clearpath(path) + if not self._file_exists(path): raise RepositoryException("File not availble in this branch.") @@ -53,18 +56,21 @@ class Repository(object): return self.in_branch(lambda: self._file_exists(path), branch) def _file_exists(self, path): + path = clearpath(path) return self.repo.dirstate[path] != "?" def write_file(self, path, value, branch): return self.in_branch(lambda: self._write_file(path, value), branch) - def _write_file(self, path, value): + def _write_file(self, path, value): + path = clearpath(path) return self.repo.wwrite(path, value, []) def add_file(self, path, value, branch): return self.in_branch(lambda: self._add_file(path, value), branch) def _add_file(self, path, value): + path = clearpath(path) self._write_file(path, value) return self.repo.add( [path] ) -- 2.20.1 From f62465929c480c1c05310df665fae32b5a24fb98 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=C5=81ukasz=20Rekucki?= Date: Fri, 4 Sep 2009 22:43:27 +0200 Subject: [PATCH 05/16] Dodano wyszukiwarke na stronie glownej. Refs #75. --- apps/explorer/views.py | 22 ++----- lib/hg.py | 3 +- project/static/css/filelist.css | 33 ++++++++++ project/static/js/editor.js | 4 +- project/static/js/jquery.hpanel.js | 2 +- project/static/js/jquery.lazyload.js | 0 project/static/js/jquery.paginate.js | 66 ++++++++++++++++++++ project/templates/explorer/file_list.html | 75 ++++++++++++++--------- 8 files changed, 154 insertions(+), 51 deletions(-) create mode 100755 project/static/css/filelist.css mode change 100644 => 100755 project/static/js/jquery.lazyload.js create mode 100644 project/static/js/jquery.paginate.js diff --git a/apps/explorer/views.py b/apps/explorer/views.py index 7d186887..d6118acb 100644 --- a/apps/explorer/views.py +++ b/apps/explorer/views.py @@ -5,7 +5,7 @@ from librarian import html, parser, dcparser, ParseError, ValidationError from django.conf import settings from django.contrib.auth.decorators import login_required, permission_required -from django.core.paginator import Paginator, InvalidPage, EmptyPage + from django.core.urlresolvers import reverse from django.http import HttpResponseRedirect, HttpResponse from django.utils import simplejson as json @@ -40,21 +40,12 @@ def ajax_login_required(view): # @with_repo def file_list(request, repo): - paginator = Paginator( repo.file_list('default'), 100); + latest_default = repo.repo.branchtags()['default'] + files = list( repo.repo[latest_default] ) bookform = forms.BookUploadForm() - try: - page = int(request.GET.get('page', '1')) - except ValueError: - page = 1 - - try: - files = paginator.page(page) - except (EmptyPage, InvalidPage): - files = paginator.page(paginator.num_pages) - return direct_to_template(request, 'explorer/file_list.html', extra_context={ - 'files': files, 'page': page, 'bookform': bookform, + 'files': files, 'bookform': bookform, }) @permission_required('explorer.can_add_files') @@ -186,7 +177,7 @@ def file_dc(request, path, repo): @login_required @with_repo def display_editor(request, path, repo): - path = unicode(path).encode("utf-8") + if not repo.file_exists(path, models.user_branch(request.user)): try: data = repo.get_file(path, 'default') @@ -199,7 +190,7 @@ def display_editor(request, path, repo): repo.in_branch(new_file, models.user_branch(request.user) ) except hg.RepositoryException, e: - return direct_to_templace(request, 'explorer/file_unavailble.html',\ + return direct_to_template(request, 'explorer/file_unavailble.html',\ extra_context = { 'path': path, 'error': e }) return direct_to_template(request, 'explorer/editor.html', extra_context={ @@ -215,7 +206,6 @@ def display_editor(request, path, repo): @ajax_login_required @with_repo def xmleditor_panel(request, path, repo): - form = forms.BookForm() text = repo.get_file(path, models.user_branch(request.user)) return direct_to_template(request, 'explorer/panels/xmleditor.html', extra_context={ diff --git a/lib/hg.py b/lib/hg.py index 18a8d18a..07ec9a79 100644 --- a/lib/hg.py +++ b/lib/hg.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- import os -import codecs -from mercurial import localrepo, ui, match, node, encoding, util +from mercurial import localrepo, ui, encoding, util import mercurial.merge, mercurial.error encoding.encoding = 'utf-8' diff --git a/project/static/css/filelist.css b/project/static/css/filelist.css new file mode 100755 index 00000000..f5b8ce0c --- /dev/null +++ b/project/static/css/filelist.css @@ -0,0 +1,33 @@ +/* + Document : filelist + Created on : 2009-09-04, 20:44:44 + Author : lreqc + Description: + Dodatkowe style dla listy plików na stronie głównej. +*/ + +#main-page-widgets > div { + float: left; + border: 1px solid black; + padding: 0.5em 2em; + margin: 1em; +} + +.file-list-widget { + background: #DDF; + max-width: 60%; +} + +.file-list-widget .page-nav-wrap button { + width: 2.5em; +} + +.upload-file-widget { + min-width: 20%; + width: 25%; +} + + + + + diff --git a/project/static/js/editor.js b/project/static/js/editor.js index e615b790..879762cd 100644 --- a/project/static/js/editor.js +++ b/project/static/js/editor.js @@ -151,10 +151,10 @@ Panel.prototype.connectToolbar = function() action_buttons.each(function() { var button = $(this); var hk = button.attr('ui:hotkey'); + var params = $.evalJSON(button.attr('ui:action-params')); var callback = function() { - editor.callScriptlet(button.attr('ui:action'), - self, eval(button.attr('ui:action-params')) ); + editor.callScriptlet(button.attr('ui:action'), self, params); }; // connect button diff --git a/project/static/js/jquery.hpanel.js b/project/static/js/jquery.hpanel.js index bec82e06..1ad0d17f 100644 --- a/project/static/js/jquery.hpanel.js +++ b/project/static/js/jquery.hpanel.js @@ -11,7 +11,7 @@ $('.panel-overlay', mydata.root).css('display', 'block'); return false; }, - resize_changed: function(event) { + resize_changed: function(event) { var old_width = parseInt(event.data.overlay.css('width')); var delta = event.pageX + event.data.hotspot_x - old_width; event.data.overlay.css({'width': old_width + delta}); diff --git a/project/static/js/jquery.lazyload.js b/project/static/js/jquery.lazyload.js old mode 100644 new mode 100755 diff --git a/project/static/js/jquery.paginate.js b/project/static/js/jquery.paginate.js new file mode 100644 index 00000000..710b1846 --- /dev/null +++ b/project/static/js/jquery.paginate.js @@ -0,0 +1,66 @@ +(function($) { + + var settings = { + items: [], + itemsPerPage: 20, + page: 0 + }; + + $.fn.filterItems = function(condition) + { + settings.items = $('p', this); + + if(condition) settings.items = settings.items.filter(function() { + return condition( $(this).attr('title') ); + }); + + var pageCount = Math.ceil(settings.items.length / settings.itemsPerPage); + var buttons = $('.page-nav-wrap button', this.parent()); + buttons.show().filter(function(i) { return i >= pageCount; }).hide(); + this.switchToPage(); + }; + + $.fn.switchToPage = function(index) + { + index = index || settings.page; + var start = index * settings.itemsPerPage; + var end = start + settings.itemsPerPage; + $('p', this).hide(); + + var visibleItems = settings.items.filter(function(i) { return i >= start && i < end; }); + visibleItems.show(); + } + + $.fn.paginate = function(options) + { + var list = this; + + // apply defaults + if (options) $.extend(settings, options); + settings.items = $('p', list); + + var nav = $(''); + list.before(nav); + var pageCount = Math.floor(settings.items.length / settings.itemsPerPage); + var orphanCount = settings.items.length - (pageCount * settings.itemsPerPage); + var button = null; + + for(var i=0; i < pageCount; i++) + { + button = $(""); + button.bind('click', i, function(event) { list.switchToPage(event.data); }); + nav.append(button); + } + + if(orphanCount > 0) + { + i = pageCount; + button = $(""); + button.bind('click', i, function(event) { list.switchToPage(event.data); }); + nav.append(button); + } + + list.filterItems(function(){return true;}); + list.switchToPage(0); + }; +})(jQuery); diff --git a/project/templates/explorer/file_list.html b/project/templates/explorer/file_list.html index 25136371..a36d353a 100644 --- a/project/templates/explorer/file_list.html +++ b/project/templates/explorer/file_list.html @@ -1,43 +1,58 @@ {% extends "base.html" %} +{% block extrahead %} + + + +{% endblock extrahead %} + {% block maincontent %} +
+ +
+
+

+ + +

+
+
+ {% for file in files %} +

{{ file }}

+ {% endfor %} +
+
{% if perms.explorer.can_add_files %} +

Dodaj nowy utwór

-
{{ bookform.as_p }}

+
{% endif %} -

Wszystkie utwory:

- - - - - {% for file in files.object_list %} - - - - - - {% endfor %} -
Lp.Nazwa utworuWersje
{{forloop.counter0|add:files.start_index}}.{{ file }}  
- - +
{% endblock maincontent %} -- 2.20.1 From d798a69cb177ba4dabd2d917e1da6ab94707aa7d Mon Sep 17 00:00:00 2001 From: =?utf8?q?=C5=81ukasz=20Rekucki?= Date: Sat, 5 Sep 2009 02:06:19 +0200 Subject: [PATCH 06/16] Komunikat, ze zaczal zapisywac. Naprawiony bug z kodowaniem znakow. Przyciski autokorekty ustawiaja dobry stan. Bledy XML przy zapisywaniu sa traktowane jako ostrzezenia. --- apps/explorer/views.py | 30 ++++++++---- project/static/css/master.css | 7 ++- project/static/js/editor.js | 67 ++++++++++++++++---------- project/templates/explorer/editor.html | 2 + 4 files changed, 70 insertions(+), 36 deletions(-) diff --git a/apps/explorer/views.py b/apps/explorer/views.py index d6118acb..82c9d398 100644 --- a/apps/explorer/views.py +++ b/apps/explorer/views.py @@ -98,27 +98,37 @@ def file_upload(request, repo): def file_xml(request, repo, path): if request.method == 'POST': errors = None + warnings = None form = forms.BookForm(request.POST) if form.is_valid(): print 'Saving whole text.', request.user.username - def save_action(): - print 'In branch: ' + repo.repo[None].branch() - repo._add_file(path, form.cleaned_data['content']) - repo._commit(message=(form.cleaned_data['commit_message'] or 'Lokalny zapis platformy.'),\ - user=request.user.username) try: - # wczytaj dokument z ciągu znaków -> weryfikacja - document = parser.WLDocument.from_string(form.cleaned_data['content']) + # encode it back to UTF-8, so we can put it into repo + encoded_data = form.cleaned_data['content'].encode('utf-8') + + def save_action(): + repo._add_file(path, encoded_data) + repo._commit(message=(form.cleaned_data['commit_message'] or 'Lokalny zapis platformy.'),\ + user=request.user.username) + + try: + # wczytaj dokument z ciągu znaków -> weryfikacja + document = parser.WLDocument.from_string(form.cleaned_data['content']) + except (ParseError, ValidationError), e: + warnings = [u'Niepoprawny dokument XML: ' + unicode(e.message)] # save to user's branch repo.in_branch(save_action, models.user_branch(request.user) ); - except (ParseError, ValidationError), e: - errors = [e.message] + except UnicodeDecodeError, e: + errors = [u'Błąd kodowania danych przed zapisem: ' + unicode(e.message)] + except RepositoryException, e: + errors = [u'Błąd repozytorium: ' + unicode(e.message)] if not errors: errors = dict( (field[0], field[1].as_text()) for field in form.errors.iteritems() ) - return HttpResponse(json.dumps({'result': errors and 'error' or 'ok', 'errors': errors})); + return HttpResponse( json.dumps({'result': errors and 'error' or 'ok', + 'errors': errors, 'warnings': warnings}) ); form = forms.BookForm() data = repo.get_file(path, models.user_branch(request.user)) diff --git a/project/static/css/master.css b/project/static/css/master.css index 561ef50a..c321c782 100644 --- a/project/static/css/master.css +++ b/project/static/css/master.css @@ -294,7 +294,7 @@ div.isection p { width: 33%; } -.msg-error, .msg-success, .msg-warning { +.msg-error, .msg-success, .msg-warning, .msg-info { overflow: hidden; padding: 0.1em 0.5em; text-align: center; @@ -325,6 +325,11 @@ div.isection p { border-color: lightgreen; } +.msg-info { + background-color: lightblue; + border-color: lightblue; +} + .msg-warning { background-color: yellow; border-color: yellow; diff --git a/project/static/js/editor.js b/project/static/js/editor.js index 879762cd..13c70978 100644 --- a/project/static/js/editor.js +++ b/project/static/js/editor.js @@ -154,7 +154,7 @@ Panel.prototype.connectToolbar = function() var params = $.evalJSON(button.attr('ui:action-params')); var callback = function() { - editor.callScriptlet(button.attr('ui:action'), self, params); + editor.callScriptlet(button.attr('ui:action'), self, params); }; // connect button @@ -354,12 +354,15 @@ Editor.prototype.saveToBranch = function(msg) 'commit_message': msg }) + self.showPopup('save-waiting', '', -1); + $.ajax({ url: saveInfo.url, dataType: 'json', success: function(data, textStatus) { - if (data.result != 'ok') - self.showPopup('save-error', data.errors[0]); + if (data.result != 'ok') { + self.showPopup('save-error', (data.errors && data.errors[0]) || 'Nieznany błąd X_X.'); + } else { self.refreshPanels(changed_panel); $('#toolbar-button-save').attr('disabled', 'disabled'); @@ -367,11 +370,17 @@ Editor.prototype.saveToBranch = function(msg) if(self.autosaveTimer) clearTimeout(self.autosaveTimer); - self.showPopup('save-successful'); + if (data.warnings == null) + self.showPopup('save-successful'); + else + self.showPopup('save-warn', data.warnings[0]); } + + self.advancePopupQueue(); }, error: function(rq, tstat, err) { - self.showPopup('save-error'); + self.showPopup('save-error', '- bład wewnętrzny serwera.'); + self.advancePopupQueue(); }, type: 'POST', data: postData @@ -435,10 +444,11 @@ Editor.prototype.sendPullRequest = function () { }); */ } -Editor.prototype.showPopup = function(name, text) +Editor.prototype.showPopup = function(name, text, timeout) { + timeout = timeout || 4000; var self = this; - self.popupQueue.push( [name, text] ) + self.popupQueue.push( [name, text, timeout] ) if( self.popupQueue.length > 1) return; @@ -447,26 +457,31 @@ Editor.prototype.showPopup = function(name, text) $('*.data', box).html(text); box.fadeIn(); - self._nextPopup = function() { - var elem = self.popupQueue.pop() - if(elem) { - var box = $('#message-box > #' + elem[0]); + if(timeout > 0) + setTimeout( $.fbind(self, self.advancePopupQueue), timeout); +}; - box.fadeOut(300, function() { - $('*.data', box).html(); - - if( self.popupQueue.length > 0) { - box = $('#message-box > #' + self.popupQueue[0][0]); - $('*.data', box).html(self.popupQueue[0][1]); - box.fadeIn(); - setTimeout(self._nextPopup, 5000); - } - }); - } +Editor.prototype.advancePopupQueue = function() { + var self = this; + var elem = this.popupQueue.shift(); + if(elem) { + var box = $('#message-box > #' + elem[0]); + + box.fadeOut(200, function() + { + $('*.data', box).html(); + + if( self.popupQueue.length > 0) { + var ibox = $('#message-box > #' + self.popupQueue[0][0]); + $('*.data', ibox).html(self.popupQueue[0][1]); + ibox.fadeIn(); + if(self.popupQueue[0][2] > 0) + setTimeout( $.fbind(self, self.advancePopupQueue), self.popupQueue[0][2]); + } + }); } +}; - setTimeout(self._nextPopup, 5000); -} Editor.prototype.registerScriptlet = function(scriptlet_id, scriptlet_func) { @@ -485,7 +500,9 @@ Editor.prototype.callScriptlet = function(scriptlet_id, panel, params) { $(function() { $.fbind = function (self, func) { - return function() { return func.apply(self, arguments); }; + return function() { + return func.apply(self, arguments); + }; }; editor = new Editor(); diff --git a/project/templates/explorer/editor.html b/project/templates/explorer/editor.html index 6dce9047..b3a2e4c6 100644 --- a/project/templates/explorer/editor.html +++ b/project/templates/explorer/editor.html @@ -34,9 +34,11 @@ {% endblock %} {% block message-box %} +

Zapisuję dane na serwerze.

Zapisano :)

Błąd przy zapisie.

Tej funkcji jeszcze nie ma :(

+

Zapisano. Uwagi: (

{% endblock %} {% block maincontent %} -- 2.20.1 From 653c75b6951e028fe4c68e27cc9852e45fa418a6 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=C5=81ukasz=20Rekucki?= Date: Tue, 8 Sep 2009 12:34:39 +0200 Subject: [PATCH 07/16] Merge i commit dzialaja. Mozliwosc uaktualnienia swojej galezi dla danego pliku. Poprawki zeby lepiej dzialalo na Ie --- apps/explorer/forms.py | 7 +- apps/explorer/models.py | 2 - apps/explorer/views.py | 249 +++++++++++++++++++------ fixtures/przyciski.xml | 156 ++++++++++------ lib/hg.py | 168 +++++++++++++---- project/static/css/filelist.css | 2 +- project/static/css/master.css | 32 ---- project/static/js/codemirror/select.js | 4 +- project/static/js/editor.js | 115 +++++++++--- project/static/js/jquery.logging.js | 46 ++--- project/templates/explorer/editor.html | 26 ++- project/urls.py | 3 + 12 files changed, 573 insertions(+), 237 deletions(-) diff --git a/apps/explorer/forms.py b/apps/explorer/forms.py index 0e1ec868..da8a1179 100644 --- a/apps/explorer/forms.py +++ b/apps/explorer/forms.py @@ -55,8 +55,13 @@ class BookForm(forms.Form): content = forms.CharField(widget=forms.Textarea) commit_message = forms.CharField(required=False) +class MergeForm(forms.Form): + message = forms.CharField(error_messages={'required': 'Please write a merge description.'}) + class BookUploadForm(forms.Form): - file = forms.FileField() + file = forms.FileField(label='Source OCR file') + bookname = forms.RegexField(regex='[\w-]+', \ + label='Publication name', help_text='Example: slowacki-beniowski') class ImageFoldersForm(forms.Form): folders = forms.ChoiceField(required=False) diff --git a/apps/explorer/models.py b/apps/explorer/models.py index e47c26fe..5fc31e7e 100644 --- a/apps/explorer/models.py +++ b/apps/explorer/models.py @@ -52,5 +52,3 @@ def get_images_from_folder(folder): in os.listdir(os.path.join(settings.MEDIA_ROOT, settings.IMAGE_DIR, folder)) if not fn.startswith('.')) -def user_branch(user): - return 'personal_'+user.username diff --git a/apps/explorer/views.py b/apps/explorer/views.py index 82c9d398..19cc10b1 100644 --- a/apps/explorer/views.py +++ b/apps/explorer/views.py @@ -16,7 +16,11 @@ from toolbar import models as toolbar_models # # Some useful decorators -# + +def file_branch(path, user=None): + return ('personal_'+user.username + '_' if user is not None else '') \ + + 'file_' + path + def with_repo(view): """Open a repository for this view""" def view_with_repo(request, *args, **kwargs): @@ -32,7 +36,7 @@ def ajax_login_required(view): if request.user.is_authenticated(): return view(request, *args, **kwargs) # not authenticated - return HttpResponse( json.dumps({'result': 'access_denied'}) ); + return HttpResponse( json.dumps({'result': 'access_denied', 'errors': ['Brak dostępu.']}) ); return view_with_auth # @@ -40,7 +44,8 @@ def ajax_login_required(view): # @with_repo def file_list(request, repo): - latest_default = repo.repo.branchtags()['default'] + # + latest_default = repo.get_branch_tip('default') files = list( repo.repo[latest_default] ) bookform = forms.BookUploadForm() @@ -59,34 +64,29 @@ def file_upload(request, repo): # prepare the data f = request.FILES['file'] decoded = f.read().decode('utf-8') - + path = form.cleaned_data['bookname'] + def upload_action(): - print 'Adding file: %s' % f.name - repo._add_file(f.name, decoded.encode('utf-8') ) - repo._commit( - message="File %s uploaded from platform by %s" %\ - (f.name, request.user.username), \ - user=request.user.username \ - ) - - # end of upload + repo._add_file(path ,decoded.encode('utf-8') ) + repo._commit(message="File %s uploaded by user %s" % \ + (path, request.user.username), user=request.user.username) repo.in_branch(upload_action, 'default') # if everything is ok, redirect to the editor return HttpResponseRedirect( reverse('editor_view', - kwargs={'path': f.name}) ) + kwargs={'path': path}) ) except hg.RepositoryException, e: other_errors.append(u'Błąd repozytorium: ' + unicode(e) ) - except UnicodeDecodeError, e: - other_errors.append(u'Niepoprawne kodowanie pliku: ' + e.reason \ - + u'. Żądane kodowanie: ' + e.encoding) + #except UnicodeDecodeError, e: + # other_errors.append(u'Niepoprawne kodowanie pliku: ' + e.reason \ + # + u'. Żądane kodowanie: ' + e.encoding) # invalid form # get form = forms.BookUploadForm() - return direct_to_template(request, 'explorer/file_upload.html', + return direct_to_template(request, 'explorer/file_upload.html',\ extra_context = {'form' : form, 'other_errors': other_errors}) # @@ -118,10 +118,10 @@ def file_xml(request, repo, path): warnings = [u'Niepoprawny dokument XML: ' + unicode(e.message)] # save to user's branch - repo.in_branch(save_action, models.user_branch(request.user) ); + repo.in_branch(save_action, file_branch(path, request.user) ); except UnicodeDecodeError, e: errors = [u'Błąd kodowania danych przed zapisem: ' + unicode(e.message)] - except RepositoryException, e: + except hg.RepositoryException, e: errors = [u'Błąd repozytorium: ' + unicode(e.message)] if not errors: @@ -131,9 +131,154 @@ def file_xml(request, repo, path): 'errors': errors, 'warnings': warnings}) ); form = forms.BookForm() - data = repo.get_file(path, models.user_branch(request.user)) + data = repo.get_file(path, file_branch(path, request.user)) form.fields['content'].initial = data - return HttpResponse( json.dumps({'result': 'ok', 'content': data}) ) + return HttpResponse( json.dumps({'result': 'ok', 'content': data}) ) + +@ajax_login_required +@with_repo +def file_update_local(request, path, repo): + result = None + errors = None + + wlock = repo.write_lock() + try: + tipA = repo.get_branch_tip('default') + tipB = repo.get_branch_tip( file_branch(path, request.user) ) + + nodeA = repo.getnode(tipA) + nodeB = repo.getnode(tipB) + + # do some wild checks - see file_commit() for more info + if (repo.common_ancestor(tipA, tipB) == nodeA) \ + or (nodeB in nodeA.parents()): + result = 'nothing-to-do' + else: + # Case 2+ + repo.merge_revisions(tipB, tipA, \ + request.user.username, 'Personal branch update.') + result = 'done' + except hg.UncleanMerge, e: + errors = [e.message] + result = 'fatal-error' + except hg.RepositoryException, e: + errors = [e.message] + result = 'fatal-error' + finally: + wlock.release() + + if result is None: + raise Exception("Ouch, this shouldn't happen!") + + return HttpResponse( json.dumps({'result': result, 'errors': errors}) ); + +@ajax_login_required +@with_repo +def file_commit(request, path, repo): + result = None + errors = None + local_modified = False + if request.method == 'POST': + form = forms.MergeForm(request.POST) + + if form.is_valid(): + wlock = repo.write_lock() + try: + tipA = repo.get_branch_tip('default') + tipB = repo.get_branch_tip( file_branch(path, request.user) ) + + nodeA = repo.getnode(tipA) + nodeB = repo.getnode(tipB) + + print repr(nodeA), repr(nodeB), repo.common_ancestor(tipA, tipB), repo.common_ancestor(tipB, tipA) + + if repo.common_ancestor(tipB, tipA) == nodeA: + # Case 1: + # * tipB + # | + # * <- can also be here! + # /| + # / | + # tipA * * + # | | + # The local branch has been recently updated, + # so we don't need to update yet again, but we need to + # merge down to default branch, even if there was + # no commit's since last update + repo.merge_revisions(tipA, tipB, \ + request.user.username, form.cleaned_data['message']) + result = 'done' + elif any( p.branch()==nodeB.branch() for p in nodeA.parents()): + # Case 2: + # + # tipA * * tipB + # |\ | + # | \| + # | * + # | | + # Default has no changes, to update from this branch + # since the last merge of local to default. + if nodeB not in nodeA.parents(): + repo.merge_revisions(tipA, tipB, \ + request.user.username, form.cleaned_data['message']) + result = 'done' + else: + result = 'nothing-to-do' + elif repo.common_ancestor(tipA, tipB) == nodeB: + # Case 3: + # tipA * + # | + # * <- this case overlaps with previos one + # |\ + # | \ + # | * tipB + # | | + # + # There was a recent merge to the defaul branch and + # no changes to local branch recently. + # + # Use the fact, that user is prepared to see changes, to + # update his branch if there are any + if nodeB not in nodeA.parents(): + repo.merge_revisions(tipB, tipA, \ + request.user.username, 'Personal branch update during merge.') + local_modified = True + result = 'done' + else: + result = 'nothing-to-do' + else: + # both branches have changes made to them, so + # first do an update + repo.merge_revisions(tipB, tipA, \ + request.user.username, 'Personal branch update during merge.') + + local_modified = True + + # fetch the new tip + tipB = repo.get_branch_tip( file_branch(path, request.user) ) + + # and merge back to the default + repo.merge_revisions(tipA, tipB, \ + request.user.username, form.cleaned_data['message']) + result = 'done' + except hg.UncleanMerge, e: + errors = [e.message] + result = 'fatal-error' + except hg.RepositoryException, e: + errors = [e.message] + result = 'fatal-error' + finally: + wlock.release() + + if result is None: + errors = [ form.errors['message'].as_text() ] + if len(errors) > 0: + result = 'fatal-error' + + return HttpResponse( json.dumps({'result': result, 'errors': errors, 'localmodified': local_modified}) ); + + return HttpResponse( json.dumps({'result': 'fatal-error', 'errors': ['No data posted']}) ) + @ajax_login_required @with_repo @@ -144,23 +289,24 @@ def file_dc(request, path, repo): form = forms.DublinCoreForm(request.POST) if form.is_valid(): + def save_action(): file_contents = repo._get_file(path) # wczytaj dokument z repozytorium document = parser.WLDocument.from_string(file_contents) - document.book_info.update(form.cleaned_data) - - print "SAVING DC" + document.book_info.update(form.cleaned_data) # zapisz - repo._write_file(path, document.serialize()) + repo._write_file(path, document.serialize().encode('utf-8')) repo._commit( \ message=(form.cleaned_data['commit_message'] or 'Lokalny zapis platformy.'), \ user=request.user.username ) try: - repo.in_branch(save_action, models.user_branch(request.user) ) + repo.in_branch(save_action, file_branch(path, request.user) ) + except UnicodeEncodeError, e: + errors = ['Bład wewnętrzny: nie można zakodować pliku do utf-8'] except (ParseError, ValidationError), e: errors = [e.message] @@ -173,7 +319,7 @@ def file_dc(request, path, repo): content = [] try: - fulltext = repo.get_file(path, models.user_branch(request.user)) + fulltext = repo.get_file(path, file_branch(path, request.user)) bookinfo = dcparser.BookInfo.from_string(fulltext) content = bookinfo.to_dict() except (ParseError, ValidationError), e: @@ -186,28 +332,25 @@ def file_dc(request, path, repo): @login_required @with_repo -def display_editor(request, path, repo): - - if not repo.file_exists(path, models.user_branch(request.user)): - try: - data = repo.get_file(path, 'default') - print type(data) - - def new_file(): - repo._add_file(path, data) - repo._commit(message='File import from default branch', - user=request.user.username) - - repo.in_branch(new_file, models.user_branch(request.user) ) - except hg.RepositoryException, e: - return direct_to_template(request, 'explorer/file_unavailble.html',\ - extra_context = { 'path': path, 'error': e }) - - return direct_to_template(request, 'explorer/editor.html', extra_context={ - 'hash': path, - 'panel_list': ['lewy', 'prawy'], - 'scriptlets': toolbar_models.Scriptlet.objects.all() - }) +def display_editor(request, path, repo): + + # this is the only entry point where we create an autobranch for the user + # if it doesn't exists. All other views SHOULD fail. + def ensure_branch_exists(): + parent = repo.get_branch_tip('default') + repo._create_branch(file_branch(path, request.user), parent) + + try: + repo.with_wlock(ensure_branch_exists) + + return direct_to_template(request, 'explorer/editor.html', extra_context={ + 'hash': path, + 'panel_list': ['lewy', 'prawy'], + 'scriptlets': toolbar_models.Scriptlet.objects.all() + }) + except KeyError: + return direct_to_template(request, 'explorer/nofile.html', \ + extra_context = { 'path': path }) # =============== # = Panel views = @@ -216,7 +359,7 @@ def display_editor(request, path, repo): @ajax_login_required @with_repo def xmleditor_panel(request, path, repo): - text = repo.get_file(path, models.user_branch(request.user)) + text = repo.get_file(path, file_branch(path, request.user)) return direct_to_template(request, 'explorer/panels/xmleditor.html', extra_context={ 'fpath': path, @@ -234,7 +377,7 @@ def gallery_panel(request, path): @ajax_login_required @with_repo def htmleditor_panel(request, path, repo): - user_branch = models.user_branch(request.user) + user_branch = file_branch(path, request.user) try: return direct_to_template(request, 'explorer/panels/htmleditor.html', extra_context={ 'fpath': path, @@ -247,7 +390,7 @@ def htmleditor_panel(request, path, repo): @ajax_login_required @with_repo def dceditor_panel(request, path, repo): - user_branch = models.user_branch(request.user) + user_branch = file_branch(path, request.user) try: doc_text = repo.get_file(path, user_branch) diff --git a/fixtures/przyciski.xml b/fixtures/przyciski.xml index 287a0cc9..d67f3ed0 100644 --- a/fixtures/przyciski.xml +++ b/fixtures/przyciski.xml @@ -1,62 +1,98 @@ -Autokorektaautokorekta0Formatowanieformatowanie0Widokdisplay_options2A<sup>+</sup>increase_font_size({change: 2})codemirror_fontsize+Zwiększ rozmiar czcionki.A<sup>-</sup>descrease_font_size({change: -2})codemirror_fontsize-Zmniejsz rozmiar czcionki.A<sup>=</sup>reset_font_size({fontSize: 13})codemirror_fontsize=Przywróć orginalny rozmiar czcionki.Novelpagesnovelpages({exprs: [ - ["\\,\\.\\.|\\.\\,\\.|\\.\\.\\,", "..."], - ["„", ",,"] /* DOUBLE LOW-9 QUOTATION MARK */ -]}) - lineregexpWykonuję operację z novel-pages.Usuń spacjęstrip_whitespace({exprs: [ ["^\\s+|\\s+$", ""], ["\\s+", " "] ]})lineregexpUsuwa zbędne spację z dokumentu.Wersinsert_verse({tag: 'wers'})insert_tagwOtacza zaznaczony tekst tagiem 'wers'.Zamień dywizzamien_dywiz({exprs:[ ["—","---"] ]})lineregexpZamienia '—' na '---'.$.log(editor, panel, params); - -var texteditor = panel.texteditor; -var text = texteditor.selection(); -texteditor.replaceSelection('<' + params.tag + '>' + text + '</' + params.tag + '>'); -if (text.length == 0) -{ - var pos = texteditor.cursorPosition(); - texteditor.selectLines(pos.line, pos.character + params.tag.length + 2); -} - -panel.fireEvent('contentChanged');// params: {exprs: list of {expr: "", repl: "" [, opts: "g"]}} -var cm = panel.texteditor; - -var exprs = $.map(params.exprs, function(expr) { - var opts = "g"; - if(expr.length > 2) - opts = expr[2]; - return {rx: new RegExp(expr[0], opts), repl: expr[1]}; -}); - -var selection = cm.selection(); - -if(selection) -{ - var lines = selection.split('\n'); - lines = $.map(lines, function(line) { - $(exprs).each(function() { - var expr = this; - line = line.replace(expr.rx, expr.repl); - }); - return line; - }); - cm.replaceSelection( lines.join('\n') ); -} -else { - var line = cm.firstLine(); - do { - var content = cm.lineContent(line); - $.log("Swapping line: $" + content + "$"); - - $(exprs).each(function() { var expr = this; - content = content.replace(expr.rx, expr.repl); - }); - cm.setLineContent(line, content); - line = cm.nextLine(line); - } while( !(line === false) ); -}var texteditor = panel.texteditor; -var frameBody = $('body', $(texteditor.frame).contents()); - -if(params.fontSize) { - frameBody.css('font-size', params.fontSize); -} -else { - var old_size = parseInt(frameBody.css('font-size')); - frameBody.css('font-size', old_size + (params.change || 0) ); +Akapity i długie cytatyakapity-i-dlugie-cytaty0Autokorektaautokorekta0Blokibloki0Bloki początkowebloki-poczatkowe0Deklaracjedeklaracje0Dramat wierszowanydramat-wierszowany0Dramat współczesnydramat-wspolczesny0Elementy początkoweelementy-poczatkowe0Masterymastery0Nagłówkinaglowki0Początek dramatupoczatek-dramatu0Poleceniapolecenia0Strukturalnestrukturalne0Style znakowestyle-znakowe0Wersywersy0Widokdisplay_options2A<sup>+</sup>increase_font_size({change: 2})codemirror_fontsize+Zwiększ rozmiar czcionki.A<sup>-</sup>descrease_font_size({change: -2})codemirror_fontsize-Zmniejsz rozmiar czcionki.A<sup>=</sup>reset_font_size({fontSize: 13})codemirror_fontsize=Przywróć orginalny rozmiar czcionki.akapitakapit({tag:"akap"})insert_tagakapit cd.akapit-cd({tag:"akap_cd"})insert_tagakapit dialogowyakapit-dialogowy({tag:"akap_dialog"})insert_tagaktakt({tag:"akt"})insert_tagautorautor({tag:"autor"})insert_tagczęść/księgaczesc({tag:"naglowek_czesc"})insert_tagdedykacjadedykacja({tag:"dedykacja"})insert_tagdedykacjadedykacja({tag:"dedykacja"})insert_tagdidaskaliadidaskalia({tag:"didaskalia"})insert_tagdidaskaliadidaskalia({tag:"didaskalia"})insert_tagdidaskalia wewn.didaskalia-wewn({tag:"didask_tekst"})insert_tagdidaskalia wewn.didaskalia-wewn({tag:"didask_tekst"})insert_tagdramat wiersz.dramat-wiersz({tag:"dramat_wierszowany_l"})insert_tagdramat wiersz./w. łamdramat-wiersz-w-lam({tag:"dramat_wierszowany_lp"})insert_tagdramat współczesnydramat-wspolczesny({tag:"dramat_wspolczesny"})insert_tagdzieło nadrzędnedzielo-nadrzedne({tag:"dzielo_nadrzedne"})insert_tagdługi cyt. poet.dlugi-cyt-poet({tag:"poezja_cyt"})insert_tagdługi cyta. poet.dlugi-cyt-poet({tag:"poezja_cyt"})insert_tagdługi cytatdlugi-cytat({tag:"dlugi_cyt"})insert_tagdługi cytatdlugi-cytatdlugi_cytatinsert_tagekstraekstra({tag:"ekstra"})insert_tagkwestiakwestia({tag:"kwestia"})insert_tagkwestiakwestia({tag:"kwestia"})insert_taglirykaliryka({tag:"liryka_l"})insert_tagliryka/w. łamliryka-w-lam({tag:"liryka_lp"})insert_tagmamtemat.matemat({tag:"mat"})insert_tagmottomotto({tag:"motto"})insert_tagmottomotto({tag:"motto"})insert_tagmotto podpismotto-podpis({tag:"motto_podpis"})insert_tagnagłówek kwestiinaglowek-kwestii({tag:"naglowek_osoba"})insert_tagnotanota({tag:"nota"})insert_tagNovelpagesnovelpages({exprs: [ + + ["\\,\\.\\.|\\.\\,\\.|\\.\\.\\,", "..."], + + ["„", ",,"] /* DOUBLE LOW-9 QUOTATION MARK */ + +]})lineregexpWykonuję operację z novel-pages.opowiadanieopowiadanie({tag:"opowiadanie"})insert_tagosobaosoba({tag:"osoba"})insert_tagosobaosoba({tag:"osoba"})insert_tagpodrozdziałpodrozdzial({tag:"naglowek_podrozdzial"})insert_tagpodtytułpodtytul({tag:"podtytul"})insert_tagpowieśćpowiesc({tag:"powiesc"})insert_tagprzypis autorskiprzypis-autorski({tag:"pa"})insert_tagprzypis edytorskiprzypis-edytorski({tag:"pe"})insert_tagprzypis redaktorskiprzypis-redaktorski({tag:"pr"})insert_tagprzypis tłumaczaprzypis-tlumacza({tag:"pt"})insert_tagrozdziałrozdzial({tag:"naglowek_rozdzial"})insert_tagscenascena({tag:"naglowek_scena"})insert_tagsep. asterykssep-asteryks({tag:"sekcja_asteryks"})insert_tagsep. liniasep-linia({tag:"separator_linia"})insert_tagsep. światłosep-swiatlo({tag:"sekcja_swiatlo"})insert_tagśródtytułsrodtytul({tag:"srodtytul"})insert_tagstrofastrofa({tag"strofa"})insert_tagstrofastrofa({tag:"strofa"})insert_tagsłowo obceslowo-obce({tag:"slowo_obce"})insert_tagtagi głównetagi-glowne({tag:"utwor"})insert_tagtytułtytul({tag:"nazwa_utworu"})insert_tagtytuł dziełatytul-dziela({tag:"tytul_dziela"})insert_tagUsuń spacjęstrip_whitespace({exprs: [ ["^\\s+|\\s+$", ""], ["\\s+", " "] ]})lineregexpUsuwa zbędne spację z dokumentu.uwagauwaga({tag:"uwaga"})insert_tagwers akap.wers-akap({tag:"wers_akap"})insert_tagwers akap.wers-akap({tag:"wers_akap"})insert_tagwers cd.wers-cd({tag:"wers_cd"})insert_tagwers cd.wers-cd({tag:"wers_cd"})insert_tagwers wciętywers-wciety({tag:"wers_wciety"})insert_tagwers wciętywers-wciety({tag:"wers_wciety"})insert_tagwwwwww({tag:"www"})insert_tagwyróżnieniewyroznienie({tag:"wyroznienie"})insert_tagwywiadwywiad({tag:"wywiad"})insert_tagwywiad odpowiedźwywiad-odpowiedz({tag:"wywiad_odp"})insert_tagwywiad pytaniewywiad-pytanie({tag:"wywiad_pyt"})insert_tagZamień dywizzamien_dywiz({exprs:[ ["—","---"] ]})lineregexpZamienia '—' na '---'.zastępnik wersuzastepnik-wersu({tag:"zastepnik_wersu"})insert_tag$.log(editor, panel, params); + + + +var texteditor = panel.texteditor; + +var text = texteditor.selection(); + +texteditor.replaceSelection('<' + params.tag + '>' + text + '</' + params.tag + '>'); + +if (text.length == 0) + +{ + + var pos = texteditor.cursorPosition(); + + texteditor.selectLines(pos.line, pos.character + params.tag.length + 2); + +} + + + +panel.fireEvent('contentChanged');// params: {exprs: list of {expr: "", repl: "" [, opts: "g"]}} +var cm = panel.texteditor; + +var exprs = $.map(params.exprs, function(expr) { + var opts = "g"; + if(expr.length > 2) + opts = expr[2]; + return {rx: new RegExp(expr[0], opts), repl: expr[1]}; +}); + +var selection = cm.selection(); + +if(selection) +{ + var changed = false; + var lines = selection.split('\n'); + var lines = $.map(lines, function(line) { + var old_line = line; + $(exprs).each(function() { + var expr = this; + line = line.replace(expr.rx, expr.repl); + }); + if(old_line != line) changed = true; + return line; + }); + + if(changed) { + cm.replaceSelection( lines.join('\n') ); + panel.fireEvent('contentChanged'); + } +} +else { + var line = cm.firstLine(); + var hasChanges = false; + do { + var content = cm.lineContent(line); + var old_content = content; + $(exprs).each(function() { var expr = this; + content = content.replace(expr.rx, expr.repl); + }); + + if(old_content != content) { + cm.setLineContent(line, content); + hasChanges = true; + } + + line = cm.nextLine(line); + } while( !(line === false) ); + + if(hasChanges) panel.fireEvent('contentChanged'); +}var texteditor = panel.texteditor; + +var frameBody = $('body', $(texteditor.frame).contents()); + + + +if(params.fontSize) { + + frameBody.css('font-size', params.fontSize); + +} + +else { + + var old_size = parseInt(frameBody.css('font-size')); + + frameBody.css('font-size', old_size + (params.change || 0) ); + } diff --git a/lib/hg.py b/lib/hg.py index 07ec9a79..06e9f832 100644 --- a/lib/hg.py +++ b/lib/hg.py @@ -5,9 +5,13 @@ import mercurial.merge, mercurial.error encoding.encoding = 'utf-8' +X = 'g\xc5\xbceg\xc5\xbc\xc3\xb3\xc5\x82ka' -def clearpath(path): - return unicode(path).encode("utf-8") +def sanitize_string(path): + if isinstance(path, unicode): # + return path.encode('utf-8') + else: # it's a string, so we have no idea what encoding it is + return path class Repository(object): """Abstrakcja repozytorium Mercurial. Działa z Mercurial w wersji 1.3.1.""" @@ -17,11 +21,10 @@ class Repository(object): self.ui.config('ui', 'quiet', 'true') self.ui.config('ui', 'interactive', 'false') - self.real_path = os.path.realpath(path) - self.repo = self.open_repository(self.real_path, create) - self._pending_files = [] - - def open_repository(self, path, create=False): + self.real_path = sanitize_string(os.path.realpath(path)) + self.repo = self._open_repository(self.real_path, create) + + def _open_repository(self, path, create=False): if os.path.isdir(path): try: return localrepo.localrepository(self.ui, path) @@ -44,8 +47,7 @@ class Repository(object): return self.in_branch(lambda: self._get_file(path), branch) def _get_file(self, path): - path = clearpath(path) - + path = sanitize_string(path) if not self._file_exists(path): raise RepositoryException("File not availble in this branch.") @@ -55,26 +57,26 @@ class Repository(object): return self.in_branch(lambda: self._file_exists(path), branch) def _file_exists(self, path): - path = clearpath(path) + path = sanitize_string(path) return self.repo.dirstate[path] != "?" def write_file(self, path, value, branch): return self.in_branch(lambda: self._write_file(path, value), branch) def _write_file(self, path, value): - path = clearpath(path) + path = sanitize_string(path) return self.repo.wwrite(path, value, []) def add_file(self, path, value, branch): return self.in_branch(lambda: self._add_file(path, value), branch) def _add_file(self, path, value): - path = clearpath(path) + path = sanitize_string(path) self._write_file(path, value) return self.repo.add( [path] ) def _commit(self, message, user=None): - return self.repo.commit(text=message, user=user) + return self.repo.commit(text=sanitize_string(message), user=sanitize_string(user)) def commit(self, message, branch, user=None): return self.in_branch(lambda: self._commit(message, key=key, user=user), branch) @@ -91,49 +93,143 @@ class Repository(object): finally: wlock.release() - def _switch_to_branch(self, bname, create=True): + def merge_branches(self, bnameA, bnameB, user, message): wlock = self.repo.wlock() try: - current = self.repo[None].branch() - if current == bname: - return current - try: - tip = self.repo.branchtags()[bname] - except KeyError, ke: - if not create: raise ke - - # create the branch on the fly + return self.merge_revisions(self.get_branch_tip(bnameA), + self.get_branch_tip(bnameB), user, message) + finally: + wlock.release() - # first switch to default branch - default_tip = self.repo.branchtags()['default'] - mercurial.merge.update(self.repo, default_tip, False, True, None) + def diff(self, revA, revB): + return UpdateStatus(self.repo.status(revA, revB)) - # set the dirstate to new branch - self.repo.dirstate.setbranch(bname) - self._commit('Initial commit for automatic branch "%s".' % bname, user="django-admin") + def merge_revisions(self, revA, revB, user, message): + wlock = self.repo.wlock() + try: + old = self.repo[None] + + self._checkout(revA) + mergestatus = self._merge(revB) + if not mergestatus.isclean(): + # revert the failed merge + self.repo.recover() + raise UncleanMerge(u'Failed to merge %d files.' % len(mergestatus.unresolved)) + + # commit the clean merge + self._commit(message, user) + + # cleanup after yourself + self._checkout(old.rev()) + except util.Abort, ae: + raise RepositoryException(u'Failed merge: ' + ae.message) + finally: + wlock.release() - # collect the new tip - tip = self.repo.branchtags()[bname] + def common_ancestor(self, revA, revB): + return self.repo[revA].ancestor(self.repo[revB]) + + def _checkout(self, rev, force=True): + return MergeStatus(mercurial.merge.update(self.repo, rev, False, force, None)) + + def _merge(self, rev): + """ Merge the revision into current working directory """ + return MergeStatus(mercurial.merge.update(self.repo, rev, True, False, None)) - upstats = mercurial.merge.update(self.repo, tip, False, True, None) - return current + def _switch_to_branch(self, bname): + bname = sanitize_string(bname) + wlock = self.repo.wlock() + try: + current = self.repo[None].branch() + if current == bname: + return current + + tip = self.get_branch_tip(bname) + status = self._checkout(tip) + + if not status.isclean(): + raise RepositoryException("Unclean branch switch. This IS REALLY bad.") + + return current except KeyError, ke: - raise RepositoryException("Can't switch to branch '%s': no such branch." % bname , ke) + raise RepositoryException((u"Can't switch to branch '%s': no such branch." % bname) , ke) except util.Abort, ae: - raise RepositoryException("Can't switch to branch '%s': %s" % (bname, ae.message), ae) + raise RepositoryException(u"Can't switch to branch '%s': %s" % (bname, ae.message), ae) finally: wlock.release() + def with_wlock(self, action): + wlock = self.repo.wlock() + try: + action() + finally: + wlock.release() + + def _create_branch(self, name, parent_rev, msg=None, before_commit=None): + """WARNING: leaves the working directory in the new branch""" + name = sanitize_string(name) + + if self.has_branch(name): return # just exit + + self._checkout(parent_rev) + self.repo.dirstate.setbranch(name) + + if msg is None: + msg = "Initial commit for branch '%s'." % name + + if before_commit: before_commit() + self._commit(msg, user='platform') + return self.get_branch_tip(name) + def write_lock(self): """Returns w write lock to the repository.""" return self.repo.wlock() + def has_branch(self, name): + name = sanitize_string(name) + return (name in self.repo.branchmap().keys()) + + def get_branch_tip(self, name): + name = sanitize_string(name) + return self.repo.branchtags()[name] -class RepositoryException(Exception): + def getnode(self, rev): + return self.repo[rev] +class MergeStatus(object): + + def __init__(self, mstatus): + self.updated = mstatus[0] + self.merged = mstatus[1] + self.removed = mstatus[2] + self.unresolved = mstatus[3] + + def isclean(self): + return self.unresolved == 0 + +class UpdateStatus(object): + + def __init__(self, mstatus): + self.modified = mstatus[0] + self.added = mstatus[1] + self.removed = mstatus[2] + self.deleted = mstatus[3] + self.untracked = mstatus[4] + self.ignored = mstatus[5] + self.clean = mstatus[6] + + def has_changes(self): + return bool( len(self.modified) + len(self.added) + \ + len(self.removed) + len(self.deleted) ) + +class RepositoryException(Exception): def __init__(self, msg, cause=None): Exception.__init__(self, msg) self.cause = cause +class UncleanMerge(RepositoryException): + pass + class RepositoryDoesNotExist(RepositoryException): pass + diff --git a/project/static/css/filelist.css b/project/static/css/filelist.css index f5b8ce0c..0e4f2a0e 100755 --- a/project/static/css/filelist.css +++ b/project/static/css/filelist.css @@ -24,7 +24,7 @@ .upload-file-widget { min-width: 20%; - width: 25%; + width: 35%; } diff --git a/project/static/css/master.css b/project/static/css/master.css index c321c782..31d811b3 100644 --- a/project/static/css/master.css +++ b/project/static/css/master.css @@ -334,35 +334,3 @@ div.isection p { background-color: yellow; border-color: yellow; } - - -/* - * Object list table - */ - table.object-list { - border-top: 2px solid black; - border-left: 2px solid black; - border-right: 1px solid black; - border-bottom: 1px solid black; - width: 60%; - margin: auto; - } - - - table.object-list td, table.object-list th { - border-bottom: 1px solid black; - border-right: 1px solid black; - padding: 0.2em 0.5em; - } - - table.object-list th { - text-align: center; - background-color: #8080d0; - font-size: 120% - } - - table.object-list td.page-navigation { - position: relative; - text-align: center; - background-color: #CCC; - } diff --git a/project/static/js/codemirror/select.js b/project/static/js/codemirror/select.js index 9ceb24e7..002004e2 100644 --- a/project/static/js/codemirror/select.js +++ b/project/static/js/codemirror/select.js @@ -238,7 +238,7 @@ var select = {}; // Move the start of a range to the start of a node, // compensating for the fact that you can't call // moveToElementText with text nodes. - function moveToNodeStart(range, node) { + function moveToNodeStart(range, node) { if (node.nodeType == 3) { var count = 0, cur = node.previousSibling; while (cur && cur.nodeType == 3) { @@ -253,7 +253,7 @@ var select = {}; else range.moveToElementText(node.parentNode); if (count) range.move("character", count); } - else range.moveToElementText(node); + else try{range.moveToElementText(node);} catch(e) {}; } // Do a binary search through the container object, comparing diff --git a/project/static/js/editor.js b/project/static/js/editor.js index 13c70978..3490b9a1 100644 --- a/project/static/js/editor.js +++ b/project/static/js/editor.js @@ -151,7 +151,14 @@ Panel.prototype.connectToolbar = function() action_buttons.each(function() { var button = $(this); var hk = button.attr('ui:hotkey'); - var params = $.evalJSON(button.attr('ui:action-params')); + + try { + var params = $.evalJSON(button.attr('ui:action-params')); + } catch(object) { + $.log('JSON exception in ', button, ': ', object); + button.attr('disabled', 'disabled'); + return; + } var callback = function() { editor.callScriptlet(button.attr('ui:action'), self, params); @@ -242,8 +249,21 @@ Editor.prototype.setupUI = function() { $('#toolbar-button-save').click( function (event, data) { self.saveToBranch(); } ); + + $('#toolbar-button-update').click( function (event, data) { + if (self.updateUserBranch()) { + // commit/update can be called only after proper, save + // this means all panels are clean, and will get refreshed + // do this only, when there are any changes to local branch + self.refreshPanels(); + } + } ); + $('#toolbar-button-commit').click( function (event, data) { self.sendPullRequest(); + event.preventDefault(); + event.stopPropagation(); + return false; } ); self.rootDiv.bind('stopResize', function() { self.savePanelOptions() @@ -364,9 +384,10 @@ Editor.prototype.saveToBranch = function(msg) self.showPopup('save-error', (data.errors && data.errors[0]) || 'Nieznany błąd X_X.'); } else { - self.refreshPanels(changed_panel); + self.refreshPanels(); $('#toolbar-button-save').attr('disabled', 'disabled'); $('#toolbar-button-commit').removeAttr('disabled'); + $('#toolbar-button-update').removeAttr('disabled'); if(self.autosaveTimer) clearTimeout(self.autosaveTimer); @@ -402,6 +423,7 @@ Editor.prototype.onContentChanged = function(event, data) { $('#toolbar-button-save').removeAttr('disabled'); $('#toolbar-button-commit').attr('disabled', 'disabled'); + $('#toolbar-button-update').attr('disabled', 'disabled'); if(this.autosaveTimer) return; this.autosaveTimer = setTimeout( function() { @@ -409,11 +431,10 @@ Editor.prototype.onContentChanged = function(event, data) { }, 300000 ); }; -Editor.prototype.refreshPanels = function(goodPanel) { +Editor.prototype.refreshPanels = function() { var self = this; - var panels = $('#' + self.rootDiv.attr('id') +' > *.panel-wrap', self.rootDiv.parent()); - panels.each(function() { + self.allPanels().each(function() { var panel = $(this).data('ctrl'); $.log('Refreshing: ', this, panel); if ( panel.changed() ) @@ -424,24 +445,70 @@ Editor.prototype.refreshPanels = function(goodPanel) { }; +Editor.prototype.updateUserBranch = function() { + if( $('.panel-wrap.changed').length != 0) + alert("There are unsaved changes - can't update."); + + var self = this; + $.ajax({ + url: $('#toolbar-button-update').attr('ui:ajax-action'), + dataType: 'json', + success: function(data, textStatus) { + switch(data.result) { + case 'done': + self.showPopup('generic-yes', 'Plik uaktualniony.'); + self.refreshPanels() + break; + case 'nothing-to-do': + self.showPopup('generic-info', 'Brak zmian do uaktualnienia.'); + break; + default: + self.showPopup('generic-error', data.errors && data.errors[0]); + } + }, + error: function(rq, tstat, err) { + self.showPopup('generic-error', 'Błąd serwera: ' + err); + }, + type: 'POST', + data: {} + }); +} + Editor.prototype.sendPullRequest = function () { if( $('.panel-wrap.changed').length != 0) - alert("There are unsaved changes - can't make a pull request."); - - this.showPopup('not-implemented'); -/* - $.ajax({ - url: '/pull-request', - dataType: 'json', - success: function(data, textStatus) { - $.log('data: ' + data); - }, - error: function(rq, tstat, err) { - $.log('commit error', rq, tstat, err); - }, - type: 'POST', - data: {} - }); */ + alert("There are unsaved changes - can't commit."); + + var self = this; + + /* this.showPopup('not-implemented'); */ + + $.log('URL !: ', $('#toolbar-commit-form').attr('action')); + + $.ajax({ + url: $('#toolbar-commit-form').attr('action'), + dataType: 'json', + success: function(data, textStatus) { + switch(data.result) { + case 'done': + self.showPopup('generic-yes', 'Łączenie zmian powiodło się.'); + + if(data.localmodified) + self.refreshPanels() + + break; + case 'nothing-to-do': + self.showPopup('generic-info', 'Brak zmian do połaczenia.'); + break; + default: + self.showPopup('generic-error', data.errors && data.errors[0]); + } + }, + error: function(rq, tstat, err) { + self.showPopup('generic-error', 'Błąd serwera: ' + err); + }, + type: 'POST', + data: {'message': $('#toolbar-commit-message').val() } + }); } Editor.prototype.showPopup = function(name, text, timeout) @@ -454,7 +521,7 @@ Editor.prototype.showPopup = function(name, text, timeout) return; var box = $('#message-box > #' + name); - $('*.data', box).html(text); + $('*.data', box).html(text || ''); box.fadeIn(); if(timeout > 0) @@ -482,6 +549,10 @@ Editor.prototype.advancePopupQueue = function() { } }; +Editor.prototype.allPanels = function() { + return $('#' + this.rootDiv.attr('id') +' > *.panel-wrap', this.rootDiv.parent()); +} + Editor.prototype.registerScriptlet = function(scriptlet_id, scriptlet_func) { diff --git a/project/static/js/jquery.logging.js b/project/static/js/jquery.logging.js index 315d48f5..d6cee14d 100644 --- a/project/static/js/jquery.logging.js +++ b/project/static/js/jquery.logging.js @@ -3,35 +3,39 @@ var LEVEL_INFO = 2; var LEVEL_WARN = 3; var LOG_LEVEL = LEVEL_DEBUG; - - var mozillaLog = function() { - if (window.console) - console.log.apply(this, arguments); - }; - - var safariLog = function() { - if (window.console) - console.log.apply(console, arguments); - }; + + var standardLog = function() { + if (window.console) + console.log.apply(console, arguments); + }; var operaLog = function() { opera.postError(arguments.join(' ')); }; - var defaultLog = function() { return false; }; + var msieLog = function() { + var args = $.makeArray(arguments); + var vals = $.map(args, function(n) { + try { + return JSON.stringify(n); + } catch(e) { + return ('' + n); + } + }); - $.log = function( ) { + if (window.console) + console.log(vals.join(" ")); + }; + + $.log = function() { return $.log.browserLog.apply(this, arguments); }; - if ($.browser.mozilla) - $.log.browserLog = mozillaLog; - else if ($.browser.safari) - $.log.browserLog = safariLog; - else if($.browser.opera) - $.log.browserLog = operaLog; - else - $.log.browserLog = defaultLog; - + if($.browser.opera) + $.log.browserLog = operaLog; + else if($.browser.msie) + $.log.browserLog = msieLog; + else + $.log.browserLog = standardLog; })(jQuery); diff --git a/project/templates/explorer/editor.html b/project/templates/explorer/editor.html index b3a2e4c6..fe9d93ab 100644 --- a/project/templates/explorer/editor.html +++ b/project/templates/explorer/editor.html @@ -29,16 +29,28 @@ {% block breadcrumbs %}Platforma Redakcyjna > plik {{ hash }}{% endblock breadcrumbs %} {% block header-toolbar %} - - + +
+ + +
+ + {% endblock %} {% block message-box %} -

Zapisuję dane na serwerze.

-

Zapisano :)

-

Błąd przy zapisie.

-

Tej funkcji jeszcze nie ma :(

-

Zapisano. Uwagi: (

+

Zapisuję dane na serwerze.

+

Zapisano :)

+

Zapisano. Uwagi: (

+

Błąd przy zapisie.

+ +

+

+

+ +

Tej funkcji jeszcze nie ma :(

+ {% endblock %} {% block maincontent %} diff --git a/project/urls.py b/project/urls.py index 972c33dd..cf082478 100644 --- a/project/urls.py +++ b/project/urls.py @@ -12,6 +12,8 @@ urlpatterns = patterns('', url(r'^file/text/'+PATH_END, 'explorer.views.file_xml', name='file_xml'), url(r'^file/dc/'+PATH_END, 'explorer.views.file_dc', name='file_dc'), url(r'^file/upload', 'explorer.views.file_upload', name='file_upload'), + url(r'^file/commit/'+PATH_END, 'explorer.views.file_commit', name='file_commit'), + url(r'^file/update/'+PATH_END, 'explorer.views.file_update_local', name='file_update'), url(r'^images/(?P[^/]+)/$', 'explorer.views.folder_images', name='folder_image'), url(r'^images/$', 'explorer.views.folder_images', {'folder': '.'}, name='folder_image_ajax'), @@ -23,6 +25,7 @@ urlpatterns = patterns('', url(r'^editor/panel/dceditor/'+PATH_END, 'explorer.views.dceditor_panel', name='dceditor_panel'), url(r'^editor/'+PATH_END, 'explorer.views.display_editor', name='editor_view'), + # Task managment url(r'^manager/pull-requests$', 'explorer.views.pull_requests'), -- 2.20.1 From cb08157935c371b4924ef921afa3c736731ee49d Mon Sep 17 00:00:00 2001 From: =?utf8?q?=C5=81ukasz=20Rekucki?= Date: Tue, 8 Sep 2009 12:42:44 +0200 Subject: [PATCH 08/16] Don't display files starting with a dot. --- apps/explorer/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/explorer/views.py b/apps/explorer/views.py index 19cc10b1..18f79b3e 100644 --- a/apps/explorer/views.py +++ b/apps/explorer/views.py @@ -46,7 +46,7 @@ def ajax_login_required(view): def file_list(request, repo): # latest_default = repo.get_branch_tip('default') - files = list( repo.repo[latest_default] ) + files = [ f for f in repo.repo[latest_default] if not f.startswith('.')] bookform = forms.BookUploadForm() return direct_to_template(request, 'explorer/file_list.html', extra_context={ -- 2.20.1 From 52666d1a087e978f58b9867558bf3fcbfdf04eee Mon Sep 17 00:00:00 2001 From: =?utf8?q?=C5=81ukasz=20Rekucki?= Date: Tue, 8 Sep 2009 13:08:18 +0200 Subject: [PATCH 09/16] Patch to handle unicode image names. --- apps/explorer/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/explorer/models.py b/apps/explorer/models.py index 5fc31e7e..f292283f 100644 --- a/apps/explorer/models.py +++ b/apps/explorer/models.py @@ -48,7 +48,7 @@ def get_image_folders(): def get_images_from_folder(folder): - return sorted(settings.MEDIA_URL + settings.IMAGE_DIR + '/' + folder + '/' + fn for fn + return sorted(settings.MEDIA_URL + settings.IMAGE_DIR + u'/' + folder + u'/' + fn.decode('utf-8') for fn in os.listdir(os.path.join(settings.MEDIA_ROOT, settings.IMAGE_DIR, folder)) - if not fn.startswith('.')) + if not fn.decode('utf-8').startswith('.')) -- 2.20.1 From 3a100c86bdaa0dbdd25796286ef3b6d4888911d8 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=C5=81ukasz=20Rekucki?= Date: Tue, 8 Sep 2009 18:24:03 +0200 Subject: [PATCH 10/16] Komenda do poprawiania przyciskow. --- apps/explorer/admin.py | 8 ----- apps/toolbar/admin.py | 24 +++++++++++-- apps/toolbar/management/__init__.py | 4 +++ apps/toolbar/management/commands/__init__.py | 4 +++ .../toolbar/management/commands/fixbuttons.py | 35 +++++++++++++++++++ project/admin.py | 4 +++ 6 files changed, 68 insertions(+), 11 deletions(-) delete mode 100644 apps/explorer/admin.py create mode 100755 apps/toolbar/management/__init__.py create mode 100755 apps/toolbar/management/commands/__init__.py create mode 100755 apps/toolbar/management/commands/fixbuttons.py create mode 100644 project/admin.py diff --git a/apps/explorer/admin.py b/apps/explorer/admin.py deleted file mode 100644 index a03f3936..00000000 --- a/apps/explorer/admin.py +++ /dev/null @@ -1,8 +0,0 @@ -from django.contrib import admin -from django.utils.translation import ugettext_lazy as _ - -from explorer import models - -admin.site.register(models.Book) -admin.site.register(models.PullRequest) - diff --git a/apps/toolbar/admin.py b/apps/toolbar/admin.py index 052538ea..58b5f746 100644 --- a/apps/toolbar/admin.py +++ b/apps/toolbar/admin.py @@ -1,5 +1,7 @@ from django.contrib import admin from django.utils.translation import ugettext_lazy as _ +from django import forms +from django.utils import simplejson as json from toolbar import models @@ -8,7 +10,26 @@ from toolbar import models # search_fields = ('name', 'slug',) # prepopulated_fields = {'slug': ('name',)} # list_editable = ('position',) + + +class ButtonAdminForm(forms.ModelForm): + model = models.Button + + def clean_params(self): + value = self.cleaned_data['params'] + try: + return json.dumps(json.loads(value)) + except Exception, e: + raise forms.ValidationError(e) + +class ButtonAdmin(admin.ModelAdmin): + form = ButtonAdminForm + list_display = ('label', 'scriptlet', 'key', 'params') + prepopulated_fields = {'slug': ('label',)} + +admin.site.register(models.Button, ButtonAdmin) admin.site.register(models.ButtonGroup) +admin.site.register(models.Scriptlet) #class ButtonAdmin(admin.ModelAdmin): # list_display = ('label', 'action', 'key', 'position',) @@ -17,6 +38,3 @@ admin.site.register(models.ButtonGroup) # filter_horizontal = ('group',) # list_editable = ('position',) -admin.site.register(models.Button) -admin.site.register(models.Scriptlet) - diff --git a/apps/toolbar/management/__init__.py b/apps/toolbar/management/__init__.py new file mode 100755 index 00000000..5ff26b2a --- /dev/null +++ b/apps/toolbar/management/__init__.py @@ -0,0 +1,4 @@ +# To change this template, choose Tools | Templates +# and open the template in the editor. + + diff --git a/apps/toolbar/management/commands/__init__.py b/apps/toolbar/management/commands/__init__.py new file mode 100755 index 00000000..5ff26b2a --- /dev/null +++ b/apps/toolbar/management/commands/__init__.py @@ -0,0 +1,4 @@ +# To change this template, choose Tools | Templates +# and open the template in the editor. + + diff --git a/apps/toolbar/management/commands/fixbuttons.py b/apps/toolbar/management/commands/fixbuttons.py new file mode 100755 index 00000000..9e721510 --- /dev/null +++ b/apps/toolbar/management/commands/fixbuttons.py @@ -0,0 +1,35 @@ +# -*- conding: utf-8 +__author__="lreqc" +__date__ ="$2009-09-08 14:31:26$" +from django.core.management.base import NoArgsCommand +from toolbar.models import Button +import json +import re + +class Command(NoArgsCommand): + + def handle_noargs(self, **options): + buttons = Button.objects.all() + for b in buttons: + params = b.params; + try: + v = json.loads(b.params) + + except ValueError, e: + print 'On button %s: ' % b.label, b.params + print e + # try to fix the bad json + + # cut the parenthis + if params[0] == u'(': + params = params[1:] + if params[-1] == u')': + params = params[:-1] + + v = json.loads(re.sub(u'([\\w-]+)\\s*:', u'"\\1": ', params).encode('utf-8')) + b.params = json.dumps(v) + b.save() + + + + \ No newline at end of file diff --git a/project/admin.py b/project/admin.py new file mode 100644 index 00000000..7bf80973 --- /dev/null +++ b/project/admin.py @@ -0,0 +1,4 @@ +from django.contrib import admin +from django.utils.translation import ugettext_lazy as _ + +import toolbar.admin \ No newline at end of file -- 2.20.1 From ba0c44546e27c41f13a0e5d7658ff018e61b22e0 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=C5=81ukasz=20Rekucki?= Date: Tue, 8 Sep 2009 18:26:09 +0200 Subject: [PATCH 11/16] Use internal JSON. --- apps/toolbar/management/commands/fixbuttons.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/toolbar/management/commands/fixbuttons.py b/apps/toolbar/management/commands/fixbuttons.py index 9e721510..2f15525b 100755 --- a/apps/toolbar/management/commands/fixbuttons.py +++ b/apps/toolbar/management/commands/fixbuttons.py @@ -3,7 +3,7 @@ __author__="lreqc" __date__ ="$2009-09-08 14:31:26$" from django.core.management.base import NoArgsCommand from toolbar.models import Button -import json +from django.utils import simplejson as json import re class Command(NoArgsCommand): @@ -32,4 +32,4 @@ class Command(NoArgsCommand): - \ No newline at end of file + -- 2.20.1 From 308aa7c7d75b50a4b36a70681b5e012dbd023c11 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=C5=81ukasz=20Rekucki?= Date: Tue, 8 Sep 2009 18:47:33 +0200 Subject: [PATCH 12/16] Kilka poprawek w CSS. poprawione przyciski. --- apps/toolbar/models.py | 5 +- dump_toolbar.sh | 3 +- fixtures/przyciski.xml | 1078 +++++++++++++++++++++++++++++--- project/static/css/master.css | 86 +-- project/static/css/toolbar.css | 1 + 5 files changed, 1028 insertions(+), 145 deletions(-) diff --git a/apps/toolbar/models.py b/apps/toolbar/models.py index 614cfcb0..ae101e07 100644 --- a/apps/toolbar/models.py +++ b/apps/toolbar/models.py @@ -16,7 +16,7 @@ class ButtonGroup(models.Model): class Button(models.Model): label = models.CharField(max_length=32) - slug = models.SlugField() #unused + slug = models.SlugField(unique=True) #unused # behaviour params = models.TextField() # TODO: should be a JSON field @@ -27,8 +27,7 @@ class Button(models.Model): tooltip = models.CharField(blank=True, max_length=120) # Why the button is restricted to have the same position in each group ? - # position = models.IntegerField(default=0) - + # position = models.IntegerField(default=0) group = models.ManyToManyField(ButtonGroup) class Meta: diff --git a/dump_toolbar.sh b/dump_toolbar.sh index 3bac9fe6..796c8c53 100755 --- a/dump_toolbar.sh +++ b/dump_toolbar.sh @@ -1 +1,2 @@ -./project/manage.py dumpdata --format=xml toolbar > fixtures/przyciski.xml +./project/manage.py dumpdata --format=xml toolbar | xmllint --format > +fixtures/przyciski.xml.new diff --git a/fixtures/przyciski.xml b/fixtures/przyciski.xml index d67f3ed0..1794c6d7 100644 --- a/fixtures/przyciski.xml +++ b/fixtures/przyciski.xml @@ -1,98 +1,980 @@ - -Akapity i długie cytatyakapity-i-dlugie-cytaty0Autokorektaautokorekta0Blokibloki0Bloki początkowebloki-poczatkowe0Deklaracjedeklaracje0Dramat wierszowanydramat-wierszowany0Dramat współczesnydramat-wspolczesny0Elementy początkoweelementy-poczatkowe0Masterymastery0Nagłówkinaglowki0Początek dramatupoczatek-dramatu0Poleceniapolecenia0Strukturalnestrukturalne0Style znakowestyle-znakowe0Wersywersy0Widokdisplay_options2A<sup>+</sup>increase_font_size({change: 2})codemirror_fontsize+Zwiększ rozmiar czcionki.A<sup>-</sup>descrease_font_size({change: -2})codemirror_fontsize-Zmniejsz rozmiar czcionki.A<sup>=</sup>reset_font_size({fontSize: 13})codemirror_fontsize=Przywróć orginalny rozmiar czcionki.akapitakapit({tag:"akap"})insert_tagakapit cd.akapit-cd({tag:"akap_cd"})insert_tagakapit dialogowyakapit-dialogowy({tag:"akap_dialog"})insert_tagaktakt({tag:"akt"})insert_tagautorautor({tag:"autor"})insert_tagczęść/księgaczesc({tag:"naglowek_czesc"})insert_tagdedykacjadedykacja({tag:"dedykacja"})insert_tagdedykacjadedykacja({tag:"dedykacja"})insert_tagdidaskaliadidaskalia({tag:"didaskalia"})insert_tagdidaskaliadidaskalia({tag:"didaskalia"})insert_tagdidaskalia wewn.didaskalia-wewn({tag:"didask_tekst"})insert_tagdidaskalia wewn.didaskalia-wewn({tag:"didask_tekst"})insert_tagdramat wiersz.dramat-wiersz({tag:"dramat_wierszowany_l"})insert_tagdramat wiersz./w. łamdramat-wiersz-w-lam({tag:"dramat_wierszowany_lp"})insert_tagdramat współczesnydramat-wspolczesny({tag:"dramat_wspolczesny"})insert_tagdzieło nadrzędnedzielo-nadrzedne({tag:"dzielo_nadrzedne"})insert_tagdługi cyt. poet.dlugi-cyt-poet({tag:"poezja_cyt"})insert_tagdługi cyta. poet.dlugi-cyt-poet({tag:"poezja_cyt"})insert_tagdługi cytatdlugi-cytat({tag:"dlugi_cyt"})insert_tagdługi cytatdlugi-cytatdlugi_cytatinsert_tagekstraekstra({tag:"ekstra"})insert_tagkwestiakwestia({tag:"kwestia"})insert_tagkwestiakwestia({tag:"kwestia"})insert_taglirykaliryka({tag:"liryka_l"})insert_tagliryka/w. łamliryka-w-lam({tag:"liryka_lp"})insert_tagmamtemat.matemat({tag:"mat"})insert_tagmottomotto({tag:"motto"})insert_tagmottomotto({tag:"motto"})insert_tagmotto podpismotto-podpis({tag:"motto_podpis"})insert_tagnagłówek kwestiinaglowek-kwestii({tag:"naglowek_osoba"})insert_tagnotanota({tag:"nota"})insert_tagNovelpagesnovelpages({exprs: [ - - ["\\,\\.\\.|\\.\\,\\.|\\.\\.\\,", "..."], - - ["„", ",,"] /* DOUBLE LOW-9 QUOTATION MARK */ - -]})lineregexpWykonuję operację z novel-pages.opowiadanieopowiadanie({tag:"opowiadanie"})insert_tagosobaosoba({tag:"osoba"})insert_tagosobaosoba({tag:"osoba"})insert_tagpodrozdziałpodrozdzial({tag:"naglowek_podrozdzial"})insert_tagpodtytułpodtytul({tag:"podtytul"})insert_tagpowieśćpowiesc({tag:"powiesc"})insert_tagprzypis autorskiprzypis-autorski({tag:"pa"})insert_tagprzypis edytorskiprzypis-edytorski({tag:"pe"})insert_tagprzypis redaktorskiprzypis-redaktorski({tag:"pr"})insert_tagprzypis tłumaczaprzypis-tlumacza({tag:"pt"})insert_tagrozdziałrozdzial({tag:"naglowek_rozdzial"})insert_tagscenascena({tag:"naglowek_scena"})insert_tagsep. asterykssep-asteryks({tag:"sekcja_asteryks"})insert_tagsep. liniasep-linia({tag:"separator_linia"})insert_tagsep. światłosep-swiatlo({tag:"sekcja_swiatlo"})insert_tagśródtytułsrodtytul({tag:"srodtytul"})insert_tagstrofastrofa({tag"strofa"})insert_tagstrofastrofa({tag:"strofa"})insert_tagsłowo obceslowo-obce({tag:"slowo_obce"})insert_tagtagi głównetagi-glowne({tag:"utwor"})insert_tagtytułtytul({tag:"nazwa_utworu"})insert_tagtytuł dziełatytul-dziela({tag:"tytul_dziela"})insert_tagUsuń spacjęstrip_whitespace({exprs: [ ["^\\s+|\\s+$", ""], ["\\s+", " "] ]})lineregexpUsuwa zbędne spację z dokumentu.uwagauwaga({tag:"uwaga"})insert_tagwers akap.wers-akap({tag:"wers_akap"})insert_tagwers akap.wers-akap({tag:"wers_akap"})insert_tagwers cd.wers-cd({tag:"wers_cd"})insert_tagwers cd.wers-cd({tag:"wers_cd"})insert_tagwers wciętywers-wciety({tag:"wers_wciety"})insert_tagwers wciętywers-wciety({tag:"wers_wciety"})insert_tagwwwwww({tag:"www"})insert_tagwyróżnieniewyroznienie({tag:"wyroznienie"})insert_tagwywiadwywiad({tag:"wywiad"})insert_tagwywiad odpowiedźwywiad-odpowiedz({tag:"wywiad_odp"})insert_tagwywiad pytaniewywiad-pytanie({tag:"wywiad_pyt"})insert_tagZamień dywizzamien_dywiz({exprs:[ ["—","---"] ]})lineregexpZamienia '—' na '---'.zastępnik wersuzastepnik-wersu({tag:"zastepnik_wersu"})insert_tag$.log(editor, panel, params); - - - -var texteditor = panel.texteditor; - -var text = texteditor.selection(); - -texteditor.replaceSelection('<' + params.tag + '>' + text + '</' + params.tag + '>'); - -if (text.length == 0) - -{ - - var pos = texteditor.cursorPosition(); - - texteditor.selectLines(pos.line, pos.character + params.tag.length + 2); - -} - - - -panel.fireEvent('contentChanged');// params: {exprs: list of {expr: "", repl: "" [, opts: "g"]}} -var cm = panel.texteditor; - -var exprs = $.map(params.exprs, function(expr) { - var opts = "g"; - if(expr.length > 2) - opts = expr[2]; - return {rx: new RegExp(expr[0], opts), repl: expr[1]}; -}); - -var selection = cm.selection(); - -if(selection) -{ - var changed = false; - var lines = selection.split('\n'); - var lines = $.map(lines, function(line) { - var old_line = line; - $(exprs).each(function() { - var expr = this; - line = line.replace(expr.rx, expr.repl); - }); - if(old_line != line) changed = true; - return line; - }); - - if(changed) { - cm.replaceSelection( lines.join('\n') ); - panel.fireEvent('contentChanged'); - } -} -else { - var line = cm.firstLine(); - var hasChanges = false; - do { - var content = cm.lineContent(line); - var old_content = content; - $(exprs).each(function() { var expr = this; - content = content.replace(expr.rx, expr.repl); - }); - - if(old_content != content) { - cm.setLineContent(line, content); - hasChanges = true; - } - - line = cm.nextLine(line); - } while( !(line === false) ); - - if(hasChanges) panel.fireEvent('contentChanged'); -}var texteditor = panel.texteditor; - -var frameBody = $('body', $(texteditor.frame).contents()); - - - -if(params.fontSize) { - - frameBody.css('font-size', params.fontSize); - -} - -else { - - var old_size = parseInt(frameBody.css('font-size')); - - frameBody.css('font-size', old_size + (params.change || 0) ); - -} + + + + Akapity i długie cytaty + akapity-i-dlugie-cytaty + 0 + + + Autokorekta + autokorekta + 0 + + + Bloki + bloki + 0 + + + Bloki początkowe + bloki-poczatkowe + 0 + + + Deklaracje + deklaracje + 0 + + + Dramat wierszowany + dramat-wierszowany + 0 + + + Dramat współczesny + dramat-wspolczesny + 0 + + + Elementy początkowe + elementy-poczatkowe + 0 + + + Mastery + mastery + 0 + + + Nagłówki + naglowki + 0 + + + Początek dramatu + poczatek-dramatu + 0 + + + Polecenia + polecenia + 0 + + + Strukturalne + strukturalne + 0 + + + Style znakowe + style-znakowe + 0 + + + Wersy + wersy + 0 + + + Widok + display_options + 2 + + + A<sup>+</sup> + increase_font_size + ({change: 2}) + codemirror_fontsize + + + Zwiększ rozmiar czcionki. + + + + + + A<sup>-</sup> + descrease_font_size + ({change: -2}) + codemirror_fontsize + - + Zmniejsz rozmiar czcionki. + + + + + + A<sup>=</sup> + reset_font_size + ({fontSize: 13}) + codemirror_fontsize + = + Przywróć orginalny rozmiar czcionki. + + + + + + akapit + akapit + ({tag:"akap"}) + insert_tag + + + + + + + + akapit cd. + akapit-cd + ({tag:"akap_cd"}) + insert_tag + + + + + + + + akapit dialogowy + akapit-dialogowy + ({tag:"akap_dialog"}) + insert_tag + + + + + + + + akt + akt + ({tag:"akt"}) + insert_tag + + + + + + + + autor + autor + ({tag:"autor"}) + insert_tag + + + + + + + + część/księga + czesc + ({tag:"naglowek_czesc"}) + insert_tag + + + + + + + + dedykacja + dedykacja + ({tag:"dedykacja"}) + insert_tag + + + + + + + + dedykacja + dedykacja + ({tag:"dedykacja"}) + insert_tag + + + + + + + + didaskalia + didaskalia + ({tag:"didaskalia"}) + insert_tag + + + + + + + + didaskalia + didaskalia + ({tag:"didaskalia"}) + insert_tag + + + + + + + + didaskalia wewn. + didaskalia-wewn + ({tag:"didask_tekst"}) + insert_tag + + + + + + + + didaskalia wewn. + didaskalia-wewn + ({tag:"didask_tekst"}) + insert_tag + + + + + + + + dramat wiersz. + dramat-wiersz + ({tag:"dramat_wierszowany_l"}) + insert_tag + + + + + + + + dramat wiersz./w. łam + dramat-wiersz-w-lam + ({tag:"dramat_wierszowany_lp"}) + insert_tag + + + + + + + + dramat współczesny + dramat-wspolczesny + ({tag:"dramat_wspolczesny"}) + insert_tag + + + + + + + + dzieło nadrzędne + dzielo-nadrzedne + ({tag:"dzielo_nadrzedne"}) + insert_tag + + + + + + + + długi cyt. poet. + dlugi-cyt-poet + ({tag:"poezja_cyt"}) + insert_tag + + + + + + + + długi cyta. poet. + dlugi-cyt-poet + ({tag:"poezja_cyt"}) + insert_tag + + + + + + + + długi cytat + dlugi-cytat + ({tag:"dlugi_cyt"}) + insert_tag + + + + + + + + długi cytat + dlugi-cytat + dlugi_cytat + insert_tag + + + + + + + + ekstra + ekstra + ({tag:"ekstra"}) + insert_tag + + + + + + + + kwestia + kwestia + ({tag:"kwestia"}) + insert_tag + + + + + + + + kwestia + kwestia + ({tag:"kwestia"}) + insert_tag + + + + + + + + liryka + liryka + ({tag:"liryka_l"}) + insert_tag + + + + + + + + liryka/w. łam + liryka-w-lam + ({tag:"liryka_lp"}) + insert_tag + + + + + + + + mamtemat. + matemat + ({tag:"mat"}) + insert_tag + + + + + + + + motto + motto + ({tag:"motto"}) + insert_tag + + + + + + + + motto + motto + ({tag:"motto"}) + insert_tag + + + + + + + + motto podpis + motto-podpis + ({tag:"motto_podpis"}) + insert_tag + + + + + + + + nagłówek kwestii + naglowek-kwestii + ({tag:"naglowek_osoba"}) + insert_tag + + + + + + + + nota + nota + ({tag:"nota"}) + insert_tag + + + + + + + + Novelpages + novelpages + ({exprs: [ + + ["\\,\\.\\.|\\.\\,\\.|\\.\\.\\,", "..."], + + ["„", ",,"] /* DOUBLE LOW-9 QUOTATION MARK */ + +]}) + lineregexp + + Wykonuję operację z novel-pages. + + + + + + opowiadanie + opowiadanie + ({tag:"opowiadanie"}) + insert_tag + + + + + + + + osoba + osoba + ({tag:"osoba"}) + insert_tag + + + + + + + + osoba + osoba + ({tag:"osoba"}) + insert_tag + + + + + + + + podrozdział + podrozdzial + ({tag:"naglowek_podrozdzial"}) + insert_tag + + + + + + + + podtytuł + podtytul + ({tag:"podtytul"}) + insert_tag + + + + + + + + powieść + powiesc + ({tag:"powiesc"}) + insert_tag + + + + + + + + przypis autorski + przypis-autorski + ({tag:"pa"}) + insert_tag + + + + + + + + przypis edytorski + przypis-edytorski + ({tag:"pe"}) + insert_tag + + + + + + + + przypis redaktorski + przypis-redaktorski + ({tag:"pr"}) + insert_tag + + + + + + + + przypis tłumacza + przypis-tlumacza + ({tag:"pt"}) + insert_tag + + + + + + + + rozdział + rozdzial + ({tag:"naglowek_rozdzial"}) + insert_tag + + + + + + + + scena + scena + ({tag:"naglowek_scena"}) + insert_tag + + + + + + + + sep. asteryks + sep-asteryks + ({tag:"sekcja_asteryks"}) + insert_tag + + + + + + + + sep. linia + sep-linia + ({tag:"separator_linia"}) + insert_tag + + + + + + + + sep. światło + sep-swiatlo + ({tag:"sekcja_swiatlo"}) + insert_tag + + + + + + + + śródtytuł + srodtytul + ({tag:"srodtytul"}) + insert_tag + + + + + + + + strofa + strofa + ({tag"strofa"}) + insert_tag + + + + + + + + strofa + strofa + ({tag:"strofa"}) + insert_tag + + + + + + + + słowo obce + slowo-obce + ({tag:"slowo_obce"}) + insert_tag + + + + + + + + tagi główne + tagi-glowne + ({tag:"utwor"}) + insert_tag + + + + + + + + tytuł + tytul + ({tag:"nazwa_utworu"}) + insert_tag + + + + + + + + tytuł dzieła + tytul-dziela + ({tag:"tytul_dziela"}) + insert_tag + + + + + + + + Usuń spację + strip_whitespace + ({exprs: [ ["^\\s+|\\s+$", ""], ["\\s+", " "] ]}) + lineregexp + + Usuwa zbędne spację z dokumentu. + + + + + + uwaga + uwaga + ({tag:"uwaga"}) + insert_tag + + + + + + + + wers akap. + wers-akap + ({tag:"wers_akap"}) + insert_tag + + + + + + + + wers akap. + wers-akap + ({tag:"wers_akap"}) + insert_tag + + + + + + + + wers cd. + wers-cd + ({tag:"wers_cd"}) + insert_tag + + + + + + + + wers cd. + wers-cd + ({tag:"wers_cd"}) + insert_tag + + + + + + + + wers wcięty + wers-wciety + ({tag:"wers_wciety"}) + insert_tag + + + + + + + + wers wcięty + wers-wciety + ({tag:"wers_wciety"}) + insert_tag + + + + + + + + www + www + ({tag:"www"}) + insert_tag + + + + + + + + wyróżnienie + wyroznienie + ({tag:"wyroznienie"}) + insert_tag + + + + + + + + wywiad + wywiad + ({tag:"wywiad"}) + insert_tag + + + + + + + + wywiad odpowiedź + wywiad-odpowiedz + ({tag:"wywiad_odp"}) + insert_tag + + + + + + + + wywiad pytanie + wywiad-pytanie + ({tag:"wywiad_pyt"}) + insert_tag + + + + + + + + Zamień dywiz + zamien_dywiz + ({exprs:[ ["—","---"] ]}) + lineregexp + + Zamienia '—' na '---'. + + + + + + zastępnik wersu + zastepnik-wersu + ({tag:"zastepnik_wersu"}) + insert_tag + + + + + + + + $.log(editor, panel, params); + + + +var texteditor = panel.texteditor; + +var text = texteditor.selection(); + +texteditor.replaceSelection('<' + params.tag + '>' + text + '</' + params.tag + '>'); + +if (text.length == 0) + +{ + + var pos = texteditor.cursorPosition(); + + texteditor.selectLines(pos.line, pos.character + params.tag.length + 2); + +} + + + +panel.fireEvent('contentChanged'); + + + // params: {exprs: list of {expr: "", repl: "" [, opts: "g"]}} +var cm = panel.texteditor; + +var exprs = $.map(params.exprs, function(expr) { + var opts = "g"; + if(expr.length > 2) + opts = expr[2]; + return {rx: new RegExp(expr[0], opts), repl: expr[1]}; +}); + +var selection = cm.selection(); + +if(selection) +{ + var changed = false; + var lines = selection.split('\n'); + var lines = $.map(lines, function(line) { + var old_line = line; + $(exprs).each(function() { + var expr = this; + line = line.replace(expr.rx, expr.repl); + }); + if(old_line != line) changed = true; + return line; + }); + + if(changed) { + cm.replaceSelection( lines.join('\n') ); + panel.fireEvent('contentChanged'); + } +} +else { + var line = cm.firstLine(); + var hasChanges = false; + do { + var content = cm.lineContent(line); + var old_content = content; + $(exprs).each(function() { var expr = this; + content = content.replace(expr.rx, expr.repl); + }); + + if(old_content != content) { + cm.setLineContent(line, content); + hasChanges = true; + } + + line = cm.nextLine(line); + } while( !(line === false) ); + + if(hasChanges) panel.fireEvent('contentChanged'); +} + + + var texteditor = panel.texteditor; + +var frameBody = $('body', $(texteditor.frame).contents()); + + + +if(params.fontSize) { + + frameBody.css('font-size', params.fontSize); + +} + +else { + + var old_size = parseInt(frameBody.css('font-size')); + + frameBody.css('font-size', old_size + (params.change || 0) ); + +} + + diff --git a/project/static/css/master.css b/project/static/css/master.css index 31d811b3..2eaf801e 100644 --- a/project/static/css/master.css +++ b/project/static/css/master.css @@ -9,10 +9,10 @@ body { position: absolute; padding: 0.2em 0.5em; background-color: #CDCDCD; - border-bottom: 0.1px solid black; - height: 1.8em; - line-height: 1.8em; - vertical-align: center; + border-bottom: 0.1px solid black; + height: 1.8em; + line-height: 1.8em; + vertical-align: middle; top: 0px; left: 0px; right: 0px; z-index: 300; @@ -22,12 +22,12 @@ body { } #header-right-toolbar { - position: absolute; - right: 1em; + position: absolute; + right: 1em; } #header button { - vertical-align: center; + vertical-align: middle; } #content { @@ -107,53 +107,53 @@ label { /* ========== */ #panels { - position: absolute; - bottom: 0px; left: 0px; right: 0px; top: 0px; + position: absolute; + bottom: 0px; left: 0px; right: 0px; top: 0px; } .panel-wrap { overflow: hidden; - position: absolute; /* absolute to relation with #panels */ - top: 0px; - bottom: 0px; + position: absolute; /* absolute to relation with #panels */ + top: 0px; + bottom: 0px; } #left-panel-wrap { - left: 0px; - width: 8px; /* initial width */ + left: 0px; + width: 8px; /* initial width */ } #right-panel-wrap { - right: 0px; - width: auto; - left: 8px; /* initial width of the left panel */ + right: 0px; + width: auto; + left: 8px; /* initial width of the left panel */ } /* contents */ .panel-content { - position: absolute; - overflow: auto; - overflow-x: hidden; - top: 22px; left: 0px; bottom:0px; right: 0px; + position: absolute; + overflow: auto; + overflow-x: hidden; + top: 25px; left: 0px; bottom:0px; right: 0px; } .panel-overlay { - position: absolute; - top: 0px; bottom: 0px; left: 0px; right: 0px; - z-index: 100; - background: gray; - opacity: 0.8; - text-align: center; - overflow: hidden; - display: none; - cursor: col-resize; + position: absolute; + top: 0px; bottom: 0px; left: 0px; right: 0px; + z-index: 100; + background: gray; + opacity: 0.8; + text-align: center; + overflow: hidden; + display: none; + cursor: col-resize; } .panel-content-overlay { } .panel-wrap.last-panel .panel-content { - right: 0px; + right: 0px; } .panel-wrap.last-panel .panel-slider { @@ -163,7 +163,7 @@ label { /* Toolbars with select box to change panel contents*/ .panel-toolbar { position: absolute; - top: 0px; left:0px; right: 0px; height: 20px; + top: 0px; left:0px; right: 0px; height: 24px; padding: 0 0 2px 0; /* border-top: 1px solid #AAA; */ @@ -185,7 +185,7 @@ label { /* Slider between panels */ .panel-wrap .panel-slider { position: absolute; - background-color: #DDD; + background-color: #DDD; top: 0px; bottom: 0px; right: 0px; width: 4px; @@ -194,8 +194,8 @@ label { border-top: none; border-bottom: none; - z-index: 90; - cursor: col-resize; + z-index: 90; + cursor: col-resize; } .panel-wrap .panel-slider:hover { @@ -203,7 +203,7 @@ label { } .panel-content-overlay.panel-wrap .panel-slider { - background-color: #DDD; + background-color: #DDD; } @@ -268,16 +268,16 @@ label { } div.isection { - margin: 1em auto; - border: 1px solid black; - padding: 0.5em 2em; - background: #9f9ffa; + margin: 1em auto; + border: 1px solid black; + padding: 0.5em 2em; + background: #9f9ffa; - width: 60%; + width: 60%; } div.isection p { - margin: 0.5em 1em; + margin: 0.5em 1em; } .change-notification { @@ -286,7 +286,7 @@ div.isection p { /* * Popups - */ +*/ #message-box { position: fixed; top: 2px; diff --git a/project/static/css/toolbar.css b/project/static/css/toolbar.css index 71940eb9..f38f4ddb 100644 --- a/project/static/css/toolbar.css +++ b/project/static/css/toolbar.css @@ -25,6 +25,7 @@ border: none; padding: 2pt 0.5em; background: #AAA; + font-family: Sans-Serif; } .toolbar div { -- 2.20.1 From 7ba0bf0e4c5325d2f78ae640568e6de9ea3e9440 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=C5=81ukasz=20Rekucki?= Date: Tue, 8 Sep 2009 19:07:48 +0200 Subject: [PATCH 13/16] Nowe przyciski --- dump_toolbar.sh | 3 +- fixtures/przyciski.xml | 488 ++++++++++++++++++++++++++--------------- 2 files changed, 309 insertions(+), 182 deletions(-) diff --git a/dump_toolbar.sh b/dump_toolbar.sh index 796c8c53..58898eee 100755 --- a/dump_toolbar.sh +++ b/dump_toolbar.sh @@ -1,2 +1 @@ -./project/manage.py dumpdata --format=xml toolbar | xmllint --format > -fixtures/przyciski.xml.new +./project/manage.py dumpdata --format=xml toolbar | xmllint --format - > fixtures/przyciski.xml.new diff --git a/fixtures/przyciski.xml b/fixtures/przyciski.xml index 1794c6d7..ea1d7246 100644 --- a/fixtures/przyciski.xml +++ b/fixtures/przyciski.xml @@ -83,7 +83,7 @@ A<sup>+</sup> increase_font_size - ({change: 2}) + {"change": 2} codemirror_fontsize + Zwiększ rozmiar czcionki. @@ -94,7 +94,7 @@ A<sup>-</sup> descrease_font_size - ({change: -2}) + {"change": -2} codemirror_fontsize - Zmniejsz rozmiar czcionki. @@ -105,7 +105,7 @@ A<sup>=</sup> reset_font_size - ({fontSize: 13}) + {"fontSize": 13} codemirror_fontsize = Przywróć orginalny rozmiar czcionki. @@ -113,10 +113,65 @@ + + A<sup>↓</sup> + tolowercase + [] + lowercase + u + Zamień wielkie litery na małe. + + + + + + Podstawowa + basic_correction + {"exprs": [["\n\\d+\n", "\n"], ["-\\s*\n+", ""], ["\\,\\.\\.|\\.\\,\\.|\\.\\.\\,", "..."]]} + fulltextregexp + + Wykonuję operację z novel-pages i poem-pages. + + + + + + Usuń spację + strip_whitespace + {"exprs": [["^\\s+|\\s+$", ""], ["\\s+", " "]]} + lineregexp + + Usuwa zbędne spację z dokumentu. + + + + + + Zamień Cudzysłowy + zamien-cudzyslowy + {"exprs": [["\u00bb|\u201e", ",,"], ["\u00ab", "\""], ["\"([\u0104\u0118\u00d3\u0141\u017b\u0179\u0106\u0143\u0105\u017c\u017a\u015b\u0144\u00f3\u0142\u0107\\w])", ",,$1"]]} + lineregexp + + + + + + + + Zamień dywiz + zamien_dywiz + {"exprs": [["(\\d)[\u2014-](\\d)", "$1--$2"], ["\u2014", "---"]]} + lineregexp + + Zamienia '—' na '---', oraz '1—2' na '1--2'. + + + + akapit akapit - ({tag:"akap"}) + {"tag": "akap"} insert_tag @@ -127,7 +182,7 @@ akapit cd. akapit-cd - ({tag:"akap_cd"}) + {"tag": "akap_cd"} insert_tag @@ -138,7 +193,7 @@ akapit dialogowy akapit-dialogowy - ({tag:"akap_dialog"}) + {"tag": "akap_dialog"} insert_tag @@ -149,7 +204,7 @@ akt akt - ({tag:"akt"}) + {"tag": "akt"} insert_tag @@ -160,7 +215,7 @@ autor autor - ({tag:"autor"}) + {"tag": "autor"} insert_tag @@ -171,7 +226,7 @@ część/księga czesc - ({tag:"naglowek_czesc"}) + {"tag": "naglowek_czesc"} insert_tag @@ -182,7 +237,7 @@ dedykacja dedykacja - ({tag:"dedykacja"}) + {"tag": "dedykacja"} insert_tag @@ -193,7 +248,7 @@ dedykacja dedykacja - ({tag:"dedykacja"}) + {"tag": "dedykacja"} insert_tag @@ -204,7 +259,7 @@ didaskalia didaskalia - ({tag:"didaskalia"}) + {"tag": "didaskalia"} insert_tag @@ -215,7 +270,7 @@ didaskalia didaskalia - ({tag:"didaskalia"}) + {"tag": "didaskalia"} insert_tag @@ -226,7 +281,7 @@ didaskalia wewn. didaskalia-wewn - ({tag:"didask_tekst"}) + {"tag": "didask_tekst"} insert_tag @@ -237,7 +292,7 @@ didaskalia wewn. didaskalia-wewn - ({tag:"didask_tekst"}) + {"tag": "didask_tekst"} insert_tag @@ -248,7 +303,7 @@ dramat wiersz. dramat-wiersz - ({tag:"dramat_wierszowany_l"}) + {"tag": "dramat_wierszowany_l"} insert_tag @@ -259,7 +314,7 @@ dramat wiersz./w. łam dramat-wiersz-w-lam - ({tag:"dramat_wierszowany_lp"}) + {"tag": "dramat_wierszowany_lp"} insert_tag @@ -270,7 +325,7 @@ dramat współczesny dramat-wspolczesny - ({tag:"dramat_wspolczesny"}) + {"tag": "dramat_wspolczesny"} insert_tag @@ -281,7 +336,7 @@ dzieło nadrzędne dzielo-nadrzedne - ({tag:"dzielo_nadrzedne"}) + {"tag": "dzielo_nadrzedne"} insert_tag @@ -292,7 +347,7 @@ długi cyt. poet. dlugi-cyt-poet - ({tag:"poezja_cyt"}) + {"tag": "poezja_cyt"} insert_tag @@ -303,7 +358,7 @@ długi cyta. poet. dlugi-cyt-poet - ({tag:"poezja_cyt"}) + {"tag": "poezja_cyt"} insert_tag @@ -314,29 +369,19 @@ długi cytat dlugi-cytat - ({tag:"dlugi_cyt"}) + {"tag": "dlugi_cyt"} insert_tag - - - - długi cytat - dlugi-cytat - dlugi_cytat - insert_tag - - - ekstra ekstra - ({tag:"ekstra"}) + {"tag": "ekstra"} insert_tag @@ -347,7 +392,7 @@ kwestia kwestia - ({tag:"kwestia"}) + {"tag": "kwestia"} insert_tag @@ -358,7 +403,7 @@ kwestia kwestia - ({tag:"kwestia"}) + {"tag": "kwestia"} insert_tag @@ -369,7 +414,7 @@ liryka liryka - ({tag:"liryka_l"}) + {"tag": "liryka_l"} insert_tag @@ -380,7 +425,7 @@ liryka/w. łam liryka-w-lam - ({tag:"liryka_lp"}) + {"tag": "liryka_lp"} insert_tag @@ -391,7 +436,7 @@ mamtemat. matemat - ({tag:"mat"}) + {"tag": "mat"} insert_tag @@ -402,7 +447,7 @@ motto motto - ({tag:"motto"}) + {"tag": "motto"} insert_tag @@ -413,7 +458,7 @@ motto motto - ({tag:"motto"}) + {"tag": "motto"} insert_tag @@ -424,7 +469,7 @@ motto podpis motto-podpis - ({tag:"motto_podpis"}) + {"tag": "motto_podpis"} insert_tag @@ -435,7 +480,7 @@ nagłówek kwestii naglowek-kwestii - ({tag:"naglowek_osoba"}) + {"tag": "naglowek_osoba"} insert_tag @@ -446,7 +491,7 @@ nota nota - ({tag:"nota"}) + {"tag": "nota"} insert_tag @@ -454,27 +499,10 @@ - - Novelpages - novelpages - ({exprs: [ - - ["\\,\\.\\.|\\.\\,\\.|\\.\\.\\,", "..."], - - ["„", ",,"] /* DOUBLE LOW-9 QUOTATION MARK */ - -]}) - lineregexp - - Wykonuję operację z novel-pages. - - - - opowiadanie opowiadanie - ({tag:"opowiadanie"}) + {"tag": "opowiadanie"} insert_tag @@ -485,7 +513,7 @@ osoba osoba - ({tag:"osoba"}) + {"tag": "osoba"} insert_tag @@ -496,7 +524,7 @@ osoba osoba - ({tag:"osoba"}) + {"tag": "osoba"} insert_tag @@ -507,7 +535,7 @@ podrozdział podrozdzial - ({tag:"naglowek_podrozdzial"}) + {"tag": "naglowek_podrozdzial"} insert_tag @@ -518,7 +546,7 @@ podtytuł podtytul - ({tag:"podtytul"}) + {"tag": "podtytul"} insert_tag @@ -529,7 +557,7 @@ powieść powiesc - ({tag:"powiesc"}) + {"tag": "powiesc"} insert_tag @@ -540,7 +568,7 @@ przypis autorski przypis-autorski - ({tag:"pa"}) + {"tag": "pa"} insert_tag @@ -551,7 +579,7 @@ przypis edytorski przypis-edytorski - ({tag:"pe"}) + {"tag": "pe"} insert_tag @@ -562,7 +590,7 @@ przypis redaktorski przypis-redaktorski - ({tag:"pr"}) + {"tag": "pr"} insert_tag @@ -573,7 +601,7 @@ przypis tłumacza przypis-tlumacza - ({tag:"pt"}) + {"tag": "pt"} insert_tag @@ -584,7 +612,7 @@ rozdział rozdzial - ({tag:"naglowek_rozdzial"}) + {"tag": "naglowek_rozdzial"} insert_tag @@ -595,7 +623,7 @@ scena scena - ({tag:"naglowek_scena"}) + {"tag": "naglowek_scena"} insert_tag @@ -606,7 +634,7 @@ sep. asteryks sep-asteryks - ({tag:"sekcja_asteryks"}) + {"tag": "sekcja_asteryks"} insert_tag @@ -617,7 +645,7 @@ sep. linia sep-linia - ({tag:"separator_linia"}) + {"tag": "separator_linia"} insert_tag @@ -628,7 +656,7 @@ sep. światło sep-swiatlo - ({tag:"sekcja_swiatlo"}) + {"tag": "sekcja_swiatlo"} insert_tag @@ -636,32 +664,10 @@ - - śródtytuł - srodtytul - ({tag:"srodtytul"}) - insert_tag - - - - - - - - strofa - strofa - ({tag"strofa"}) - insert_tag - - - - - - strofa strofa - ({tag:"strofa"}) + {"tag": "strofa"} insert_tag @@ -672,7 +678,7 @@ słowo obce slowo-obce - ({tag:"slowo_obce"}) + {"tag": "slowo_obce"} insert_tag @@ -683,7 +689,7 @@ tagi główne tagi-glowne - ({tag:"utwor"}) + {"tag": "utwor"} insert_tag @@ -694,7 +700,7 @@ tytuł tytul - ({tag:"nazwa_utworu"}) + {"tag": "nazwa_utworu"} insert_tag @@ -705,7 +711,7 @@ tytuł dzieła tytul-dziela - ({tag:"tytul_dziela"}) + {"tag": "tytul_dziela", "attrs": {"typ": " "}} insert_tag @@ -713,21 +719,10 @@ - - Usuń spację - strip_whitespace - ({exprs: [ ["^\\s+|\\s+$", ""], ["\\s+", " "] ]}) - lineregexp - - Usuwa zbędne spację z dokumentu. - - - - uwaga uwaga - ({tag:"uwaga"}) + {"tag": "uwaga"} insert_tag @@ -738,7 +733,7 @@ wers akap. wers-akap - ({tag:"wers_akap"}) + {"tag": "wers_akap"} insert_tag @@ -749,7 +744,7 @@ wers akap. wers-akap - ({tag:"wers_akap"}) + {"tag": "wers_akap"} insert_tag @@ -760,7 +755,7 @@ wers cd. wers-cd - ({tag:"wers_cd"}) + {"tag": "wers_cd"} insert_tag @@ -771,7 +766,7 @@ wers cd. wers-cd - ({tag:"wers_cd"}) + {"tag": "wers_cd"} insert_tag @@ -782,7 +777,7 @@ wers wcięty wers-wciety - ({tag:"wers_wciety"}) + {"tag": "wers_wciety"} insert_tag @@ -793,7 +788,7 @@ wers wcięty wers-wciety - ({tag:"wers_wciety"}) + {"tag": "wers_wciety"} insert_tag @@ -804,7 +799,7 @@ www www - ({tag:"www"}) + {"tag": "www"} insert_tag @@ -815,7 +810,7 @@ wyróżnienie wyroznienie - ({tag:"wyroznienie"}) + {"tag": "wyroznienie"} insert_tag @@ -826,7 +821,7 @@ wywiad wywiad - ({tag:"wywiad"}) + {"tag": "wywiad"} insert_tag @@ -837,7 +832,7 @@ wywiad odpowiedź wywiad-odpowiedz - ({tag:"wywiad_odp"}) + {"tag": "wywiad_odp"} insert_tag @@ -848,7 +843,7 @@ wywiad pytanie wywiad-pytanie - ({tag:"wywiad_pyt"}) + {"tag": "wywiad_pyt"} insert_tag @@ -856,21 +851,10 @@ - - Zamień dywiz - zamien_dywiz - ({exprs:[ ["—","---"] ]}) - lineregexp - - Zamienia '—' na '---'. - - - - zastępnik wersu zastepnik-wersu - ({tag:"zastepnik_wersu"}) + {"tag": "zastepnik_wersu"} insert_tag @@ -878,20 +862,43 @@ + + śródtytuł + srodtytul + {"tag": "srodtytul"} + insert_tag + + + + + + - $.log(editor, panel, params); + var texteditor = panel.texteditor; +var text = texteditor.selection(); +var out = '<'+params.tag; -var texteditor = panel.texteditor; +for (var attr in params.attrs) { -var text = texteditor.selection(); + out += ' '+attr+'="' + params.attrs[attr] + '"'; -texteditor.replaceSelection('<' + params.tag + '>' + text + '</' + params.tag + '>'); +}; -if (text.length == 0) +out += '>'; + +out += text; + +out += '</' + params.tag + '>'; + + + +texteditor.replaceSelection(out); -{ + + +if (text.length == 0) { var pos = texteditor.cursorPosition(); @@ -905,56 +912,86 @@ panel.fireEvent('contentChanged'); // params: {exprs: list of {expr: "", repl: "" [, opts: "g"]}} + var cm = panel.texteditor; + + var exprs = $.map(params.exprs, function(expr) { + var opts = "g"; + if(expr.length > 2) + opts = expr[2]; + return {rx: new RegExp(expr[0], opts), repl: expr[1]}; + }); -var selection = cm.selection(); -if(selection) -{ - var changed = false; - var lines = selection.split('\n'); - var lines = $.map(lines, function(line) { - var old_line = line; - $(exprs).each(function() { - var expr = this; - line = line.replace(expr.rx, expr.repl); - }); - if(old_line != line) changed = true; - return line; + +var partial = true; + +var text = cm.selection(); + + + +if(!text) { + + var cpos = cm.cursorPosition(); + + cpos.line = cm.lineNumber(cpos.line) + + cm.selectLines(cm.firstLine(), 0, cm.lastLine(), 0); + + text = cm.selection(); + + partial = false; + +} + + + +var changed = false; + +var lines = text.split('\n'); + +var lines = $.map(lines, function(line) { + + var old_line = line; + + $(exprs).each(function() { + + var expr = this; + + line = line.replace(expr.rx, expr.repl); + }); - if(changed) { - cm.replaceSelection( lines.join('\n') ); - panel.fireEvent('contentChanged'); - } + if(old_line != line) changed = true; + + return line; + +}); + + + +if(changed) + +{ + + cm.replaceSelection( lines.join('\n') ); + + panel.fireEvent('contentChanged'); + } -else { - var line = cm.firstLine(); - var hasChanges = false; - do { - var content = cm.lineContent(line); - var old_content = content; - $(exprs).each(function() { var expr = this; - content = content.replace(expr.rx, expr.repl); - }); - - if(old_content != content) { - cm.setLineContent(line, content); - hasChanges = true; - } - - line = cm.nextLine(line); - } while( !(line === false) ); - - if(hasChanges) panel.fireEvent('contentChanged'); -} + + + +if(!partial) + + cm.selectLines( cm.nthLine(cpos.line), cpos.character ) var texteditor = panel.texteditor; @@ -977,4 +1014,95 @@ else { } + + var cm = panel.texteditor; + +var exprs = $.map(params.exprs, function(expr) { + + var opts = "mg"; + + if(expr.length > 2) + + opts = expr[2]; + + return {rx: new RegExp(expr[0], opts), repl: expr[1]}; + +}); + + + +var partial = true; + +var text = cm.selection(); + + + +if(!text) { + + var cpos = cm.cursorPosition(); + + cpos.line = cm.lineNumber(cpos.line) + + cm.selectLines(cm.firstLine(), 0, cm.lastLine(), 0); + + text = cm.selection(); + + partial = false; + +} + + + +var original = text; + + + +$(exprs).each(function() { + + text = text.replace(this.rx, this.repl); + +}); + + + +if( original != text) { + + cm.replaceSelection(text); + + panel.fireEvent('contentChanged'); + +} + + + +if(!partial) { + + cm.selectLines( cm.nthLine(cpos.line), cpos.character ); + +} + + + params.each(function() { + + editor.callScriptlet(this[0], this[1]); + +}); + + + var cm = panel.texteditor; + +var text = cm.selection(); + +if(!text) return; + +var repl = text.toLowerCase(); + +if(repl != text) { + + cm.replaceSelection(repl); + + panel.fireEvent('contentChanged'); + +}; + -- 2.20.1 From 537012c60af1ea1c0e39949c58df4647ddadc72b Mon Sep 17 00:00:00 2001 From: =?utf8?q?=C5=81ukasz=20Rekucki?= Date: Tue, 8 Sep 2009 19:34:14 +0200 Subject: [PATCH 14/16] Zlacz takie same przyciski podczas naprawiania. --- .../toolbar/management/commands/fixbuttons.py | 41 +++++++++++++++---- dump_toolbar.sh | 2 +- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/apps/toolbar/management/commands/fixbuttons.py b/apps/toolbar/management/commands/fixbuttons.py index 2f15525b..627ef25d 100755 --- a/apps/toolbar/management/commands/fixbuttons.py +++ b/apps/toolbar/management/commands/fixbuttons.py @@ -10,26 +10,49 @@ class Command(NoArgsCommand): def handle_noargs(self, **options): buttons = Button.objects.all() + print "Validating parameters... " for b in buttons: params = b.params; try: - v = json.loads(b.params) - + v = json.loads(b.params) except ValueError, e: - print 'On button %s: ' % b.label, b.params - print e - # try to fix the bad json - - # cut the parenthis + print 'Trying to fix button "%s" ...' % b.slug if params[0] == u'(': params = params[1:] if params[-1] == u')': params = params[:-1] + try: + v = son.loads(re.sub(u'([\\w-]+)\\s*:', u'"\\1": ', params).encode('utf-8')) + except ValueError, e: + print "Unable to fix '%s' " % b.params + print "Try to fix this button manually and rerun the script." + return False - v = json.loads(re.sub(u'([\\w-]+)\\s*:', u'"\\1": ', params).encode('utf-8')) + # resave b.params = json.dumps(v) b.save() + print "Merge duplicate buttons (if any)..." + hash = {} + for b in buttons: + if b.slug not in hash: + hash[b.slug] = b + continue + + # duplicate button + print "Found duplicate of '%s'" % b.slug + a = hash[b.slug] + + remove_duplicate = True + if a.params != b.params: + print "Conflicting params for duplicate of '%s'." % b.slug + print "Groups will be joined, but won't remove duplicates." + remove_duplicate = False + for g in b.group.all(): + a.group.add(g) - + b.group.clear() + + a.save() + b.delete() diff --git a/dump_toolbar.sh b/dump_toolbar.sh index 58898eee..6dcbbe08 100755 --- a/dump_toolbar.sh +++ b/dump_toolbar.sh @@ -1 +1 @@ -./project/manage.py dumpdata --format=xml toolbar | xmllint --format - > fixtures/przyciski.xml.new +./project/manage.py dumpdata --format=xml toolbar | xmllint --format - > fixtures/przyciski.new.xml -- 2.20.1 From 39e235fcc4bffec8893cf9a2f8924303c7b3a859 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=C5=81ukasz=20Rekucki?= Date: Tue, 8 Sep 2009 20:13:29 +0200 Subject: [PATCH 15/16] Sprawdzanie pustych grup. --- apps/toolbar/management/commands/fixbuttons.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/apps/toolbar/management/commands/fixbuttons.py b/apps/toolbar/management/commands/fixbuttons.py index 627ef25d..5482ddc5 100755 --- a/apps/toolbar/management/commands/fixbuttons.py +++ b/apps/toolbar/management/commands/fixbuttons.py @@ -1,8 +1,9 @@ -# -*- conding: utf-8 +#!/usr/bin/env python +# -*- conding: utf-8 -*- __author__="lreqc" __date__ ="$2009-09-08 14:31:26$" from django.core.management.base import NoArgsCommand -from toolbar.models import Button +from toolbar.models import Button, ButtonGroup from django.utils import simplejson as json import re @@ -55,4 +56,14 @@ class Command(NoArgsCommand): b.group.clear() a.save() - b.delete() + if remove_duplicate: + b.delete() + + print "Searching for empty groups and orphaned buttons:" + for g in ButtonGroup.objects.all(): + if len(g.button_set.all()) == 0: + print "Empty group: '%s'" % g.slug + + for b in Button.objects.all(): + if len(b.group.all()) == 0: + print "orphan: '%s'" % b.slug -- 2.20.1 From 4419f93a01685b9864a6e78cb905c803ec0970b0 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=C5=81ukasz=20Rekucki?= Date: Wed, 9 Sep 2009 01:52:14 +0200 Subject: [PATCH 16/16] Skroty klawiszowe z Ctrl i Shift. Update przyciskow. --- apps/explorer/forms.py | 7 +- apps/explorer/views.py | 10 +- apps/toolbar/admin.py | 39 +- apps/toolbar/models.py | 15 + apps/toolbar/templates/toolbar/toolbar.html | 2 +- apps/toolbar/templatetags/toolbar_tags.py | 5 - fixtures/przyciski.xml | 2090 ++++++++--------- fixtures/przyciski.yaml | 73 - project/static/js/editor.js | 59 +- project/templates/explorer/file_list.html | 4 +- .../templates/explorer/panels/xmleditor.html | 2 +- 11 files changed, 1097 insertions(+), 1209 deletions(-) mode change 100644 => 100755 fixtures/przyciski.xml delete mode 100644 fixtures/przyciski.yaml diff --git a/apps/explorer/forms.py b/apps/explorer/forms.py index da8a1179..e453f1fd 100644 --- a/apps/explorer/forms.py +++ b/apps/explorer/forms.py @@ -62,6 +62,7 @@ class BookUploadForm(forms.Form): file = forms.FileField(label='Source OCR file') bookname = forms.RegexField(regex='[\w-]+', \ label='Publication name', help_text='Example: slowacki-beniowski') + autoxml = forms.BooleanField(required=False, initial=True, label=u"Generate DublinCore template") class ImageFoldersForm(forms.Form): folders = forms.ChoiceField(required=False) @@ -78,13 +79,13 @@ class DublinCoreForm(forms.Form): kinds = ListField() genres = ListField() created_at = forms.DateField() - released_to_public_domain_at = forms.DateField() + released_to_public_domain_at = forms.DateField(required=False) editors = ListField(widget=forms.Textarea, required=False, converter=person_conv) translators = ListField(widget=forms.Textarea, required=False, converter=person_conv) technical_editors = ListField(widget=forms.Textarea, required=False, converter=person_conv) publisher = forms.CharField() - source_name = forms.CharField(widget=forms.Textarea) - source_url = forms.URLField(verify_exists=False) + source_name = forms.CharField(widget=forms.Textarea, required=False) + source_url = forms.URLField(verify_exists=False, required=False) url = forms.URLField(verify_exists=False) parts = forms.CharField(widget=forms.Textarea, required=False) license = forms.CharField(required=False) diff --git a/apps/explorer/views.py b/apps/explorer/views.py index 18f79b3e..b3cc09bc 100644 --- a/apps/explorer/views.py +++ b/apps/explorer/views.py @@ -1,7 +1,10 @@ # -*- coding: utf-8 -*- import urllib2 import hg -from librarian import html, parser, dcparser, ParseError, ValidationError +from datetime import date + +from librarian import html, parser, dcparser, wrap_text +from librarian import ParseError, ValidationError from django.conf import settings from django.contrib.auth.decorators import login_required, permission_required @@ -65,9 +68,12 @@ def file_upload(request, repo): f = request.FILES['file'] decoded = f.read().decode('utf-8') path = form.cleaned_data['bookname'] + + if form.cleaned_data['autoxml']: + decoded = wrap_text(decoded, unicode(date.today()) ) def upload_action(): - repo._add_file(path ,decoded.encode('utf-8') ) + repo._add_file(path, decoded.encode('utf-8') ) repo._commit(message="File %s uploaded by user %s" % \ (path, request.user.username), user=request.user.username) diff --git a/apps/toolbar/admin.py b/apps/toolbar/admin.py index 58b5f746..dca934cc 100644 --- a/apps/toolbar/admin.py +++ b/apps/toolbar/admin.py @@ -12,8 +12,41 @@ from toolbar import models # list_editable = ('position',) +class KeyModSelector(forms.MultiWidget): + def __init__(self): + super(KeyModSelector, self).__init__( + [forms.CheckboxInput() for x in xrange(0,3)]) + + def decompress(self, v): + r = [(v&0x01) != 0, (v&0x02) != 0, (v&0x04) != 0] + print "DECOMPRESS: " , v, repr(r) + return r + + def format_output(self, widgets): + out = u'' + out += u'

' + widgets[0] + u' Alt

' + out += u'

' + widgets[1] + u' Ctrl

' + out += u'

' + widgets[2] + u' Shift

' + return out + +class KeyModField(forms.MultiValueField): + + def __init__(self): + super(KeyModField, self).__init__(\ + fields=tuple(forms.BooleanField() for x in xrange(0,3)), \ + widget=KeyModSelector() ) + + def compress(self, dl): + v = int(dl[0]) | (int(dl[1]) << 1) | (int(dl[2]) << 2) + print "COMPRESS", v + return v + + class ButtonAdminForm(forms.ModelForm): - model = models.Button + key_mod = KeyModField() + + class Meta: + model = models.Button def clean_params(self): value = self.cleaned_data['params'] @@ -22,9 +55,11 @@ class ButtonAdminForm(forms.ModelForm): except Exception, e: raise forms.ValidationError(e) + + class ButtonAdmin(admin.ModelAdmin): form = ButtonAdminForm - list_display = ('label', 'scriptlet', 'key', 'params') + list_display = ('label', 'scriptlet', 'hotkey_name', 'params') prepopulated_fields = {'slug': ('label',)} admin.site.register(models.Button, ButtonAdmin) diff --git a/apps/toolbar/models.py b/apps/toolbar/models.py index ae101e07..004fde9f 100644 --- a/apps/toolbar/models.py +++ b/apps/toolbar/models.py @@ -24,6 +24,7 @@ class Button(models.Model): # ui related stuff key = models.CharField(blank=True, max_length=1) + key_mod = models.PositiveIntegerField(blank=True, default=1) tooltip = models.CharField(blank=True, max_length=120) # Why the button is restricted to have the same position in each group ? @@ -33,6 +34,20 @@ class Button(models.Model): class Meta: ordering = ('label',) verbose_name, verbose_name_plural = _('button'), _('buttons') + + def hotkey_code(self): + return ord(self.key.upper()) | (self.key_mod << 8) + + def hotkey_name(self): + if not self.key: + return '' + + mods = [] + if self.key_mod & 0x01: mods.append('Alt') + if self.key_mod & 0x02: mods.append('Ctrl') + if self.key_mod & 0x04: mods.append('Shift') + mods.append('"'+self.key+'"') + return '+'.join(mods) def __unicode__(self): return self.label diff --git a/apps/toolbar/templates/toolbar/toolbar.html b/apps/toolbar/templates/toolbar/toolbar.html index 21135305..a6241d1e 100644 --- a/apps/toolbar/templates/toolbar/toolbar.html +++ b/apps/toolbar/templates/toolbar/toolbar.html @@ -19,7 +19,7 @@ diff --git a/apps/toolbar/templatetags/toolbar_tags.py b/apps/toolbar/templatetags/toolbar_tags.py index e29c8a0d..a38ed017 100644 --- a/apps/toolbar/templatetags/toolbar_tags.py +++ b/apps/toolbar/templatetags/toolbar_tags.py @@ -7,8 +7,3 @@ register = template.Library() def toolbar(): groups = models.ButtonGroup.objects.all() return {'groups': groups} - -@register.filter -def keycode(value): - return ord(str(value).upper()) - diff --git a/fixtures/przyciski.xml b/fixtures/przyciski.xml old mode 100644 new mode 100755 index ea1d7246..ec2acaba --- a/fixtures/przyciski.xml +++ b/fixtures/przyciski.xml @@ -1,1108 +1,982 @@ - - - - Akapity i długie cytaty - akapity-i-dlugie-cytaty - 0 - - - Autokorekta - autokorekta - 0 - - - Bloki - bloki - 0 - - - Bloki początkowe - bloki-poczatkowe - 0 - - - Deklaracje - deklaracje - 0 - - - Dramat wierszowany - dramat-wierszowany - 0 - - - Dramat współczesny - dramat-wspolczesny - 0 - - - Elementy początkowe - elementy-poczatkowe - 0 - - - Mastery - mastery - 0 - - - Nagłówki - naglowki - 0 - - - Początek dramatu - poczatek-dramatu - 0 - - - Polecenia - polecenia - 0 - - - Strukturalne - strukturalne - 0 - - - Style znakowe - style-znakowe - 0 - - - Wersy - wersy - 0 - - - Widok - display_options - 2 - - - A<sup>+</sup> - increase_font_size - {"change": 2} - codemirror_fontsize - + - Zwiększ rozmiar czcionki. - - - - - - A<sup>-</sup> - descrease_font_size - {"change": -2} - codemirror_fontsize - - - Zmniejsz rozmiar czcionki. - - - - - - A<sup>=</sup> - reset_font_size - {"fontSize": 13} - codemirror_fontsize - = - Przywróć orginalny rozmiar czcionki. - - - - - - A<sup>↓</sup> - tolowercase - [] - lowercase - u - Zamień wielkie litery na małe. - - - - - - Podstawowa - basic_correction - {"exprs": [["\n\\d+\n", "\n"], ["-\\s*\n+", ""], ["\\,\\.\\.|\\.\\,\\.|\\.\\.\\,", "..."]]} - fulltextregexp - - Wykonuję operację z novel-pages i poem-pages. - - - - - - Usuń spację - strip_whitespace - {"exprs": [["^\\s+|\\s+$", ""], ["\\s+", " "]]} - lineregexp - - Usuwa zbędne spację z dokumentu. - - - - - - Zamień Cudzysłowy - zamien-cudzyslowy - {"exprs": [["\u00bb|\u201e", ",,"], ["\u00ab", "\""], ["\"([\u0104\u0118\u00d3\u0141\u017b\u0179\u0106\u0143\u0105\u017c\u017a\u015b\u0144\u00f3\u0142\u0107\\w])", ",,$1"]]} - lineregexp - - - - - - - - Zamień dywiz - zamien_dywiz - {"exprs": [["(\\d)[\u2014-](\\d)", "$1--$2"], ["\u2014", "---"]]} - lineregexp - - Zamienia '—' na '---', oraz '1—2' na '1--2'. - - - - - - akapit - akapit - {"tag": "akap"} - insert_tag - - - - - - - - akapit cd. - akapit-cd - {"tag": "akap_cd"} - insert_tag - - - - - - - - akapit dialogowy - akapit-dialogowy - {"tag": "akap_dialog"} - insert_tag - - - - - - - - akt - akt - {"tag": "akt"} - insert_tag - - - - - - - - autor - autor - {"tag": "autor"} - insert_tag - - - - - - - - część/księga - czesc - {"tag": "naglowek_czesc"} - insert_tag - - - - - - - - dedykacja - dedykacja - {"tag": "dedykacja"} - insert_tag - - - - - - - - dedykacja - dedykacja - {"tag": "dedykacja"} - insert_tag - - - - - - - - didaskalia - didaskalia - {"tag": "didaskalia"} - insert_tag - - - - - - - - didaskalia - didaskalia - {"tag": "didaskalia"} - insert_tag - - - - - - - - didaskalia wewn. - didaskalia-wewn - {"tag": "didask_tekst"} - insert_tag - - - - - - - - didaskalia wewn. - didaskalia-wewn - {"tag": "didask_tekst"} - insert_tag - - - - - - - - dramat wiersz. - dramat-wiersz - {"tag": "dramat_wierszowany_l"} - insert_tag - - - - - - - - dramat wiersz./w. łam - dramat-wiersz-w-lam - {"tag": "dramat_wierszowany_lp"} - insert_tag - - - - - - - - dramat współczesny - dramat-wspolczesny - {"tag": "dramat_wspolczesny"} - insert_tag - - - - - - - - dzieło nadrzędne - dzielo-nadrzedne - {"tag": "dzielo_nadrzedne"} - insert_tag - - - - - - - - długi cyt. poet. - dlugi-cyt-poet - {"tag": "poezja_cyt"} - insert_tag - - - - - - - - długi cyta. poet. - dlugi-cyt-poet - {"tag": "poezja_cyt"} - insert_tag - - - - - - - - długi cytat - dlugi-cytat - {"tag": "dlugi_cyt"} - insert_tag - - - - - - - - - ekstra - ekstra - {"tag": "ekstra"} - insert_tag - - - - - - - - kwestia - kwestia - {"tag": "kwestia"} - insert_tag - - - - - - - - kwestia - kwestia - {"tag": "kwestia"} - insert_tag - - - - - - - - liryka - liryka - {"tag": "liryka_l"} - insert_tag - - - - - - - - liryka/w. łam - liryka-w-lam - {"tag": "liryka_lp"} - insert_tag - - - - - - - - mamtemat. - matemat - {"tag": "mat"} - insert_tag - - - - - - - - motto - motto - {"tag": "motto"} - insert_tag - - - - - - - - motto - motto - {"tag": "motto"} - insert_tag - - - - - - - - motto podpis - motto-podpis - {"tag": "motto_podpis"} - insert_tag - - - - - - - - nagłówek kwestii - naglowek-kwestii - {"tag": "naglowek_osoba"} - insert_tag - - - - - - - - nota - nota - {"tag": "nota"} - insert_tag - - - - - - - - opowiadanie - opowiadanie - {"tag": "opowiadanie"} - insert_tag - - - - - - - - osoba - osoba - {"tag": "osoba"} - insert_tag - - - - - - - - osoba - osoba - {"tag": "osoba"} - insert_tag - - - - - - - - podrozdział - podrozdzial - {"tag": "naglowek_podrozdzial"} - insert_tag - - - - - - - - podtytuł - podtytul - {"tag": "podtytul"} - insert_tag - - - - - - - - powieść - powiesc - {"tag": "powiesc"} - insert_tag - - - - - - - - przypis autorski - przypis-autorski - {"tag": "pa"} - insert_tag - - - - - - - - przypis edytorski - przypis-edytorski - {"tag": "pe"} - insert_tag - - - - - - - - przypis redaktorski - przypis-redaktorski - {"tag": "pr"} - insert_tag - - - - - - - - przypis tłumacza - przypis-tlumacza - {"tag": "pt"} - insert_tag - - - - - - - - rozdział - rozdzial - {"tag": "naglowek_rozdzial"} - insert_tag - - - - - - - - scena - scena - {"tag": "naglowek_scena"} - insert_tag - - - - - - - - sep. asteryks - sep-asteryks - {"tag": "sekcja_asteryks"} - insert_tag - - - - - - - - sep. linia - sep-linia - {"tag": "separator_linia"} - insert_tag - - - - - - - - sep. światło - sep-swiatlo - {"tag": "sekcja_swiatlo"} - insert_tag - - - - - - - - strofa - strofa - {"tag": "strofa"} - insert_tag - - - - - - - - słowo obce - slowo-obce - {"tag": "slowo_obce"} - insert_tag - - - - - - - - tagi główne - tagi-glowne - {"tag": "utwor"} - insert_tag - - - - - - - - tytuł - tytul - {"tag": "nazwa_utworu"} - insert_tag - - - - - - - - tytuł dzieła - tytul-dziela - {"tag": "tytul_dziela", "attrs": {"typ": " "}} - insert_tag - - - - - - - - uwaga - uwaga - {"tag": "uwaga"} - insert_tag - - - - - - - - wers akap. - wers-akap - {"tag": "wers_akap"} - insert_tag - - - - - - - - wers akap. - wers-akap - {"tag": "wers_akap"} - insert_tag - - - - - - - - wers cd. - wers-cd - {"tag": "wers_cd"} - insert_tag - - - - - - - - wers cd. - wers-cd - {"tag": "wers_cd"} - insert_tag - - - - - - - - wers wcięty - wers-wciety - {"tag": "wers_wciety"} - insert_tag - - - - - - - - wers wcięty - wers-wciety - {"tag": "wers_wciety"} - insert_tag - - - - - - - - www - www - {"tag": "www"} - insert_tag - - - - - - - - wyróżnienie - wyroznienie - {"tag": "wyroznienie"} - insert_tag - - - - - - - - wywiad - wywiad - {"tag": "wywiad"} - insert_tag - - - - - - - - wywiad odpowiedź - wywiad-odpowiedz - {"tag": "wywiad_odp"} - insert_tag - - - - - - - - wywiad pytanie - wywiad-pytanie - {"tag": "wywiad_pyt"} - insert_tag - - - - - - - - zastępnik wersu - zastepnik-wersu - {"tag": "zastepnik_wersu"} - insert_tag - - - - - - - - śródtytuł - srodtytul - {"tag": "srodtytul"} - insert_tag - - - - - - - - var texteditor = panel.texteditor; - -var text = texteditor.selection(); - -var out = '<'+params.tag; - -for (var attr in params.attrs) { - - out += ' '+attr+'="' + params.attrs[attr] + '"'; - -}; - -out += '>'; - -out += text; - -out += '</' + params.tag + '>'; - - - -texteditor.replaceSelection(out); - - - -if (text.length == 0) { - - var pos = texteditor.cursorPosition(); - - texteditor.selectLines(pos.line, pos.character + params.tag.length + 2); - -} - - - -panel.fireEvent('contentChanged'); - - - // params: {exprs: list of {expr: "", repl: "" [, opts: "g"]}} - -var cm = panel.texteditor; - - - -var exprs = $.map(params.exprs, function(expr) { - - var opts = "g"; - - if(expr.length > 2) - - opts = expr[2]; - - return {rx: new RegExp(expr[0], opts), repl: expr[1]}; - -}); - - - -var partial = true; - -var text = cm.selection(); - - - -if(!text) { - - var cpos = cm.cursorPosition(); - - cpos.line = cm.lineNumber(cpos.line) - - cm.selectLines(cm.firstLine(), 0, cm.lastLine(), 0); - - text = cm.selection(); - - partial = false; - -} - - - -var changed = false; - -var lines = text.split('\n'); - -var lines = $.map(lines, function(line) { - - var old_line = line; - - $(exprs).each(function() { - - var expr = this; - - line = line.replace(expr.rx, expr.repl); - - }); - - if(old_line != line) changed = true; - - return line; - -}); - - - -if(changed) - -{ - - cm.replaceSelection( lines.join('\n') ); - - panel.fireEvent('contentChanged'); - -} - - - -if(!partial) - - cm.selectLines( cm.nthLine(cpos.line), cpos.character ) - - - var texteditor = panel.texteditor; - -var frameBody = $('body', $(texteditor.frame).contents()); - - - -if(params.fontSize) { - - frameBody.css('font-size', params.fontSize); - -} - -else { - - var old_size = parseInt(frameBody.css('font-size')); - - frameBody.css('font-size', old_size + (params.change || 0) ); - -} - - - var cm = panel.texteditor; - -var exprs = $.map(params.exprs, function(expr) { - - var opts = "mg"; - - if(expr.length > 2) - - opts = expr[2]; - - return {rx: new RegExp(expr[0], opts), repl: expr[1]}; - -}); - - - -var partial = true; - -var text = cm.selection(); - - - -if(!text) { - - var cpos = cm.cursorPosition(); - - cpos.line = cm.lineNumber(cpos.line) - - cm.selectLines(cm.firstLine(), 0, cm.lastLine(), 0); - - text = cm.selection(); - - partial = false; - -} - - - -var original = text; - - - -$(exprs).each(function() { - - text = text.replace(this.rx, this.repl); - -}); - - - -if( original != text) { - - cm.replaceSelection(text); - - panel.fireEvent('contentChanged'); - -} - - - -if(!partial) { - - cm.selectLines( cm.nthLine(cpos.line), cpos.character ); - -} - - - params.each(function() { - - editor.callScriptlet(this[0], this[1]); - -}); - - - var cm = panel.texteditor; - -var text = cm.selection(); - -if(!text) return; - -var repl = text.toLowerCase(); - -if(repl != text) { - - cm.replaceSelection(repl); - - panel.fireEvent('contentChanged'); - -}; - - + + + + Akapity i długie cytaty + akapity-i-dlugie-cytaty + 0 + + + Autokorekta + autokorekta + 0 + + + Bloki + bloki + 0 + + + Dramat wierszowany + dramat-wierszowany + 0 + + + Dramat współczesny + dramat-wspolczesny + 0 + + + Elementy początkowe + elementy-poczatkowe + 0 + + + Nagłówki + naglowki + 0 + + + Początek dramatu + poczatek-dramatu + 0 + + + Polecenia + polecenia + 0 + + + Strukturalne + strukturalne + 0 + + + Style znakowe + style-znakowe + 0 + + + Wersy + wersy + 0 + + + Widok + display_options + 2 + + + A<sup>+</sup> + increase_font_size + {"change": 2} + codemirror_fontsize + + + Zwiększ rozmiar czcionki. + + + + + + A<sup>-</sup> + descrease_font_size + {"change": -2} + codemirror_fontsize + - + Zmniejsz rozmiar czcionki. + + + + + + A<sup>=</sup> + reset_font_size + {"fontSize": 13} + codemirror_fontsize + = + Przywróć orginalny rozmiar czcionki. + + + + + + A<sup>↓</sup> + tolowercase + [] + lowercase + u + Zamień wielkie litery na małe. + + + + + + akapit + akapit + {"tag": "akap"} + insert_tag + + + + + + + + akapit cd. + akapit-cd + {"tag": "akap_cd"} + insert_tag + + + + + + + + akapit dialogowy + akapit-dialogowy + {"tag": "akap_dialog"} + insert_tag + + + + + + + + akt + akt + {"tag": "akt"} + insert_tag + + + + + + + + autor + autor + {"tag": "autor"} + insert_tag + + + + + + + + część/księga + czesc + {"tag": "naglowek_czesc"} + insert_tag + + + + + + + + dedykacja + dedykacja + {"tag": "dedykacja"} + insert_tag + + + + + + + + + didaskalia + didaskalia + {"tag": "didaskalia"} + insert_tag + + + + + + + + + didaskalia początkowe + didaskalia-poczatkowe + {"tag": "miejsce_czas"} + insert_tag + + + + + + + + didaskalia wewn. + didaskalia-wewn + {"tag": "didask_tekst"} + insert_tag + + + + + + + + + dramat wiersz. + dramat-wiersz + {"tag": "dramat_wierszowany_l"} + insert_tag + + + + + + + + dramat wiersz./w. łam + dramat-wiersz-w-lam + {"tag": "dramat_wierszowany_lp"} + insert_tag + + + + + + + + dramat współczesny + dramat-wspolczesny + {"tag": "dramat_wspolczesny"} + insert_tag + + + + + + + + dzieło nadrzędne + dzielo-nadrzedne + {"tag": "dzielo_nadrzedne"} + insert_tag + + + + + + + + długi cyt. poet. + dlugi-cyt-poet + {"tag": "poezja_cyt"} + insert_tag + + + + + + + + + długi cytat + dlugi-cytat + {"tag": "dlugi_cyt"} + insert_tag + + + + + + + + + ekstra + ekstra + {"tag": "ekstra"} + insert_tag + + + + + + + + kwestia + kwestia + {"tag": "kwestia"} + insert_tag + + + + + + + + + liryka + liryka + {"tag": "liryka_l"} + insert_tag + + + + + + + + liryka/w. łam + liryka-w-lam + {"tag": "liryka_lp"} + insert_tag + + + + + + + + lista osób: pole + lista-osob-pole + {"tag": "lista_osoba", "attrs": {"typ": ""}} + insert_tag + + + + + + + + mamtemat. + matemat + {"tag": "mat"} + insert_tag + + + + + + + + motto + motto + {"tag": "motto"} + insert_tag + + + + + + + + + motto podpis + motto-podpis + {"tag": "motto_podpis"} + insert_tag + + + + + + + + nagłówek kwestii + naglowek-kwestii + {"tag": "naglowek_osoba"} + insert_tag + + + + + + + + nota + nota + {"tag": "nota"} + insert_tag + + + + + + + + opowiadanie + opowiadanie + {"tag": "opowiadanie"} + insert_tag + + + + + + + + osoba + osoba + {"tag": "osoba"} + insert_tag + + + + + + + + + podrozdział + podrozdzial + {"tag": "naglowek_podrozdzial"} + insert_tag + + + + + + + + Podstawowa + basic_correction + {"exprs": [["\n\\d+\n", "\n"], ["-\\s*\n+", ""], ["\\,\\.\\.|\\.\\,\\.|\\.\\.\\,", "..."]]} + fulltextregexp + + Wykonuję operację z novel-pages i poem-pages. + + + + + + podtytuł + podtytul + {"tag": "podtytul"} + insert_tag + + + + + + + + powieść + powiesc + {"tag": "powiesc"} + insert_tag + + + + + + + + przypis autorski + przypis-autorski + {"tag": "pa"} + insert_tag + + + + + + + + przypis edytorski + przypis-edytorski + {"tag": "pe"} + insert_tag + + + + + + + + przypis redaktorski + przypis-redaktorski + {"tag": "pr"} + insert_tag + + + + + + + + przypis tłumacza + przypis-tlumacza + {"tag": "pt"} + insert_tag + + + + + + + + rozdział + rozdzial + {"tag": "naglowek_rozdzial"} + insert_tag + + + + + + + + scena + scena + {"tag": "naglowek_scena"} + insert_tag + + + + + + + + sep. asteryks + sep-asteryks + {"tag": "sekcja_asteryks"} + insert_tag + + + + + + + + sep. linia + sep-linia + {"tag": "separator_linia"} + insert_tag + + + + + + + + sep. światło + sep-swiatlo + {"tag": "sekcja_swiatlo"} + insert_tag + + + + + + + + śródtytuł + srodtytul + {"tag": "srodtytul"} + insert_tag + + + + + + + + strofa + strofa + {"tag": "strofa"} + insert_tag + s + + + + + + + + słowo obce + slowo-obce + {"tag": "slowo_obce"} + insert_tag + + + + + + + + tagi główne + tagi-glowne + {"tag": "utwor"} + insert_tag + + + + + + + + tytuł + tytul + {"tag": "nazwa_utworu"} + insert_tag + + + + + + + + tytuł dzieła + tytul-dziela + {"tag": "tytul_dziela", "attrs": {"typ": "1"}} + insert_tag + + + + + + + + Usuń spację + strip_whitespace + {"exprs": [["^\\s+|\\s+$", ""], ["\\s+", " "]]} + lineregexp + + Usuwa zbędne spację z dokumentu. + + + + + + uwaga + uwaga + {"tag": "uwaga"} + insert_tag + + + + + + + + wers akap. + wers-akap + {"tag": "wers_akap"} + insert_tag + + + + + + + + + wers cd. + wers-cd + {"tag": "wers_cd"} + insert_tag + + + + + + + + + Wers wcięty + wers-wciety + {"tag": "wers_wciety", "attrs": {"typ": ""}} + insert_tag + + + + + + + + + www + www + {"tag": "www"} + insert_tag + + + + + + + + wyróżnienie + wyroznienie + {"tag": "wyroznienie"} + insert_tag + + + + + + + + wywiad + wywiad + {"tag": "wywiad"} + insert_tag + + + + + + + + wywiad odpowiedź + wywiad-odpowiedz + {"tag": "wywiad_odp"} + insert_tag + + + + + + + + wywiad pytanie + wywiad-pytanie + {"tag": "wywiad_pyt"} + insert_tag + + + + + + + + Zamień cudzysłowy + zamien-cudzyslowy + {"exprs": [["\u00bb|\u201e", ",,"], ["\u00ab", "\""], ["\"([\u0104\u0118\u00d3\u0141\u017b\u0179\u0106\u0143\u0105\u017c\u017a\u015b\u0144\u00f3\u0142\u0107\\w])", ",,$1"]]} + lineregexp + + + + + + + + Zamień dywiz + zamien_dywiz + {"exprs": [["(\\d)[\u2014-](\\d)", "$1--$2"], ["\u2014", "---"]]} + lineregexp + + Zamienia '—' na '---', oraz '1—2' na '1--2'. + + + + + + zastępnik wersu + zastepnik-wersu + {"tag": "zastepnik_wersu"} + insert_tag + + + + + + + + var texteditor = panel.texteditor; + +var text = texteditor.selection(); + +var out = '<'+params.tag; + +for (var attr in params.attrs) { + + out += ' '+attr+'="' + params.attrs[attr] + '"'; + +}; + +out += '>'; + +out += text; + +out += '</' + params.tag + '>'; + + + +texteditor.replaceSelection(out); + + + +if (text.length == 0) { + + var pos = texteditor.cursorPosition(); + + texteditor.selectLines(pos.line, pos.character + params.tag.length + 2); + +} + + + +panel.fireEvent('contentChanged'); + + + editor.showPopup('generic-info', 'Przetwarzanie zaznaczonego tekstu...', '', -1); + +var cm = panel.texteditor; +var exprs = $.map(params.exprs, function(expr) { + + var opts = "g"; + + if(expr.length > 2) + + opts = expr[2]; + + return {rx: new RegExp(expr[0], opts), repl: expr[1]}; + +}); + + + +var partial = true; + +var text = cm.selection(); + + + +if(!text) { + + var cpos = cm.cursorPosition(); + + cpos.line = cm.lineNumber(cpos.line) + + cm.selectLines(cm.firstLine(), 0, cm.lastLine(), 0); + + text = cm.selection(); + + partial = false; + +} + + + +var changed = 0; +var lines = text.split('\n'); +var lines = $.map(lines, function(line) { + var old_line = line; + $(exprs).each(function() { + var expr = this; + line = line.replace(expr.rx, expr.repl); + }); + + if(old_line != line) changed += 1; + return line; +}); + +if(changed > 0) +{ + cm.replaceSelection( lines.join('\n') ); + panel.fireEvent('contentChanged'); + editor.showPopup('generic-yes', 'Zmieniono ' + changed + ' linii.', 1500); + editor.advancePopupQueue(); +} +else { + editor.showPopup('generic-info', 'Brak zmian w tekście', 1500); + editor.advancePopupQueue(); +} + +if(!partial) + cm.selectLines( cm.nthLine(cpos.line), cpos.character ) + + + var texteditor = panel.texteditor; + +var frameBody = $('body', $(texteditor.frame).contents()); + + + +if(params.fontSize) { + + frameBody.css('font-size', params.fontSize); + +} + +else { + + var old_size = parseInt(frameBody.css('font-size')); + + frameBody.css('font-size', old_size + (params.change || 0) ); + +} + + + editor.showPopup('generic-info', 'Przetwarzanie zaznaczonego tekstu...', '', -1); + +var cm = panel.texteditor; + +var exprs = $.map(params.exprs, function(expr) { + var opts = "mg"; + if(expr.length > 2) + opts = expr[2]; + + return {rx: new RegExp(expr[0], opts), repl: expr[1]}; +}); + +var partial = true; +var text = cm.selection(); + +if(!text) { + var cpos = cm.cursorPosition(); + cpos.line = cm.lineNumber(cpos.line) + cm.selectLines(cm.firstLine(), 0, cm.lastLine(), 0); + + text = cm.selection(); + partial = false; +} + + + +var original = text; +$(exprs).each(function() { + text = text.replace(this.rx, this.repl); +}); + +if( original != text) +{ + cm.replaceSelection(text); + panel.fireEvent('contentChanged'); + editor.showPopup('generic-yes', 'Zmieniono tekst' ); + editor.advancePopupQueue(); +} +else { + editor.showPopup('generic-info', 'Brak zmian w tekście.'); + editor.advancePopupQueue(); +} + +if(!partial) { + cm.selectLines( cm.nthLine(cpos.line), cpos.character ); +} + + + params.each(function() { + + editor.callScriptlet(this[0], this[1]); + +}); + + + var cm = panel.texteditor; + +var text = cm.selection(); + +if(!text) return; + +var repl = text.toLowerCase(); + +if(repl != text) { + + cm.replaceSelection(repl); + + panel.fireEvent('contentChanged'); + +}; + + diff --git a/fixtures/przyciski.yaml b/fixtures/przyciski.yaml deleted file mode 100644 index a8cef760..00000000 --- a/fixtures/przyciski.yaml +++ /dev/null @@ -1,73 +0,0 @@ -- fields: {name: Autokorekta, position: 0, slug: autokorekta} - model: toolbar.buttongroup - pk: 2 -- fields: {name: Formatowanie, position: 0, slug: formatowanie} - model: toolbar.buttongroup - pk: 1 -- fields: - group: [2] - key: '' - label: Novelpages - params: "({exprs: [\r\n [\"\\\\,\\\\.\\\\.|\\\\.\\\\,\\\\.|\\\\.\\\\.\\\\,\"\ - , \"...\"],\r\n [\"\u201E\", \",,\"] /* DOUBLE LOW-9 QUOTATION MARK */\r\n\ - ]})\r\n " - scriptlet: lineregexp - slug: novelpages - tooltip: "Wykonuj\u0119 operacj\u0119 z novel-pages." - model: toolbar.button - pk: 4 -- fields: - group: [2] - key: '' - label: "Usu\u0144 spacj\u0119" - params: '({exprs: [ ["^\\s+|\\s+$", ""], ["\\s+", " "] ]})' - scriptlet: lineregexp - slug: strip_whitespace - tooltip: "Usuwa zb\u0119dne spacj\u0119 z dokumentu." - model: toolbar.button - pk: 3 -- fields: - group: [1] - key: w - label: Wers - params: '({tag: ''wers''})' - scriptlet: insert_tag - slug: insert_verse - tooltip: Otacza zaznaczony tekst tagiem 'wers'. - model: toolbar.button - pk: 1 -- fields: - group: [2] - key: '' - label: "Zamie\u0144 dywiz" - params: "({exprs:[ [\"\u2014\",\"---\"] ]})" - scriptlet: lineregexp - slug: zamien_dywiz - tooltip: "Zamienia '\u2014' na '---'." - model: toolbar.button - pk: 2 -- fields: {code: "$.log(editor, panel, params);\r\n\r\nvar texteditor = panel.texteditor;\r\ - \nvar text = texteditor.selection();\r\ntexteditor.replaceSelection('<' + params.tag\ - \ + '>' + text + '');\r\nif (text.length == 0) \r\n{\r\n\ - \ var pos = texteditor.cursorPosition();\r\n texteditor.selectLines(pos.line,\ - \ pos.character + params.tag.length + 2);\r\n}\r\n\r\npanel.fireEvent('contentChanged');"} - model: toolbar.scriptlet - pk: insert_tag -- fields: {code: "// params: {exprs: list of {expr: \"\", repl: \"\" [, opts: \"g\"\ - ]}}\r\nvar cm = panel.texteditor;\r\n\r\nvar exprs = $.map(params.exprs, function(expr)\ - \ {\r\n var opts = \"g\";\r\n if(expr.length > 2)\r\n opts = expr[2];\r\ - \n return {rx: new RegExp(expr[0], opts), repl: expr[1]};\r\n});\r\n\r\n\ - var selection = cm.selection();\r\n\r\nif(selection) \r\n{\r\n var lines\ - \ = selection.split('\\n');\r\n lines = $.map(lines, function(line) { \r\n\ - \ $(exprs).each(function() { \r\n var expr = this;\r\n \ - \ line = line.replace(expr.rx, expr.repl);\r\n });\r\n \ - \ return line;\r\n });\r\n cm.replaceSelection( lines.join('\\n') );\r\ - \n}\r\nelse {\r\n var line = cm.firstLine();\r\n do {\r\n var content\ - \ = cm.lineContent(line);\r\n $.log(\"Swapping line: $\" + content +\ - \ \"$\");\r\n \r\n $(exprs).each(function() { var expr = this;\r\n\ - \ content = content.replace(expr.rx, expr.repl);\r\n });\r\ - \n cm.setLineContent(line, content);\r\n line = cm.nextLine(line);\r\ - \n } while( !(line === false) );\r\n}"} - model: toolbar.scriptlet - pk: lineregexp - diff --git a/project/static/js/editor.js b/project/static/js/editor.js index 3490b9a1..f7f4cf31 100644 --- a/project/static/js/editor.js +++ b/project/static/js/editor.js @@ -1,3 +1,21 @@ +function Hotkey(code) { + this.code = code + this.has_alt = ((code & 0x01 << 8) != 0) + this.has_ctrl = ((code & 0x01 << 9) != 0) + this.has_shift = ((code & 0x01 << 10) != 0) + this.character = String.fromCharCode(code & 0xff) +} + + +Hotkey.prototype.toString = function() { + mods = [] + if(this.has_alt) mods.push('Alt') + if(this.has_ctrl) mods.push('Ctrl') + if(this.has_shift) mods.push('Shift') + mods.push('"'+this.character+'"') + return mods.join('+') +} + function Panel(panelWrap) { var self = this; self.hotkeys = []; @@ -122,12 +140,12 @@ Panel.prototype.connectToolbar = function() // connect group-switch buttons var group_buttons = $('*.toolbar-tabs-container button', toolbar); - $.log('Found groups:', group_buttons); + // $.log('Found groups:', group_buttons); group_buttons.each(function() { var group = $(this); var group_name = group.attr('ui:group'); - $.log('Connecting group: ' + group_name); + // $.log('Connecting group: ' + group_name); group.click(function() { // change the active group @@ -151,6 +169,7 @@ Panel.prototype.connectToolbar = function() action_buttons.each(function() { var button = $(this); var hk = button.attr('ui:hotkey'); + if(hk) hk = new Hotkey( parseInt(hk) ); try { var params = $.evalJSON(button.attr('ui:action-params')); @@ -166,15 +185,18 @@ Panel.prototype.connectToolbar = function() // connect button button.click(callback); - + // connect hotkey - if(hk) self.hotkeys[parseInt(hk)] = callback; - + if(hk) { + self.hotkeys[hk.code] = callback; + $.log('hotkey', hk); + } + // tooltip if (button.attr('ui:tooltip') ) { var tooltip = button.attr('ui:tooltip'); - if(hk) tooltip += ' [Alt+'+hk+']'; + if(hk) tooltip += ' ['+hk+']'; button.wTooltip({ delay: 1000, @@ -193,13 +215,24 @@ Panel.prototype.connectToolbar = function() Panel.prototype.hotkeyPressed = function(event) { - var callback = this.hotkeys[event.keyCode]; + code = event.keyCode; + if(event.altKey) code = code | 0x100; + if(event.ctrlKey) code = code | 0x200; + if(event.shiftKey) code = code | 0x400; + + var callback = this.hotkeys[code]; if(callback) callback(); } Panel.prototype.isHotkey = function(event) { - if( event.altKey && (this.hotkeys[event.keyCode] != null) ) + code = event.keyCode; + if(event.altKey) code = code | 0x100; + if(event.ctrlKey) code = code | 0x200; + if(event.shiftKey) code = code | 0x400; + + if(this.hotkeys[code] != null) return true; + return false; } @@ -522,7 +555,7 @@ Editor.prototype.showPopup = function(name, text, timeout) var box = $('#message-box > #' + name); $('*.data', box).html(text || ''); - box.fadeIn(); + box.fadeIn(100); if(timeout > 0) setTimeout( $.fbind(self, self.advancePopupQueue), timeout); @@ -534,14 +567,14 @@ Editor.prototype.advancePopupQueue = function() { if(elem) { var box = $('#message-box > #' + elem[0]); - box.fadeOut(200, function() + box.fadeOut(100, function() { - $('*.data', box).html(); + $('*.data', box).html(''); if( self.popupQueue.length > 0) { var ibox = $('#message-box > #' + self.popupQueue[0][0]); - $('*.data', ibox).html(self.popupQueue[0][1]); - ibox.fadeIn(); + $('*.data', ibox).html(self.popupQueue[0][1] || ''); + ibox.fadeIn(100); if(self.popupQueue[0][2] > 0) setTimeout( $.fbind(self, self.advancePopupQueue), self.popupQueue[0][2]); } diff --git a/project/templates/explorer/file_list.html b/project/templates/explorer/file_list.html index a36d353a..d47a158a 100644 --- a/project/templates/explorer/file_list.html +++ b/project/templates/explorer/file_list.html @@ -48,7 +48,9 @@ $(function() {

Dodaj nowy utwór

- {{ bookform.as_p }} +

+

+

diff --git a/project/templates/explorer/panels/xmleditor.html b/project/templates/explorer/panels/xmleditor.html index 3a1baf1c..5c622bbf 100644 --- a/project/templates/explorer/panels/xmleditor.html +++ b/project/templates/explorer/panels/xmleditor.html @@ -16,7 +16,7 @@ panel_hooks = { var textareaId = 'xmleditor-' + Math.ceil(Math.random() * 1000000000); $('textarea', panel).attr('id', textareaId); - var texteditor = CodeMirror.fromTextArea(textareaId, { + var texteditor = CodeMirror.fromTextArea(textareaId, { parserfile: 'parsexml.js', path: "{{STATIC_URL}}js/codemirror/", stylesheet: "{{STATIC_URL}}css/xmlcolors.css", -- 2.20.1