Merge branch 'production'
authorRadek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>
Tue, 3 Aug 2010 11:07:29 +0000 (13:07 +0200)
committerRadek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>
Tue, 3 Aug 2010 11:07:29 +0000 (13:07 +0200)
145 files changed:
.gitignore
apps/django_cas/backends.py
apps/filebrowser/media/filebrowser/uploadify/example/css/default.css
apps/filebrowser/media/filebrowser/uploadify/example/css/uploadify.css
apps/filebrowser/media/filebrowser/uploadify/uploadify.css
apps/toolbar/__init__.py
apps/toolbar/admin.py
apps/toolbar/fixtures/initial_data.yaml
apps/toolbar/locale/pl/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/toolbar/locale/pl/LC_MESSAGES/django.po [new file with mode: 0644]
apps/toolbar/migrations/__init__.py
apps/toolbar/templates/toolbar/button.html
apps/toolbar/templates/toolbar/toolbar.html
apps/wiki/__init__.py
apps/wiki/admin.py [new file with mode: 0644]
apps/wiki/constants.py
apps/wiki/fixtures/initial_themes.yaml [new file with mode: 0644]
apps/wiki/forms.py
apps/wiki/helpers.py
apps/wiki/locale/pl/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/wiki/locale/pl/LC_MESSAGES/django.po [new file with mode: 0644]
apps/wiki/migrations/0001_initial.py [new file with mode: 0644]
apps/wiki/migrations/0002_auto__add_theme.py [new file with mode: 0644]
apps/wiki/migrations/__init__.py [new file with mode: 0644]
apps/wiki/models.py
apps/wiki/nice_diff.py [changed mode: 0755->0644]
apps/wiki/templates/wiki/base.html
apps/wiki/templates/wiki/diff_table.html
apps/wiki/templates/wiki/document_create_missing.html
apps/wiki/templates/wiki/document_details.html
apps/wiki/templates/wiki/document_details_base.html
apps/wiki/templates/wiki/document_details_readonly.html
apps/wiki/templates/wiki/document_list.html
apps/wiki/templates/wiki/save_dialog.html
apps/wiki/templates/wiki/tabs/gallery_view.html
apps/wiki/templates/wiki/tabs/gallery_view_item.html [new file with mode: 0644]
apps/wiki/templates/wiki/tabs/history_view.html
apps/wiki/templates/wiki/tabs/history_view_item.html
apps/wiki/templates/wiki/tabs/search_view.html [new file with mode: 0644]
apps/wiki/templates/wiki/tabs/search_view_item.html [new file with mode: 0644]
apps/wiki/templates/wiki/tabs/source_editor.html
apps/wiki/templates/wiki/tabs/source_editor_item.html
apps/wiki/templates/wiki/tabs/summary_view.html
apps/wiki/templates/wiki/tabs/summary_view_item.html
apps/wiki/templates/wiki/tabs/wysiwyg_editor.html
apps/wiki/templates/wiki/tabs/wysiwyg_editor_item.html
apps/wiki/templates/wiki/tag_dialog.html
apps/wiki/templatetags/__init__.py [new file with mode: 0644]
apps/wiki/templatetags/wiki.py [new file with mode: 0644]
apps/wiki/urls.py
apps/wiki/views.py
deployment.py
hudson_build.sh [new file with mode: 0644]
lib/test_vstorage.py [deleted file]
lib/test_wlapi.py [deleted file]
lib/vstorage.py [deleted file]
lib/vstorage/__init__.py [new file with mode: 0644]
lib/vstorage/hgui.py [new file with mode: 0644]
lib/vstorage/tests.py [new file with mode: 0644]
lib/wlapi.py [deleted file]
lib/wlapi/__init__.py [new file with mode: 0644]
lib/wlapi/tests.py [new file with mode: 0644]
localsettings.sample [deleted file]
logging.cfg.dev
redakcja.vhost.template
redakcja.wsgi.template
redakcja/compress_settings.py [deleted file]
redakcja/context_processors.py
redakcja/locale/pl/LC_MESSAGES/django.po
redakcja/localsettings.sample [new file with mode: 0644]
redakcja/manage.py
redakcja/settings.py [deleted file]
redakcja/settings/__init__.py [new file with mode: 0644]
redakcja/settings/common.py [new file with mode: 0644]
redakcja/settings/compress.py [new file with mode: 0644]
redakcja/settings/test.py [new file with mode: 0644]
redakcja/static/css/dialogs.css
redakcja/static/css/filelist.css
redakcja/static/css/gallery.css
redakcja/static/css/html.css
redakcja/static/css/html_print.css
redakcja/static/css/jquery.autocomplete.css
redakcja/static/css/master.css
redakcja/static/css/summary.css
redakcja/static/css/toolbar.css [new file with mode: 0644]
redakcja/static/css/xmlcolors_15032010.css
redakcja/static/filebrowser/uploadify/example/css/default.css
redakcja/static/filebrowser/uploadify/example/css/uploadify.css
redakcja/static/filebrowser/uploadify/uploadify.css
redakcja/static/js/button_scripts.js
redakcja/static/js/jquery-1.4.2.min.js [deleted file]
redakcja/static/js/jquery.autocomplete.js [deleted file]
redakcja/static/js/jquery.blockui.js [deleted file]
redakcja/static/js/jquery.elastic.js [deleted file]
redakcja/static/js/lib/codemirror/codemirror.js
redakcja/static/js/lib/codemirror/editor.js
redakcja/static/js/lib/jquery-1.4.2.min.js [new file with mode: 0644]
redakcja/static/js/lib/jquery/jquery.autocomplete.js [new file with mode: 0644]
redakcja/static/js/lib/jquery/jquery.blockui.js [new file with mode: 0644]
redakcja/static/js/lib/jquery/jquery.elastic.js [new file with mode: 0644]
redakcja/static/js/wiki/base.js
redakcja/static/js/wiki/dialog_save.js
redakcja/static/js/wiki/loader.js
redakcja/static/js/wiki/toolbar.js [new file with mode: 0644]
redakcja/static/js/wiki/view_editor_source.js
redakcja/static/js/wiki/view_editor_wysiwyg.js
redakcja/static/js/wiki/view_gallery.js
redakcja/static/js/wiki/view_history.js
redakcja/static/js/wiki/view_search.js [new file with mode: 0644]
redakcja/static/js/wiki/wikiapi.js
redakcja/static/js/wiki/xslt.js
redakcja/templates/base.html
redakcja/urls.py
redmine/redmine_publications/README.rdoc [deleted file]
redmine/redmine_publications/app/controllers/publications_controller.rb [deleted file]
redmine/redmine_publications/app/helpers/publications_helper.rb [deleted file]
redmine/redmine_publications/app/models/issue_publication.rb [deleted file]
redmine/redmine_publications/app/models/publication.rb [deleted file]
redmine/redmine_publications/app/views/issues/_issue_form_pub.html.erb [deleted file]
redmine/redmine_publications/app/views/issues/_issue_view_pub.erb [deleted file]
redmine/redmine_publications/app/views/publications/index.html.erb [deleted file]
redmine/redmine_publications/app/views/publications/issues.html.erb [deleted file]
redmine/redmine_publications/app/views/publications/refresh.erb [deleted file]
redmine/redmine_publications/app/views/settings/_publications_settings.html.erb [deleted file]
redmine/redmine_publications/db/migrate/001_create_publications.rb [deleted file]
redmine/redmine_publications/db/migrate/002_create_issue_publications.rb [deleted file]
redmine/redmine_publications/db/migrate/003_publications_add_repo_id.rb [deleted file]
redmine/redmine_publications/db/migrate/004_publications_add_name.rb [deleted file]
redmine/redmine_publications/init.rb [deleted file]
redmine/redmine_publications/lang/en.yml [deleted file]
redmine/redmine_publications/lib/issue_publication_hook.rb [deleted file]
redmine/redmine_publications/lib/redmine_publications/change_patch.rb [deleted file]
redmine/redmine_publications/lib/redmine_publications/issue_patch.rb [deleted file]
redmine/redmine_publications/locales/en.yml [deleted file]
redmine/redmine_publications/locales/pl.yml [deleted file]
redmine/redmine_publications/routes.rb [deleted file]
redmine/redmine_publications/test/fixtures/publications.yml [deleted file]
redmine/redmine_publications/test/functional/publications_controller_test.rb [deleted file]
redmine/redmine_publications/test/test_helper.rb [deleted file]
redmine/redmine_publications/test/unit/publication_test.rb [deleted file]
requirements-test.txt [new file with mode: 0644]
requirements.txt
scripts/crop.py [changed mode: 0644->0755]
scripts/imgconv.py [changed mode: 0644->0755]
scripts/rip-themes-from-redmine.py [changed mode: 0644->0755]

index a926b1a..0d55584 100644 (file)
@@ -2,10 +2,15 @@ localsettings.py
 dev.sqlite
 requirements.pybundle
 *~
+*.orig
 
 # Python garbage
 *.pyc
 .coverage
+.coveragerc
+coverage.xml
+nosetests.xml
+pip-log.txt
 
 # Mac OS X garbage
 .DS_Store
index 328469a..d55c9db 100644 (file)
@@ -53,7 +53,7 @@ def _verify_cas2(ticket, service):
     except:
         import traceback
         traceback.print_exc()
-        print "****"
+        print "****", url
         print response
         print "****"
     finally:
index ec5902d..2173d9e 100644 (file)
@@ -1,10 +1,10 @@
-body {\r
-       font: 12px/16px Arial, Helvetica, sans-serif;\r
-}\r
-#fileQueue {\r
-       width: 400px;\r
-       height: 300px;\r
-       overflow: auto;\r
-       border: 1px solid #E5E5E5;\r
-       margin-bottom: 10px;\r
+body {
+       font: 12px/16px Arial, Helvetica, sans-serif;
+}
+#fileQueue {
+       width: 400px;
+       height: 300px;
+       overflow: auto;
+       border: 1px solid #E5E5E5;
+       margin-bottom: 10px;
 }
\ No newline at end of file
index 0cf8c0e..754de06 100644 (file)
@@ -1,53 +1,53 @@
-/*\r
-Uploadify v2.1.0\r
-Release Date: August 24, 2009\r
-\r
-Copyright (c) 2009 Ronnie Garcia, Travis Nickels\r
-\r
-Permission is hereby granted, free of charge, to any person obtaining a copy\r
-of this software and associated documentation files (the "Software"), to deal\r
-in the Software without restriction, including without limitation the rights\r
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
-copies of the Software, and to permit persons to whom the Software is\r
-furnished to do so, subject to the following conditions:\r
-\r
-The above copyright notice and this permission notice shall be included in\r
-all copies or substantial portions of the Software.\r
-\r
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r
-THE SOFTWARE.\r
-*/\r
-.uploadifyQueueItem {\r
-       font: 11px Verdana, Geneva, sans-serif;\r
-       border: 2px solid #E5E5E5;\r
-       background-color: #F5F5F5;\r
-       margin-top: 5px;\r
-       padding: 10px;\r
-       width: 350px;\r
-}\r
-.uploadifyError {\r
-       border: 2px solid #FBCBBC !important;\r
-       background-color: #FDE5DD !important;\r
-}\r
-.uploadifyQueueItem .cancel {\r
-       float: right;\r
-}\r
-.uploadifyProgress {\r
-       background-color: #FFFFFF;\r
-       border-top: 1px solid #808080;\r
-       border-left: 1px solid #808080;\r
-       border-right: 1px solid #C5C5C5;\r
-       border-bottom: 1px solid #C5C5C5;\r
-       margin-top: 10px;\r
-       width: 100%;\r
-}\r
-.uploadifyProgressBar {\r
-       background-color: #0099FF;\r
-       width: 1px;\r
-       height: 3px;\r
+/*
+Uploadify v2.1.0
+Release Date: August 24, 2009
+
+Copyright (c) 2009 Ronnie Garcia, Travis Nickels
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+.uploadifyQueueItem {
+       font: 11px Verdana, Geneva, sans-serif;
+       border: 2px solid #E5E5E5;
+       background-color: #F5F5F5;
+       margin-top: 5px;
+       padding: 10px;
+       width: 350px;
+}
+.uploadifyError {
+       border: 2px solid #FBCBBC !important;
+       background-color: #FDE5DD !important;
+}
+.uploadifyQueueItem .cancel {
+       float: right;
+}
+.uploadifyProgress {
+       background-color: #FFFFFF;
+       border-top: 1px solid #808080;
+       border-left: 1px solid #808080;
+       border-right: 1px solid #C5C5C5;
+       border-bottom: 1px solid #C5C5C5;
+       margin-top: 10px;
+       width: 100%;
+}
+.uploadifyProgressBar {
+       background-color: #0099FF;
+       width: 1px;
+       height: 3px;
 }
\ No newline at end of file
index 0cf8c0e..754de06 100644 (file)
@@ -1,53 +1,53 @@
-/*\r
-Uploadify v2.1.0\r
-Release Date: August 24, 2009\r
-\r
-Copyright (c) 2009 Ronnie Garcia, Travis Nickels\r
-\r
-Permission is hereby granted, free of charge, to any person obtaining a copy\r
-of this software and associated documentation files (the "Software"), to deal\r
-in the Software without restriction, including without limitation the rights\r
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
-copies of the Software, and to permit persons to whom the Software is\r
-furnished to do so, subject to the following conditions:\r
-\r
-The above copyright notice and this permission notice shall be included in\r
-all copies or substantial portions of the Software.\r
-\r
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r
-THE SOFTWARE.\r
-*/\r
-.uploadifyQueueItem {\r
-       font: 11px Verdana, Geneva, sans-serif;\r
-       border: 2px solid #E5E5E5;\r
-       background-color: #F5F5F5;\r
-       margin-top: 5px;\r
-       padding: 10px;\r
-       width: 350px;\r
-}\r
-.uploadifyError {\r
-       border: 2px solid #FBCBBC !important;\r
-       background-color: #FDE5DD !important;\r
-}\r
-.uploadifyQueueItem .cancel {\r
-       float: right;\r
-}\r
-.uploadifyProgress {\r
-       background-color: #FFFFFF;\r
-       border-top: 1px solid #808080;\r
-       border-left: 1px solid #808080;\r
-       border-right: 1px solid #C5C5C5;\r
-       border-bottom: 1px solid #C5C5C5;\r
-       margin-top: 10px;\r
-       width: 100%;\r
-}\r
-.uploadifyProgressBar {\r
-       background-color: #0099FF;\r
-       width: 1px;\r
-       height: 3px;\r
+/*
+Uploadify v2.1.0
+Release Date: August 24, 2009
+
+Copyright (c) 2009 Ronnie Garcia, Travis Nickels
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+.uploadifyQueueItem {
+       font: 11px Verdana, Geneva, sans-serif;
+       border: 2px solid #E5E5E5;
+       background-color: #F5F5F5;
+       margin-top: 5px;
+       padding: 10px;
+       width: 350px;
+}
+.uploadifyError {
+       border: 2px solid #FBCBBC !important;
+       background-color: #FDE5DD !important;
+}
+.uploadifyQueueItem .cancel {
+       float: right;
+}
+.uploadifyProgress {
+       background-color: #FFFFFF;
+       border-top: 1px solid #808080;
+       border-left: 1px solid #808080;
+       border-right: 1px solid #C5C5C5;
+       border-bottom: 1px solid #C5C5C5;
+       margin-top: 10px;
+       width: 100%;
+}
+.uploadifyProgressBar {
+       background-color: #0099FF;
+       width: 1px;
+       height: 3px;
 }
\ No newline at end of file
index e69de29..c53f0e7 100644 (file)
@@ -0,0 +1 @@
+  # pragma: no cover
index 6f69fb9..283ab78 100644 (file)
@@ -22,7 +22,7 @@ class ButtonAdmin(admin.ModelAdmin):
     form = ButtonAdminForm
     list_display = ('slug', 'label', 'tooltip', 'accesskey')
     list_display_links = ('slug',)
-    list_editable = ('label', 'tooltip',)
+    list_editable = ('label', 'tooltip', 'accesskey')
     prepopulated_fields = {'slug': ('label',)}
 
 admin.site.register(models.Button, ButtonAdmin)
index 723732d..c7b5af6 100644 (file)
@@ -38,8 +38,8 @@
     model: toolbar.buttongroup
     pk: 17
 -   fields:
-        group: [14, 12]
         accesskey: a
+        group: [14, 12]
         label: akapit
         link: ''
         params: '{"tag": "akap"}'
@@ -49,8 +49,8 @@
     model: toolbar.button
     pk: 39
 -   fields:
-        group: [14]
         accesskey: ''
+        group: [14]
         label: akapit cd.
         link: ''
         params: '{"tag": "akap_cd"}'
@@ -60,8 +60,8 @@
     model: toolbar.button
     pk: 40
 -   fields:
-        group: [14]
         accesskey: d
+        group: [14]
         label: akapit dialogowy
         link: ''
         params: '{"tag": "akap_dialog"}'
@@ -71,8 +71,8 @@
     model: toolbar.button
     pk: 41
 -   fields:
-        group: [1]
         accesskey: ''
+        group: [1]
         label: akt
         link: ''
         params: '{"tag": "akt"}'
@@ -82,8 +82,8 @@
     model: toolbar.button
     pk: 14
 -   fields:
-        group: [13]
         accesskey: ''
+        group: [13]
         label: autor
         link: ''
         params: '{"tag": "autor_utworu"}'
     model: toolbar.button
     pk: 32
 -   fields:
-        group: [2]
         accesskey: ''
+        group: [2]
         label: Podstawowa
         link: ''
         params: '[["fulltextregexp", {"exprs": [["\ufeff", ""], ["$[\\s]*\\d+[\\s]*^",
-            ""], ["-\\s*^", ""], ["\\,\\.\\.|\\.\\,\\.|\\.\\.\\,", "..."]]}], ["lineregexp",
-            {"exprs": [["^\\s+|\\s+$", ""], ["\\s+", " "], ["(,,)\\s+|\\s+(\")", "$1"],
-            ["(\\d)[\u2014-](\\d)", "$1--$2"], ["[\u2014]", "---"], ["<(/?)P([aert])",
-            "<$1p$2"], ["([^\\.])(\\s*)</p", "$1.$2</p"], ["([,\\.:;!\\?])([^\\s\\\\])",
-            "$1 $2"], ["([^\\s])\\s+([,\\.:;!\\?])", "$1$2"]]}]]'
+            ""], ["-\\s*^", ""], ["\\,\\.\\.|\\.\\,\\.|\\.\\.\\,", "..."], ["<(/?)P([aert])",
+            "<$1p$2"], ["[\u2014\u2013\u2010-]+", "---"], ["(\\d)---(\\d)", "$1--$2"],
+            ["(\\S)---(\\S)", "$1-$2"]]}], ["lineregexp", {"exprs": [["^\\s+|\\s+$",
+            ""], ["\\s+", " "], ["(,,)\\s+", "$1"], ["\\s+(\")", "$1"], ["([^\\.])(\\s*)</p",
+            "$1.$2</p"], ["([,\\.:;!\\?])([^\\s\\\\])", "$1 $2"], ["([^\\s])\\s+([,\\.:;!\\?])",
+            "$1$2"]]}]]'
         scriptlet: macro
         slug: basic_correction
-        tooltip: "Wykonuj\u0119 operacj\u0119 z novel-pages i poem-pages."
+        tooltip: "Wykonuj\u0119 podstawow\u0105 korekt\u0119 tekstu."
     model: toolbar.button
     pk: 4
 -   fields:
-        group: [2]
         accesskey: ''
+        group: [2]
         label: "zamiana cudzys\u0142ow\xF3w 1"
         link: ''
         params: '{"exprs": [["\u00ab|\u201e", ",,"], ["\u00bb", "\""], ["([^=])\"([\u0104\u0118\u00d3\u0141\u017b\u0179\u0106\u0143\u0105\u017c\u017a\u015b\u0144\u00f3\u0142\u0107\\w])",
     model: toolbar.button
     pk: 89
 -   fields:
-        group: [2]
         accesskey: ''
+        group: [2]
         label: "zamiana cudzys\u0142ow\xF3w 2"
         link: ''
         params: '{"exprs": [["\u00bb|\u201e", ",,"], ["\u00ab", "\""], ["([^=])\"([\u0104\u0118\u00d3\u0141\u017b\u0179\u0106\u0143\u0105\u017c\u017a\u015b\u0144\u00f3\u0142\u0107\\w])",
     model: toolbar.button
     pk: 77
 -   fields:
-        group: [1]
         accesskey: ''
+        group: [1]
         label: "cz\u0119\u015B\u0107/ksi\u0119ga"
         link: ''
         params: '{"tag": "naglowek_czesc"}'
     model: toolbar.button
     pk: 10
 -   fields:
-        group: [13, 22]
         accesskey: ''
+        group: [13, 22]
         label: dedykacja
         link: ''
         params: '{"tag": "dedykacja"}'
     model: toolbar.button
     pk: 74
 -   fields:
-        group: [12]
         accesskey: ''
+        group: [12]
         label: didaskalia
         link: ''
         params: '{"tag": "didaskalia"}'
     model: toolbar.button
     pk: 62
 -   fields:
-        group: [22]
         accesskey: ''
+        group: [22]
         label: "didaskalia pocz\u0105tkowe"
         link: ''
         params: '{"tag": "miejsce_czas"}'
     model: toolbar.button
     pk: 79
 -   fields:
-        group: [12]
         accesskey: ''
+        group: [12]
         label: didaskalia tekstowe
         link: ''
         params: '{"tag": "didask_tekst"}'
     model: toolbar.button
     pk: 63
 -   fields:
-        group: [21]
         accesskey: ''
+        group: [21]
         label: "d\u0142ugi cyt. poet."
         link: ''
         params: '{"tag": "poezja_cyt"}'
     model: toolbar.button
     pk: 67
 -   fields:
-        group: [21]
         accesskey: ''
+        group: [21]
         label: "d\u0142ugi cytat"
         link: ''
         params: '{"tag": "dlugi_cyt"}'
     model: toolbar.button
     pk: 42
 -   fields:
-        group: [11]
         accesskey: ''
+        group: [11]
         label: dramat wiersz.
         link: ''
         params: '{"tag": "dramat_wierszowany_l"}'
     model: toolbar.button
     pk: 20
 -   fields:
-        group: [11]
         accesskey: ''
+        group: [11]
         label: "dramat wiersz./w. \u0142am"
         link: ''
         params: '{"tag": "dramat_wierszowany_lp"}'
     model: toolbar.button
     pk: 22
 -   fields:
-        group: [11]
         accesskey: ''
+        group: [11]
         label: "dramat wsp\xF3\u0142czesny"
         link: ''
         params: '{"tag": "dramat_wspolczesny"}'
     model: toolbar.button
     pk: 21
 -   fields:
-        group: [13]
         accesskey: ''
+        group: [13]
         label: "dzie\u0142o nadrz\u0119dne"
         link: ''
         params: '{"tag": "dzielo_nadrzedne"}'
     model: toolbar.button
     pk: 38
 -   fields:
-        group: [27]
         accesskey: ''
+        group: [27]
         label: extra
         link: ''
         params: '{"tag": "extra"}'
     model: toolbar.button
     pk: 96
 -   fields:
-        group: []
         accesskey: ''
+        group: []
         label: Wydrukuj
         link: print/html
         params: '[]'
     model: toolbar.button
     pk: 87
 -   fields:
-        group: [12]
         accesskey: k
+        group: [12]
         label: kwestia
         link: ''
         params: '{"tag": "kwestia"}'
     model: toolbar.button
     pk: 82
 -   fields:
-        group: [11]
         accesskey: ''
+        group: [11]
         label: liryka
         link: ''
         params: '{"tag": "liryka_l"}'
     model: toolbar.button
     pk: 23
 -   fields:
-        group: [11]
         accesskey: ''
+        group: [11]
         label: "liryka/w. \u0142am"
         link: ''
         params: '{"tag": "liryka_lp"}'
     model: toolbar.button
     pk: 24
 -   fields:
-        group: [22]
         accesskey: ''
+        group: [22]
         label: "lista os\xF3b"
         link: ''
         params: '{"tag": "lista_osob"}'
     model: toolbar.button
     pk: 93
 -   fields:
-        group: [22]
         accesskey: ''
+        group: [22]
         label: 'typ osoby '
         link: ''
         params: '{"tag": "lista_osoba", "attrs": {"typ": ""}}'
     model: toolbar.button
     pk: 78
 -   fields:
-        group: [15]
         accesskey: ''
+        group: [15]
         label: matemat.
         link: ''
         params: '{"tag": "mat"}'
     model: toolbar.button
     pk: 47
 -   fields:
-        group: [13, 22]
         accesskey: ''
+        group: [13, 22]
         label: motto
         link: ''
         params: '{"tag": "motto"}'
     model: toolbar.button
     pk: 75
 -   fields:
-        group: [13, 22]
         accesskey: ''
+        group: [13, 22]
         label: motto podpis
         link: ''
         params: '{"tag": "motto_podpis"}'
     model: toolbar.button
     pk: 37
 -   fields:
-        group: [12]
         accesskey: ''
+        group: [2]
+        label: ",,\u2026\" na \xAB\u2026\xBB"
+        link: ''
+        params: '{"exprs": [[",,", "\u00ab"], ["\"", "\u00bb"]]}'
+        scriptlet: fulltextregexp
+        slug: na-francuskie
+        tooltip: "Zamienia cudzys\u0142owy podw\xF3jne na francuskie"
+    model: toolbar.button
+    pk: 2
+-   fields:
+        accesskey: ''
+        group: [2]
+        label: ",,\u2026\" na \xBB\u2026\xAB"
+        link: ''
+        params: '{"exprs": [[",,", "\u00bb"], ["\"", "\u00ab"]]}'
+        scriptlet: fulltextregexp
+        slug: na-niemieckie
+        tooltip: "Zamienia cudzys\u0142owy podw\xF3jne na niemieckie"
+    model: toolbar.button
+    pk: 3
+-   fields:
+        accesskey: ''
+        group: [12]
         label: "nag\u0142\xF3wek kwestii"
         link: ''
         params: '{"tag": "naglowek_osoba"}'
     model: toolbar.button
     pk: 16
 -   fields:
-        group: [22]
         accesskey: ''
+        group: [22]
         label: "nag\u0142\xF3wek listy"
         link: ''
         params: '{"tag": "naglowek_listy"}'
     model: toolbar.button
     pk: 94
 -   fields:
-        group: [13]
         accesskey: ''
+        group: [13]
         label: nazwa utworu
         link: ''
         params: '{"tag": "nazwa_utworu"}'
     model: toolbar.button
     pk: 33
 -   fields:
-        group: [13]
         accesskey: ''
+        group: [13]
         label: nota
         link: ''
         params: '{"tag": "nota"}'
     model: toolbar.button
     pk: 35
 -   fields:
-        group: [11]
         accesskey: ''
+        group: [11]
         label: opowiadanie
         link: ''
         params: '{"tag": "opowiadanie"}'
     model: toolbar.button
     pk: 18
 -   fields:
-        group: [12]
         accesskey: b
+        group: [12]
         label: osoba
         link: ''
         params: '{"tag": "osoba"}'
     model: toolbar.button
     pk: 64
 -   fields:
-        group: [22]
         accesskey: ''
+        group: [22]
         label: osoba na liscie
         link: ''
         params: '{"tag": "lista_osoba"}'
     model: toolbar.button
     pk: 95
 -   fields:
-        group: [1]
         accesskey: ''
+        group: [1]
         label: "podrozdzia\u0142"
         link: ''
         params: '{"tag": "naglowek_podrozdzial"}'
     model: toolbar.button
     pk: 12
 -   fields:
-        group: [1]
         accesskey: ''
+        group: [1]
         label: "podtytu\u0142"
         link: ''
         params: '{"tag": "podtytul"}'
     model: toolbar.button
     pk: 34
 -   fields:
-        group: [11]
         accesskey: ''
+        group: [11]
         label: "powie\u015B\u0107"
         link: ''
         params: '{"tag": "powiesc"}'
     model: toolbar.button
     pk: 19
 -   fields:
-        group: []
         accesskey: ''
+        group: []
         label: Wydrukuj
         link: print/xml
         params: '[]'
     model: toolbar.button
     pk: 86
 -   fields:
-        group: [26]
         accesskey: ''
+        group: [26]
         label: przypis autorski
         link: ''
         params: '{"tag": "pa"}'
     model: toolbar.button
     pk: 68
 -   fields:
-        group: [26]
         accesskey: ''
+        group: [26]
         label: przypis edytorski
         link: ''
         params: '{"tag": "pe"}'
     model: toolbar.button
     pk: 71
 -   fields:
-        group: [26]
         accesskey: ''
+        group: [26]
         label: przypis redaktorski
         link: ''
         params: '{"tag": "pr"}'
     model: toolbar.button
     pk: 70
 -   fields:
-        group: [26]
         accesskey: ''
+        group: [26]
         label: "przypis t\u0142umacza"
         link: ''
         params: '{"tag": "pt"}'
     model: toolbar.button
     pk: 69
 -   fields:
-        group: [1]
         accesskey: ''
+        group: [1]
         label: "rozdzia\u0142"
         link: ''
         params: '{"tag": "naglowek_rozdzial"}'
     model: toolbar.button
     pk: 11
 -   fields:
-        group: [1]
         accesskey: ''
+        group: [1]
         label: scena
         link: ''
         params: '{"tag": "naglowek_scena"}'
     model: toolbar.button
     pk: 15
 -   fields:
-        group: [16]
         accesskey: ''
+        group: [16]
         label: asterysk
         link: ''
         params: '{"nocontent": "true", "tag": "sekcja_asterysk"}'
     model: toolbar.button
     pk: 54
 -   fields:
-        group: [16]
         accesskey: ''
+        group: [16]
         label: linia
         link: ''
         params: '{"nocontent": "true", "tag": "separator_linia"}'
     model: toolbar.button
     pk: 55
 -   fields:
-        group: [16]
         accesskey: ''
+        group: [16]
         label: "\u015Bwiat\u0142o"
         link: ''
         params: '{"nocontent": "true", "tag": "sekcja_swiatlo"}'
     model: toolbar.button
     pk: 53
 -   fields:
-        group: [15]
         accesskey: ''
+        group: [15]
         label: "s\u0142owo obce"
         link: ''
         params: '{"tag": "slowo_obce"}'
     model: toolbar.button
     pk: 46
 -   fields:
-        group: [1]
         accesskey: ''
+        group: [1]
         label: "\u015Br\xF3dtytu\u0142"
         link: ''
         params: '{"tag": "srodtytul"}'
     model: toolbar.button
     pk: 13
 -   fields:
-        group: [2]
-        accesskey: ''
-        label: "Usu\u0144 spacj\u0119"
-        link: ''
-        params: '{"exprs": [["^\\s+|\\s+$", ""], ["\\s+", " "], ["(,,)\\s+", "$1"],
-            ["\\s+(\")", "$1"]]}'
-        scriptlet: lineregexp
-        slug: strip_whitespace
-        tooltip: "Usuwa zb\u0119dne spacj\u0119 z dokumentu."
-    model: toolbar.button
-    pk: 3
--   fields:
-        group: [12, 17]
         accesskey: s
+        group: [12, 17]
         label: strofa
         link: ''
         params: '{"tag": "strofa"}'
     model: toolbar.button
     pk: 81
 -   fields:
-        group: [11]
         accesskey: ''
+        group: [11]
         label: "tag g\u0142\xF3wny"
         link: ''
         params: '{"tag": "utwor"}'
     model: toolbar.button
     pk: 17
 -   fields:
-        group: [2]
         accesskey: u
+        group: [2]
         label: "A<sup>\u2193</sup>"
         link: ''
         params: '[]'
     model: toolbar.button
     pk: 76
 -   fields:
-        group: [15]
         accesskey: ''
+        group: [15]
         label: "tytu\u0142 dzie\u0142a"
         link: ''
         params: '{"tag": "tytul_dziela"}'
     model: toolbar.button
     pk: 92
 -   fields:
-        group: [15]
         accesskey: ''
+        group: [15]
         label: "tytu\u0142 dzie\u0142a typ 1"
         link: ''
         params: '{"tag": "tytul_dziela", "attrs": {"typ": "1"}}'
     model: toolbar.button
     pk: 45
 -   fields:
-        group: [27]
         accesskey: ''
+        group: [27]
         label: uwaga
         link: ''
         params: '{"tag": "uwaga"}'
     model: toolbar.button
     pk: 51
 -   fields:
-        group: [14, 17]
         accesskey: ''
+        group: [14, 17]
         label: wers akap.
         link: ''
         params: '{"tag": "wers_akap"}'
     model: toolbar.button
     pk: 83
 -   fields:
-        group: [12, 17]
         accesskey: ''
+        group: [12, 17]
         label: wers cd.
         link: ''
         params: '{"tag": "wers_cd"}'
     model: toolbar.button
     pk: 85
 -   fields:
-        group: [12, 17]
         accesskey: w
+        group: [12, 17]
         label: "wers mocno wci\u0119ty"
         link: ''
         params: '{"tag": "wers_wciety", "attrs": {"typ": ""}}'
     model: toolbar.button
     pk: 84
 -   fields:
-        group: [12, 17]
         accesskey: q
+        group: [12, 17]
         label: "wers wci\u0119ty"
         link: ''
         params: '{"tag": "wers_wciety", "attrs": {"typ": "1"}}'
     model: toolbar.button
     pk: 91
 -   fields:
-        group: [15]
         accesskey: ''
+        group: [15]
         label: www
         link: ''
         params: '{"tag": "www"}'
     model: toolbar.button
     pk: 48
 -   fields:
-        group: [15]
         accesskey: ''
+        group: [15]
         label: "wyr\xF3\u017Cnienie"
         link: ''
         params: '{"tag": "wyroznienie"}'
     model: toolbar.button
     pk: 44
 -   fields:
-        group: [11]
         accesskey: ''
+        group: [11]
         label: wywiad
         link: ''
         params: '{"tag": "wywiad"}'
     model: toolbar.button
     pk: 25
 -   fields:
-        group: [21]
         accesskey: ''
+        group: [21]
         label: "wywiad odpowied\u017A"
         link: ''
         params: '{"tag": "wywiad_odp"}'
     model: toolbar.button
     pk: 73
 -   fields:
-        group: [21]
         accesskey: ''
+        group: [21]
         label: wywiad pytanie
         link: ''
         params: '{"tag": "wywiad_pyt"}'
     model: toolbar.button
     pk: 72
 -   fields:
-        group: [2]
         accesskey: ''
-        label: "Zamie\u0144 dywiz"
-        link: ''
-        params: '{"exprs": [["(\\s)-(\\s)", "$1---$2"], ["^(\\s*)-(\\s)", "$1---$2"],
-            ["(\\s)-(\\s*)$", "$1---$2"], ["(\\d)[\u2014\u2013\u2010-](\\d)", "$1--$2"],
-            ["\u2014\u2013\u2010", "---"]]}'
-        scriptlet: lineregexp
-        slug: zamien_dywiz
-        tooltip: "Zamienia '\u2014' na '---', oraz '1\u20142' na '1--2'."
-    model: toolbar.button
-    pk: 2
--   fields:
         group: [16]
-        accesskey: ''
         label: "zast\u0119pnik wersu"
         link: ''
         params: '{"tag": "zastepnik_wersu"}'
             \r\n\r\n\r\n\r\n\r\n\r\n\r\npanel.fireEvent('contentChanged');"}
     model: toolbar.scriptlet
     pk: insert_stanza
-
diff --git a/apps/toolbar/locale/pl/LC_MESSAGES/django.mo b/apps/toolbar/locale/pl/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..54dabdf
Binary files /dev/null and b/apps/toolbar/locale/pl/LC_MESSAGES/django.mo differ
diff --git a/apps/toolbar/locale/pl/LC_MESSAGES/django.po b/apps/toolbar/locale/pl/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..8c7cfb1
--- /dev/null
@@ -0,0 +1,37 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-08-03 12:14+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: models.py:17
+msgid "button group"
+msgstr "grupa przycisków"
+
+#: models.py:17
+msgid "button groups"
+msgstr "grupy przycisków"
+
+#: models.py:51
+msgid "button"
+msgstr "przycisk"
+
+#: models.py:51
+msgid "buttons"
+msgstr "przyciski"
+
+#: models.py:75
+msgid "javascript"
+msgstr ""
index a43cb93..cdffcaf 100644 (file)
@@ -1,5 +1,5 @@
 {% if button.link %}
-<a href="{{button.link}}" target="_new">
+<a href="{{button.link}}" target="_blank">
 {% endif %}
 <button type="button"
        data-ui-action="{{ button.scriptlet_id }}"
index fd8be78..b9624d6 100644 (file)
@@ -1,20 +1,21 @@
 {% load toolbar_tags %}
 <div class="toolbar">
-    <select name="button_group" id="toolbar-button-group-select" size="1">
+    <select class="group_selector">
         {% for group in toolbar_groups %}
         <option value="{{ group.slug }}" {% if forloop.first %}selected="selected"{% endif %}>{{ group.name }}</option>
         {% endfor %}
     </select>
 
-    <div class="toolbar-button-groups-container">
+       <button type="button" class="prev">&lt;</button>
+    <div class="button_group_container">
         {% for group in toolbar_groups %}
-        <div data-group="{{group.slug}}" class="toolbar-buttons-container">
+        <ul data-group="{{ group.slug }}" class="button_group">
             {# buttons for this group #}
             {% for button in group.button_set.all %}
-            {% toolbar_button button %}
+               <li class="toolbar-button">{% toolbar_button button %}</li>
             {% endfor %}
-        </div>
+        </ul>
         {% endfor %}
     </div>
-    <div class="toolbar-end"></div>
+    <button type="button" class="next">&gt;</button>
 </div>
index e69de29..c53f0e7 100644 (file)
@@ -0,0 +1 @@
+  # pragma: no cover
diff --git a/apps/wiki/admin.py b/apps/wiki/admin.py
new file mode 100644 (file)
index 0000000..1a61b66
--- /dev/null
@@ -0,0 +1,5 @@
+from django.contrib import admin
+
+from wiki import models
+
+admin.site.register(models.Theme)
index 472bbb6..de6d0e2 100644 (file)
@@ -1,24 +1,20 @@
 # -*- coding: utf-8 -*-
 from django.utils.translation import ugettext_lazy as _
 
-DOCUMENT_TAGS = (
-    ("source", _(u"Tekst źródłowy")),
-    ("first_correction", _(u"Po autokorekcie")),
-    ("tagged", _(u"Tekst otagowany")),
-    ("second_correction", _(u"Po korekcie")),
-    ("source_annotations", _(u"Sprawdzone przypisy źródła")),
-    ("language_updates", _(u"Uwspółcześnienia")),
-    ("ready_to_publish", _(u"Tekst do publikacji")),
-)
-
-DOCUMENT_TAGS_DICT = dict(DOCUMENT_TAGS)
-
 DOCUMENT_STAGES = (
-    ("first_correction", _(u"Autokorekta")),
-    ("tagged", _(u"Tagowanie")),
-    ("second_correction", _(u"Korekta")),
-    ("source_annotations", _(u"Przypisy źródła")),
-    ("language_updates", _(u"Uwspółcześnienia")),
+    ("", u"-----"),
+    ("first_correction", _(u"First correction")),
+    ("tagging", _(u"Tagging")),
+    ("proofreading", _(u"Initial Proofreading")),
+    ("annotation-proofreading", _(u"Annotation Proofreading")),
+    ("modernisation", _(u"Modernisation")),
+    ("themes", _(u"Themes")),
+    ("editor-proofreading", _(u"Editor's Proofreading")),
+    ("technical-editor-proofreading", _(u"Technical Editor's Proofreading")),
 )
 
+DOCUMENT_TAGS = DOCUMENT_STAGES + \
+    (("ready-to-publish", _(u"Ready to publish")),)
+
+DOCUMENT_TAGS_DICT = dict(DOCUMENT_TAGS)
 DOCUMENT_STAGES_DICT = dict(DOCUMENT_STAGES)
diff --git a/apps/wiki/fixtures/initial_themes.yaml b/apps/wiki/fixtures/initial_themes.yaml
new file mode 100644 (file)
index 0000000..fc0b773
--- /dev/null
@@ -0,0 +1,1246 @@
+- fields: {name: Alkohol}
+  model: wiki.theme
+  pk: 1
+- fields: {name: Ambicja}
+  model: wiki.theme
+  pk: 2
+- fields: {name: "Anio\u0142"}
+  model: wiki.theme
+  pk: 3
+- fields: {name: Antysemityzm}
+  model: wiki.theme
+  pk: 4
+- fields: {name: Arkadia}
+  model: wiki.theme
+  pk: 5
+- fields: {name: Artysta}
+  model: wiki.theme
+  pk: 6
+- fields: {name: "Bezdomno\u015B\u0107"}
+  model: wiki.theme
+  pk: 7
+- fields: {name: "Bezpiecze\u0144stwo"}
+  model: wiki.theme
+  pk: 8
+- fields: {name: Bieda}
+  model: wiki.theme
+  pk: 9
+- fields: {name: Bijatyka}
+  model: wiki.theme
+  pk: 10
+- fields: {name: Bogactwo}
+  model: wiki.theme
+  pk: 14
+- fields: {name: Brat}
+  model: wiki.theme
+  pk: 16
+- fields: {name: Bunt}
+  model: wiki.theme
+  pk: 17
+- fields: {name: Buntownik}
+  model: wiki.theme
+  pk: 18
+- fields: {name: Burza}
+  model: wiki.theme
+  pk: 19
+- fields: {name: "B\xF3g"}
+  model: wiki.theme
+  pk: 15
+- fields: {name: "B\u0142azen"}
+  model: wiki.theme
+  pk: 11
+- fields: {name: "B\u0142oto"}
+  model: wiki.theme
+  pk: 13
+- fields: {name: "B\u0142\u0105dzenie"}
+  model: wiki.theme
+  pk: 12
+- fields: {name: Car}
+  model: wiki.theme
+  pk: 20
+- fields: {name: Carpe diem}
+  model: wiki.theme
+  pk: 21
+- fields: {name: "Chciwo\u015B\u0107"}
+  model: wiki.theme
+  pk: 25
+- fields: {name: Chleb}
+  model: wiki.theme
+  pk: 26
+- fields: {name: Choroba}
+  model: wiki.theme
+  pk: 28
+- fields: {name: Chrystus}
+  model: wiki.theme
+  pk: 29
+- fields: {name: Chrzest}
+  model: wiki.theme
+  pk: 30
+- fields: {name: "Ch\u0142op"}
+  model: wiki.theme
+  pk: 27
+- fields: {name: "Cia\u0142o"}
+  model: wiki.theme
+  pk: 31
+- fields: {name: "Ciemno\u015B\u0107"}
+  model: wiki.theme
+  pk: 22
+- fields: {name: Cierpienie}
+  model: wiki.theme
+  pk: 32
+- fields: {name: "Cie\u0144"}
+  model: wiki.theme
+  pk: 23
+- fields: {name: Cisza}
+  model: wiki.theme
+  pk: 24
+- fields: {name: Cmentarz}
+  model: wiki.theme
+  pk: 33
+- fields: {name: Cnota}
+  model: wiki.theme
+  pk: 34
+- fields: {name: Cud}
+  model: wiki.theme
+  pk: 36
+- fields: {name: Czarownica}
+  model: wiki.theme
+  pk: 37
+- fields: {name: Czary}
+  model: wiki.theme
+  pk: 38
+- fields: {name: Czas}
+  model: wiki.theme
+  pk: 39
+- fields: {name: Czyn}
+  model: wiki.theme
+  pk: 40
+- fields: {name: "Czy\u015Bciec"}
+  model: wiki.theme
+  pk: 41
+- fields: {name: "C\xF3rka"}
+  model: wiki.theme
+  pk: 35
+- fields: {name: Dama}
+  model: wiki.theme
+  pk: 42
+- fields: {name: Danse macabre}
+  model: wiki.theme
+  pk: 43
+- fields: {name: Deszcz}
+  model: wiki.theme
+  pk: 44
+- fields: {name: "Diabe\u0142"}
+  model: wiki.theme
+  pk: 45
+- fields: {name: Dobro}
+  model: wiki.theme
+  pk: 46
+- fields: {name: Dom}
+  model: wiki.theme
+  pk: 47
+- fields: {name: "Doros\u0142o\u015B\u0107"}
+  model: wiki.theme
+  pk: 48
+- fields: {name: Drzewo}
+  model: wiki.theme
+  pk: 49
+- fields: {name: Duch}
+  model: wiki.theme
+  pk: 50
+- fields: {name: Duma}
+  model: wiki.theme
+  pk: 52
+- fields: {name: Dusza}
+  model: wiki.theme
+  pk: 51
+- fields: {name: Dworek}
+  model: wiki.theme
+  pk: 53
+- fields: {name: Dworzanin}
+  model: wiki.theme
+  pk: 54
+- fields: {name: "Dw\xF3r"}
+  model: wiki.theme
+  pk: 55
+- fields: {name: "Dzieci\u0144stwo"}
+  model: wiki.theme
+  pk: 56
+- fields: {name: Dziecko}
+  model: wiki.theme
+  pk: 57
+- fields: {name: Dziedzictwo}
+  model: wiki.theme
+  pk: 58
+- fields: {name: Dziewictwo}
+  model: wiki.theme
+  pk: 59
+- fields: {name: "D\u017Awi\u0119k"}
+  model: wiki.theme
+  pk: 60
+- fields: {name: Egzorcyzm}
+  model: wiki.theme
+  pk: 61
+- fields: {name: Elita}
+  model: wiki.theme
+  pk: 62
+- fields: {name: Emigrant}
+  model: wiki.theme
+  pk: 63
+- fields: {name: "Fa\u0142sz"}
+  model: wiki.theme
+  pk: 64
+- fields: {name: Filozof}
+  model: wiki.theme
+  pk: 65
+- fields: {name: Fircyk}
+  model: wiki.theme
+  pk: 66
+- fields: {name: Flirt}
+  model: wiki.theme
+  pk: 67
+- fields: {name: Gospodarz}
+  model: wiki.theme
+  pk: 71
+- fields: {name: Gospodyni}
+  model: wiki.theme
+  pk: 72
+- fields: {name: Gotycyzm}
+  model: wiki.theme
+  pk: 74
+- fields: {name: "Go\u015B\u0107"}
+  model: wiki.theme
+  pk: 73
+- fields: {name: Gra}
+  model: wiki.theme
+  pk: 76
+- fields: {name: Grzech}
+  model: wiki.theme
+  pk: 78
+- fields: {name: "Grzeczno\u015B\u0107"}
+  model: wiki.theme
+  pk: 79
+- fields: {name: "Gr\xF3b"}
+  model: wiki.theme
+  pk: 77
+- fields: {name: Gwiazda}
+  model: wiki.theme
+  pk: 80
+- fields: {name: "G\xF3ra"}
+  model: wiki.theme
+  pk: 75
+- fields: {name: "G\u0142upiec"}
+  model: wiki.theme
+  pk: 68
+- fields: {name: "G\u0142upota"}
+  model: wiki.theme
+  pk: 69
+- fields: {name: "G\u0142\xF3d"}
+  model: wiki.theme
+  pk: 70
+- fields: {name: Handel}
+  model: wiki.theme
+  pk: 81
+- fields: {name: "Ha\u0144ba"}
+  model: wiki.theme
+  pk: 82
+- fields: {name: Historia}
+  model: wiki.theme
+  pk: 83
+- fields: {name: Honor}
+  model: wiki.theme
+  pk: 84
+- fields: {name: Idealista}
+  model: wiki.theme
+  pk: 85
+- fields: {name: "Imi\u0119"}
+  model: wiki.theme
+  pk: 86
+- fields: {name: Interes}
+  model: wiki.theme
+  pk: 87
+- fields: {name: "Jab\u0142ka"}
+  model: wiki.theme
+  pk: 88
+- fields: {name: Jedzenie}
+  model: wiki.theme
+  pk: 89
+- fields: {name: "Jesie\u0144"}
+  model: wiki.theme
+  pk: 90
+- fields: {name: Kaleka}
+  model: wiki.theme
+  pk: 91
+- fields: {name: Kara}
+  model: wiki.theme
+  pk: 92
+- fields: {name: Karczma}
+  model: wiki.theme
+  pk: 93
+- fields: {name: "Kl\u0119ska"}
+  model: wiki.theme
+  pk: 94
+- fields: {name: Kobieta}
+  model: wiki.theme
+  pk: 97
+- fields: {name: "Kobieta \"upad\u0142a\""}
+  model: wiki.theme
+  pk: 99
+- fields: {name: Kobieta demoniczna}
+  model: wiki.theme
+  pk: 98
+- fields: {name: Kochanek}
+  model: wiki.theme
+  pk: 100
+- fields: {name: Kochanek romantyczny}
+  model: wiki.theme
+  pk: 101
+- fields: {name: Kolonializm}
+  model: wiki.theme
+  pk: 102
+- fields: {name: Kondycja ludzka}
+  model: wiki.theme
+  pk: 103
+- fields: {name: Konflikt}
+  model: wiki.theme
+  pk: 104
+- fields: {name: "Konflikt wewn\u0119trzny"}
+  model: wiki.theme
+  pk: 105
+- fields: {name: "Koniec \u015Bwiata"}
+  model: wiki.theme
+  pk: 106
+- fields: {name: "Korzy\u015B\u0107"}
+  model: wiki.theme
+  pk: 108
+- fields: {name: Kot}
+  model: wiki.theme
+  pk: 109
+- fields: {name: "Ko\u0144"}
+  model: wiki.theme
+  pk: 107
+- fields: {name: "Kradzie\u017C"}
+  model: wiki.theme
+  pk: 110
+- fields: {name: Krew}
+  model: wiki.theme
+  pk: 111
+- fields: {name: Krzywda}
+  model: wiki.theme
+  pk: 113
+- fields: {name: "Kr\xF3l"}
+  model: wiki.theme
+  pk: 112
+- fields: {name: "Ksi\u0105dz"}
+  model: wiki.theme
+  pk: 114
+- fields: {name: "Ksi\u0105\u017Cka"}
+  model: wiki.theme
+  pk: 115
+- fields: {name: "Ksi\u0119\u017Cyc"}
+  model: wiki.theme
+  pk: 116
+- fields: {name: Kuchnia}
+  model: wiki.theme
+  pk: 117
+- fields: {name: Kuszenie}
+  model: wiki.theme
+  pk: 118
+- fields: {name: Kwiaty}
+  model: wiki.theme
+  pk: 119
+- fields: {name: "K\u0142amstwo"}
+  model: wiki.theme
+  pk: 95
+- fields: {name: "K\u0142\xF3tnia"}
+  model: wiki.theme
+  pk: 96
+- fields: {name: Labirynt}
+  model: wiki.theme
+  pk: 120
+- fields: {name: Las}
+  model: wiki.theme
+  pk: 121
+- fields: {name: Lato}
+  model: wiki.theme
+  pk: 122
+- fields: {name: Lekarz}
+  model: wiki.theme
+  pk: 123
+- fields: {name: Lenistwo}
+  model: wiki.theme
+  pk: 124
+- fields: {name: Liberat}
+  model: wiki.theme
+  pk: 126
+- fields: {name: List}
+  model: wiki.theme
+  pk: 125
+- fields: {name: Los}
+  model: wiki.theme
+  pk: 127
+- fields: {name: Lud}
+  model: wiki.theme
+  pk: 128
+- fields: {name: Lustro}
+  model: wiki.theme
+  pk: 129
+- fields: {name: Marzenie}
+  model: wiki.theme
+  pk: 132
+- fields: {name: Maska}
+  model: wiki.theme
+  pk: 133
+- fields: {name: Maszyna}
+  model: wiki.theme
+  pk: 134
+- fields: {name: Matka}
+  model: wiki.theme
+  pk: 135
+- fields: {name: Matka Boska}
+  model: wiki.theme
+  pk: 136
+- fields: {name: "Ma\u0142\u017Ce\u0144stwo"}
+  model: wiki.theme
+  pk: 131
+- fields: {name: Melancholia}
+  model: wiki.theme
+  pk: 139
+- fields: {name: Miasto}
+  model: wiki.theme
+  pk: 142
+- fields: {name: Mieszczanin}
+  model: wiki.theme
+  pk: 143
+- fields: {name: Mizoginia}
+  model: wiki.theme
+  pk: 152
+- fields: {name: "Mi\u0142osierdzie"}
+  model: wiki.theme
+  pk: 144
+- fields: {name: "Mi\u0142o\u015B\u0107"}
+  model: wiki.theme
+  pk: 145
+- fields: {name: "Mi\u0142o\u015B\u0107 niespe\u0142niona"}
+  model: wiki.theme
+  pk: 146
+- fields: {name: "Mi\u0142o\u015B\u0107 platoniczna"}
+  model: wiki.theme
+  pk: 147
+- fields: {name: "Mi\u0142o\u015B\u0107 romantyczna"}
+  model: wiki.theme
+  pk: 148
+- fields: {name: "Mi\u0142o\u015B\u0107 silniejsza ni\u017C \u015Bmier\u0107"}
+  model: wiki.theme
+  pk: 149
+- fields: {name: "Mi\u0142o\u015B\u0107 spe\u0142niona"}
+  model: wiki.theme
+  pk: 150
+- fields: {name: "Mi\u0142o\u015B\u0107 tragiczna"}
+  model: wiki.theme
+  pk: 151
+- fields: {name: Moda}
+  model: wiki.theme
+  pk: 154
+- fields: {name: Modlitwa}
+  model: wiki.theme
+  pk: 155
+- fields: {name: Morderstwo}
+  model: wiki.theme
+  pk: 156
+- fields: {name: Morze}
+  model: wiki.theme
+  pk: 157
+- fields: {name: Motyl}
+  model: wiki.theme
+  pk: 158
+- fields: {name: Mucha}
+  model: wiki.theme
+  pk: 159
+- fields: {name: Muzyka}
+  model: wiki.theme
+  pk: 160
+- fields: {name: "M\u0105dro\u015B\u0107"}
+  model: wiki.theme
+  pk: 137
+- fields: {name: "M\u0105\u017C"}
+  model: wiki.theme
+  pk: 138
+- fields: {name: "M\u0119drzec"}
+  model: wiki.theme
+  pk: 140
+- fields: {name: "M\u0119\u017Cczyzna"}
+  model: wiki.theme
+  pk: 141
+- fields: {name: "M\u0142odo\u015B\u0107"}
+  model: wiki.theme
+  pk: 153
+- fields: {name: Narodziny}
+  model: wiki.theme
+  pk: 161
+- fields: {name: "Nar\xF3d"}
+  model: wiki.theme
+  pk: 162
+- fields: {name: Natura}
+  model: wiki.theme
+  pk: 163
+- fields: {name: Nauczyciel}
+  model: wiki.theme
+  pk: 164
+- fields: {name: Nauczycielka}
+  model: wiki.theme
+  pk: 165
+- fields: {name: Nauka}
+  model: wiki.theme
+  pk: 166
+- fields: {name: "Niebezpiecze\u0144stwo"}
+  model: wiki.theme
+  pk: 167
+- fields: {name: Niedziela}
+  model: wiki.theme
+  pk: 168
+- fields: {name: Niemiec}
+  model: wiki.theme
+  pk: 169
+- fields: {name: "Nienawi\u015B\u0107"}
+  model: wiki.theme
+  pk: 170
+- fields: {name: Niewola}
+  model: wiki.theme
+  pk: 172
+- fields: {name: "Nie\u015Bmiertelno\u015B\u0107"}
+  model: wiki.theme
+  pk: 171
+- fields: {name: Noc}
+  model: wiki.theme
+  pk: 173
+- fields: {name: Nuda}
+  model: wiki.theme
+  pk: 174
+- fields: {name: Obcy}
+  model: wiki.theme
+  pk: 175
+- fields: {name: "Obowi\u0105zek"}
+  model: wiki.theme
+  pk: 177
+- fields: {name: "Obraz \u015Bwiata"}
+  model: wiki.theme
+  pk: 178
+- fields: {name: "Obrz\u0119dy"}
+  model: wiki.theme
+  pk: 179
+- fields: {name: Obyczaje}
+  model: wiki.theme
+  pk: 180
+- fields: {name: Obywatel}
+  model: wiki.theme
+  pk: 181
+- fields: {name: "Ob\u0142ok"}
+  model: wiki.theme
+  pk: 176
+- fields: {name: "Odrodzenie przez gr\xF3b"}
+  model: wiki.theme
+  pk: 182
+- fields: {name: Odwaga}
+  model: wiki.theme
+  pk: 183
+- fields: {name: Ofiara}
+  model: wiki.theme
+  pk: 184
+- fields: {name: "Ogie\u0144"}
+  model: wiki.theme
+  pk: 185
+- fields: {name: "Ogr\xF3d"}
+  model: wiki.theme
+  pk: 186
+- fields: {name: Ojciec}
+  model: wiki.theme
+  pk: 187
+- fields: {name: Ojczyzna}
+  model: wiki.theme
+  pk: 188
+- fields: {name: Oko}
+  model: wiki.theme
+  pk: 189
+- fields: {name: "Okrucie\u0144stwo"}
+  model: wiki.theme
+  pk: 191
+- fields: {name: "Okr\u0119t"}
+  model: wiki.theme
+  pk: 190
+- fields: {name: Omen}
+  model: wiki.theme
+  pk: 192
+- fields: {name: Opieka}
+  model: wiki.theme
+  pk: 193
+- fields: {name: Organizm}
+  model: wiki.theme
+  pk: 194
+- fields: {name: "Otch\u0142a\u0144"}
+  model: wiki.theme
+  pk: 195
+- fields: {name: "O\u015Bwiadczyny"}
+  model: wiki.theme
+  pk: 415
+- fields: {name: "Paj\u0105k"}
+  model: wiki.theme
+  pk: 196
+- fields: {name: "Pami\u0119\u0107"}
+  model: wiki.theme
+  pk: 197
+- fields: {name: Pan}
+  model: wiki.theme
+  pk: 198
+- fields: {name: "Panna m\u0142oda"}
+  model: wiki.theme
+  pk: 199
+- fields: {name: Patriota}
+  model: wiki.theme
+  pk: 201
+- fields: {name: "Pa\u0144stwo"}
+  model: wiki.theme
+  pk: 200
+- fields: {name: "Piek\u0142o"}
+  model: wiki.theme
+  pk: 202
+- fields: {name: Pielgrzym}
+  model: wiki.theme
+  pk: 203
+- fields: {name: "Pieni\u0105dz"}
+  model: wiki.theme
+  pk: 204
+- fields: {name: Pies}
+  model: wiki.theme
+  pk: 205
+- fields: {name: "Pija\u0144stwo"}
+  model: wiki.theme
+  pk: 207
+- fields: {name: Piwnica}
+  model: wiki.theme
+  pk: 208
+- fields: {name: "Pi\u0119tno"}
+  model: wiki.theme
+  pk: 206
+- fields: {name: Plotka}
+  model: wiki.theme
+  pk: 209
+- fields: {name: "Pobo\u017Cno\u015B\u0107"}
+  model: wiki.theme
+  pk: 210
+- fields: {name: "Poca\u0142unek"}
+  model: wiki.theme
+  pk: 211
+- fields: {name: Pochlebstwo}
+  model: wiki.theme
+  pk: 212
+- fields: {name: "Podr\xF3\u017C"}
+  model: wiki.theme
+  pk: 216
+- fields: {name: "Podst\u0119p"}
+  model: wiki.theme
+  pk: 217
+- fields: {name: Poeta}
+  model: wiki.theme
+  pk: 213
+- fields: {name: Poetka}
+  model: wiki.theme
+  pk: 214
+- fields: {name: Poezja}
+  model: wiki.theme
+  pk: 215
+- fields: {name: Pogrzeb}
+  model: wiki.theme
+  pk: 218
+- fields: {name: Pojedynek}
+  model: wiki.theme
+  pk: 219
+- fields: {name: Pokora}
+  model: wiki.theme
+  pk: 220
+- fields: {name: Pokusa}
+  model: wiki.theme
+  pk: 221
+- fields: {name: Polak}
+  model: wiki.theme
+  pk: 222
+- fields: {name: Polityka}
+  model: wiki.theme
+  pk: 223
+- fields: {name: Polowanie}
+  model: wiki.theme
+  pk: 224
+- fields: {name: Polska}
+  model: wiki.theme
+  pk: 225
+- fields: {name: Portret}
+  model: wiki.theme
+  pk: 226
+- fields: {name: Porwanie}
+  model: wiki.theme
+  pk: 227
+- fields: {name: "Potw\xF3r"}
+  model: wiki.theme
+  pk: 229
+- fields: {name: Powstanie}
+  model: wiki.theme
+  pk: 230
+- fields: {name: Powstaniec}
+  model: wiki.theme
+  pk: 231
+- fields: {name: Pozory}
+  model: wiki.theme
+  pk: 232
+- fields: {name: "Pozycja spo\u0142eczna"}
+  model: wiki.theme
+  pk: 233
+- fields: {name: "Po\u015Bwi\u0119cenie"}
+  model: wiki.theme
+  pk: 228
+- fields: {name: "Po\u017Car"}
+  model: wiki.theme
+  pk: 234
+- fields: {name: "Po\u017C\u0105danie"}
+  model: wiki.theme
+  pk: 235
+- fields: {name: Praca}
+  model: wiki.theme
+  pk: 236
+- fields: {name: Praca organiczna}
+  model: wiki.theme
+  pk: 238
+- fields: {name: Praca u podstaw}
+  model: wiki.theme
+  pk: 237
+- fields: {name: Prawda}
+  model: wiki.theme
+  pk: 239
+- fields: {name: Prawnik}
+  model: wiki.theme
+  pk: 240
+- fields: {name: Prometeusz}
+  model: wiki.theme
+  pk: 241
+- fields: {name: Proroctwo}
+  model: wiki.theme
+  pk: 242
+- fields: {name: Prorok}
+  model: wiki.theme
+  pk: 243
+- fields: {name: Przebranie}
+  model: wiki.theme
+  pk: 245
+- fields: {name: Przeczucie}
+  model: wiki.theme
+  pk: 246
+- fields: {name: "Przedmurze chrze\u015Bcija\u0144stwa"}
+  model: wiki.theme
+  pk: 247
+- fields: {name: "Przekle\u0144stwo"}
+  model: wiki.theme
+  pk: 248
+- fields: {name: Przekupstwo}
+  model: wiki.theme
+  pk: 249
+- fields: {name: Przemiana}
+  model: wiki.theme
+  pk: 250
+- fields: {name: Przemijanie}
+  model: wiki.theme
+  pk: 251
+- fields: {name: Przemoc}
+  model: wiki.theme
+  pk: 252
+- fields: {name: "Przestrze\u0144"}
+  model: wiki.theme
+  pk: 253
+- fields: {name: "Przyja\u017A\u0144"}
+  model: wiki.theme
+  pk: 254
+- fields: {name: "Przyroda nieo\u017Cywiona"}
+  model: wiki.theme
+  pk: 255
+- fields: {name: "Przysi\u0119ga"}
+  model: wiki.theme
+  pk: 256
+- fields: {name: "Przyw\xF3dca"}
+  model: wiki.theme
+  pk: 257
+- fields: {name: "Pr\xF3\u017Cno\u015B\u0107"}
+  model: wiki.theme
+  pk: 244
+- fields: {name: Ptak}
+  model: wiki.theme
+  pk: 258
+- fields: {name: Pustynia}
+  model: wiki.theme
+  pk: 259
+- fields: {name: Pycha}
+  model: wiki.theme
+  pk: 260
+- fields: {name: Raj}
+  model: wiki.theme
+  pk: 261
+- fields: {name: Realista}
+  model: wiki.theme
+  pk: 262
+- fields: {name: Religia}
+  model: wiki.theme
+  pk: 263
+- fields: {name: Rewolucja}
+  model: wiki.theme
+  pk: 264
+- fields: {name: Robak}
+  model: wiki.theme
+  pk: 265
+- fields: {name: Robotnik}
+  model: wiki.theme
+  pk: 266
+- fields: {name: Rodzina}
+  model: wiki.theme
+  pk: 267
+- fields: {name: Rosja}
+  model: wiki.theme
+  pk: 268
+- fields: {name: Rosjanin}
+  model: wiki.theme
+  pk: 269
+- fields: {name: Rozczarowanie}
+  model: wiki.theme
+  pk: 271
+- fields: {name: Rozpacz}
+  model: wiki.theme
+  pk: 272
+- fields: {name: Rozstanie}
+  model: wiki.theme
+  pk: 273
+- fields: {name: Rozum}
+  model: wiki.theme
+  pk: 274
+- fields: {name: "Ro\u015Bliny"}
+  model: wiki.theme
+  pk: 270
+- fields: {name: Ruiny}
+  model: wiki.theme
+  pk: 275
+- fields: {name: Rycerz}
+  model: wiki.theme
+  pk: 276
+- fields: {name: Rzeka}
+  model: wiki.theme
+  pk: 277
+- fields: {name: Salon}
+  model: wiki.theme
+  pk: 278
+- fields: {name: "Samob\xF3jstwo"}
+  model: wiki.theme
+  pk: 279
+- fields: {name: Samolubstwo}
+  model: wiki.theme
+  pk: 280
+- fields: {name: Samotnik}
+  model: wiki.theme
+  pk: 281
+- fields: {name: "Samotno\u015B\u0107"}
+  model: wiki.theme
+  pk: 282
+- fields: {name: Sarmata}
+  model: wiki.theme
+  pk: 283
+- fields: {name: Sen}
+  model: wiki.theme
+  pk: 287
+- fields: {name: Serce}
+  model: wiki.theme
+  pk: 288
+- fields: {name: Sielanka}
+  model: wiki.theme
+  pk: 290
+- fields: {name: Sierota}
+  model: wiki.theme
+  pk: 291
+- fields: {name: Siostra}
+  model: wiki.theme
+  pk: 293
+- fields: {name: "Si\u0142a"}
+  model: wiki.theme
+  pk: 292
+- fields: {name: "Sk\u0105piec"}
+  model: wiki.theme
+  pk: 299
+- fields: {name: "Sobowt\xF3r"}
+  model: wiki.theme
+  pk: 300
+- fields: {name: "Spowied\u017A"}
+  model: wiki.theme
+  pk: 302
+- fields: {name: "Spo\u0142ecznik"}
+  model: wiki.theme
+  pk: 301
+- fields: {name: "Sprawiedliwo\u015B\u0107"}
+  model: wiki.theme
+  pk: 303
+- fields: {name: "Staro\u015B\u0107"}
+  model: wiki.theme
+  pk: 304
+- fields: {name: Strach}
+  model: wiki.theme
+  pk: 305
+- fields: {name: "Str\xF3j"}
+  model: wiki.theme
+  pk: 306
+- fields: {name: Stworzenie}
+  model: wiki.theme
+  pk: 307
+- fields: {name: Sumienie}
+  model: wiki.theme
+  pk: 308
+- fields: {name: Swaty}
+  model: wiki.theme
+  pk: 309
+- fields: {name: Syberia}
+  model: wiki.theme
+  pk: 310
+- fields: {name: Syn}
+  model: wiki.theme
+  pk: 311
+- fields: {name: Syn marnotrawny}
+  model: wiki.theme
+  pk: 312
+- fields: {name: Syzyf}
+  model: wiki.theme
+  pk: 313
+- fields: {name: Szaleniec}
+  model: wiki.theme
+  pk: 314
+- fields: {name: "Szale\u0144stwo"}
+  model: wiki.theme
+  pk: 315
+- fields: {name: "Szanta\u017C"}
+  model: wiki.theme
+  pk: 316
+- fields: {name: Szatan}
+  model: wiki.theme
+  pk: 317
+- fields: {name: "Szcz\u0119\u015Bcie"}
+  model: wiki.theme
+  pk: 318
+- fields: {name: "Szko\u0142a"}
+  model: wiki.theme
+  pk: 319
+- fields: {name: Szlachcic}
+  model: wiki.theme
+  pk: 320
+- fields: {name: Szpieg}
+  model: wiki.theme
+  pk: 321
+- fields: {name: Sztuka}
+  model: wiki.theme
+  pk: 322
+- fields: {name: "S\u0105d"}
+  model: wiki.theme
+  pk: 285
+- fields: {name: "S\u0105d Ostateczny"}
+  model: wiki.theme
+  pk: 286
+- fields: {name: "S\u0105siad"}
+  model: wiki.theme
+  pk: 284
+- fields: {name: "S\u0119dzia"}
+  model: wiki.theme
+  pk: 289
+- fields: {name: "S\u0142awa"}
+  model: wiki.theme
+  pk: 294
+- fields: {name: "S\u0142owo"}
+  model: wiki.theme
+  pk: 296
+- fields: {name: "S\u0142o\u0144ce"}
+  model: wiki.theme
+  pk: 295
+- fields: {name: "S\u0142uga"}
+  model: wiki.theme
+  pk: 297
+- fields: {name: "S\u0142u\u017Calczo\u015B\u0107"}
+  model: wiki.theme
+  pk: 298
+- fields: {name: Tajemnica}
+  model: wiki.theme
+  pk: 332
+- fields: {name: Taniec}
+  model: wiki.theme
+  pk: 333
+- fields: {name: "Tch\xF3rzostwo"}
+  model: wiki.theme
+  pk: 334
+- fields: {name: Teatr}
+  model: wiki.theme
+  pk: 335
+- fields: {name: Testament}
+  model: wiki.theme
+  pk: 336
+- fields: {name: Theatrum mundi}
+  model: wiki.theme
+  pk: 338
+- fields: {name: Trucizna}
+  model: wiki.theme
+  pk: 340
+- fields: {name: Trup}
+  model: wiki.theme
+  pk: 341
+- fields: {name: "Tw\xF3rczo\u015B\u0107"}
+  model: wiki.theme
+  pk: 342
+- fields: {name: "T\u0119sknota"}
+  model: wiki.theme
+  pk: 337
+- fields: {name: "T\u0142um"}
+  model: wiki.theme
+  pk: 339
+- fields: {name: "Ucze\u0144"}
+  model: wiki.theme
+  pk: 343
+- fields: {name: Uczta}
+  model: wiki.theme
+  pk: 344
+- fields: {name: Umiarkowanie}
+  model: wiki.theme
+  pk: 346
+- fields: {name: Upadek}
+  model: wiki.theme
+  pk: 347
+- fields: {name: "Upi\xF3r"}
+  model: wiki.theme
+  pk: 348
+- fields: {name: Uroda}
+  model: wiki.theme
+  pk: 345
+- fields: {name: "Urz\u0119dnik"}
+  model: wiki.theme
+  pk: 349
+- fields: {name: Vanitas}
+  model: wiki.theme
+  pk: 350
+- fields: {name: Walka}
+  model: wiki.theme
+  pk: 351
+- fields: {name: Walka klas}
+  model: wiki.theme
+  pk: 352
+- fields: {name: Wampir}
+  model: wiki.theme
+  pk: 353
+- fields: {name: Warszawa}
+  model: wiki.theme
+  pk: 354
+- fields: {name: Wdowa}
+  model: wiki.theme
+  pk: 356
+- fields: {name: Wdowiec}
+  model: wiki.theme
+  pk: 357
+- fields: {name: Wesele}
+  model: wiki.theme
+  pk: 358
+- fields: {name: Wiatr}
+  model: wiki.theme
+  pk: 359
+- fields: {name: Wiedza}
+  model: wiki.theme
+  pk: 363
+- fields: {name: "Wierno\u015B\u0107"}
+  model: wiki.theme
+  pk: 360
+- fields: {name: Wierzenia}
+  model: wiki.theme
+  pk: 361
+- fields: {name: "Wie\u015B"}
+  model: wiki.theme
+  pk: 362
+- fields: {name: "Wie\u017Ca Babel"}
+  model: wiki.theme
+  pk: 364
+- fields: {name: Wina}
+  model: wiki.theme
+  pk: 367
+- fields: {name: Wino}
+  model: wiki.theme
+  pk: 368
+- fields: {name: Wiosna}
+  model: wiki.theme
+  pk: 369
+- fields: {name: Wizja}
+  model: wiki.theme
+  pk: 370
+- fields: {name: "Wi\u0119zienie"}
+  model: wiki.theme
+  pk: 365
+- fields: {name: "Wi\u0119zie\u0144"}
+  model: wiki.theme
+  pk: 366
+- fields: {name: Woda}
+  model: wiki.theme
+  pk: 373
+- fields: {name: Wojna}
+  model: wiki.theme
+  pk: 374
+- fields: {name: "Wojna pokole\u0144"}
+  model: wiki.theme
+  pk: 375
+- fields: {name: "Wolno\u015B\u0107"}
+  model: wiki.theme
+  pk: 376
+- fields: {name: "Wr\xF3g"}
+  model: wiki.theme
+  pk: 377
+- fields: {name: Wspomnienia}
+  model: wiki.theme
+  pk: 378
+- fields: {name: "Wsp\xF3\u0142praca"}
+  model: wiki.theme
+  pk: 379
+- fields: {name: Wygnanie}
+  model: wiki.theme
+  pk: 380
+- fields: {name: Wyrzuty sumienia}
+  model: wiki.theme
+  pk: 381
+- fields: {name: Wyspa}
+  model: wiki.theme
+  pk: 382
+- fields: {name: Wzrok}
+  model: wiki.theme
+  pk: 383
+- fields: {name: "W\u0105\u017C"}
+  model: wiki.theme
+  pk: 355
+- fields: {name: "W\u0142adza"}
+  model: wiki.theme
+  pk: 371
+- fields: {name: "W\u0142asno\u015B\u0107"}
+  model: wiki.theme
+  pk: 372
+- fields: {name: Zabawa}
+  model: wiki.theme
+  pk: 384
+- fields: {name: Zabobony}
+  model: wiki.theme
+  pk: 385
+- fields: {name: Zamek}
+  model: wiki.theme
+  pk: 386
+- fields: {name: "Zar\u0119czyny"}
+  model: wiki.theme
+  pk: 387
+- fields: {name: "Zazdro\u015B\u0107"}
+  model: wiki.theme
+  pk: 389
+- fields: {name: "Za\u015Bwiaty"}
+  model: wiki.theme
+  pk: 388
+- fields: {name: Zbawienie}
+  model: wiki.theme
+  pk: 390
+- fields: {name: Zbrodnia}
+  model: wiki.theme
+  pk: 391
+- fields: {name: Zbrodniarz}
+  model: wiki.theme
+  pk: 392
+- fields: {name: Zdrada}
+  model: wiki.theme
+  pk: 393
+- fields: {name: Zdrowie}
+  model: wiki.theme
+  pk: 394
+- fields: {name: Zemsta}
+  model: wiki.theme
+  pk: 395
+- fields: {name: "Zes\u0142aniec"}
+  model: wiki.theme
+  pk: 396
+- fields: {name: Ziarno}
+  model: wiki.theme
+  pk: 397
+- fields: {name: Ziemia}
+  model: wiki.theme
+  pk: 398
+- fields: {name: Zima}
+  model: wiki.theme
+  pk: 399
+- fields: {name: Zmartwychwstanie}
+  model: wiki.theme
+  pk: 403
+- fields: {name: "Zwierz\u0119ta"}
+  model: wiki.theme
+  pk: 405
+- fields: {name: "Zwyci\u0119stwo"}
+  model: wiki.theme
+  pk: 406
+- fields: {name: "Zw\u0105tpienie"}
+  model: wiki.theme
+  pk: 404
+- fields: {name: "Z\u0142o"}
+  model: wiki.theme
+  pk: 400
+- fields: {name: "Z\u0142odziej"}
+  model: wiki.theme
+  pk: 401
+- fields: {name: "Z\u0142oty wiek"}
+  model: wiki.theme
+  pk: 402
+- fields: {name: "\u0141zy"}
+  model: wiki.theme
+  pk: 130
+- fields: {name: "\u015Alub"}
+  model: wiki.theme
+  pk: 323
+- fields: {name: "\u015Amiech"}
+  model: wiki.theme
+  pk: 324
+- fields: {name: "\u015Amier\u0107"}
+  model: wiki.theme
+  pk: 325
+- fields: {name: "\u015Amier\u0107 bohaterska"}
+  model: wiki.theme
+  pk: 326
+- fields: {name: "\u015Apiew"}
+  model: wiki.theme
+  pk: 327
+- fields: {name: "\u015Awiat\u0142o"}
+  model: wiki.theme
+  pk: 328
+- fields: {name: "\u015Awit"}
+  model: wiki.theme
+  pk: 331
+- fields: {name: "\u015Awi\u0119toszek"}
+  model: wiki.theme
+  pk: 329
+- fields: {name: "\u015Awi\u0119ty"}
+  model: wiki.theme
+  pk: 330
+- fields: {name: "\u017Ba\u0142oba"}
+  model: wiki.theme
+  pk: 407
+- fields: {name: "\u017Bebrak"}
+  model: wiki.theme
+  pk: 408
+- fields: {name: "\u017Bona"}
+  model: wiki.theme
+  pk: 410
+- fields: {name: "\u017Bo\u0142nierz"}
+  model: wiki.theme
+  pk: 409
+- fields: {name: "\u017Bycie jako w\u0119dr\xF3wka"}
+  model: wiki.theme
+  pk: 411
+- fields: {name: "\u017Bycie snem"}
+  model: wiki.theme
+  pk: 412
+- fields: {name: "\u017Byd"}
+  model: wiki.theme
+  pk: 413
+- fields: {name: "\u017Bywio\u0142y"}
+  model: wiki.theme
+  pk: 414
+
index f6e6f40..e0c69fd 100644 (file)
@@ -57,22 +57,28 @@ class DocumentTextSaveForm(forms.Form):
     parent_revision = forms.IntegerField(widget=forms.HiddenInput)
     text = forms.CharField(widget=forms.HiddenInput)
 
-    author = forms.CharField(
+    author_name = forms.CharField(
         required=False,
-        label=_(u"Autor"),
-        help_text=_(u"Twoje imie i nazwisko lub email."),
+        label=_(u"Author"),
+        help_text=_(u"Your name/"),
+    )
+
+    author_email = forms.EmailField(
+        required=False,
+        label=_(u"Author's email"),
+        help_text=_(u"Your email address, so we can show a gravatar :)"),
     )
 
     comment = forms.CharField(
         required=True,
         widget=forms.Textarea,
-        label=_(u"Twój komentarz"),
-        help_text=_(u"Opisz w miarę dokładnie swoje zmiany."),
+        label=_(u"Your comments"),
+        help_text=_(u"Describe changes you made."),
     )
 
     stage_completed = forms.ChoiceField(
         choices=DOCUMENT_STAGES,
         required=False,
-        label=_(u"Skończyłem robić"),
-        help_text=_(u"Jeśli skończyłeś jeden z etapów utworu, wybierz go."),
+        label=_(u"Completed"),
+        help_text=_(u"If you completed a life cycle stage, select it."),
     )
index bc4b760..f072ef9 100644 (file)
@@ -58,3 +58,74 @@ def ajax_require_permission(permission):
             return view(request, *args, **kwargs)
         return authorized_view
     return decorator
+
+import collections
+
+def recursive_groupby(iterable):
+    """
+#    >>> recursive_groupby([1,2,3,4,5])
+#    [1, 2, 3, 4, 5]
+
+    >>> recursive_groupby([[1]])
+    [1]
+
+    >>> recursive_groupby([('a', 1),('a', 2), 3, ('b', 4), 5])
+    ['a', [1, 2], 3, 'b', [4], 5]
+
+    >>> recursive_groupby([('a', 'x', 1),('a', 'x', 2), ('a', 'x', 3)])
+    ['a', ['x', [1, 2, 3]]]
+
+    """
+
+    def _generator(iterator):
+        group = None
+        grouper = None
+
+        for item in iterator:
+            if not isinstance(item, collections.Sequence):
+                if grouper is not None:
+                    yield grouper
+                    if len(group):
+                        yield recursive_groupby(group)
+                    group = None
+                    grouper = None
+                yield item
+                continue
+            elif len(item) == 1:
+                if grouper is not None:
+                    yield grouper
+                    if len(group):
+                        yield recursive_groupby(group)
+                    group = None
+                    grouper = None
+                yield item[0]
+                continue
+            elif not len(item):
+                continue
+
+            if grouper is None:
+                group = [item[1:]]
+                grouper = item[0]
+                continue
+
+            if grouper != item[0]:
+                if grouper is not None:
+                    yield grouper
+                    if len(group):
+                        yield recursive_groupby(group)
+                    group = None
+                    grouper = None
+                group = [item[1:]]
+                grouper = item[0]
+                continue
+
+            group.append(item[1:])
+
+        if grouper is not None:
+            yield grouper
+            if len(group):
+                yield recursive_groupby(group)
+            group = None
+            grouper = None
+
+    return list(_generator(iterable))
diff --git a/apps/wiki/locale/pl/LC_MESSAGES/django.mo b/apps/wiki/locale/pl/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..ffadebc
Binary files /dev/null and b/apps/wiki/locale/pl/LC_MESSAGES/django.mo differ
diff --git a/apps/wiki/locale/pl/LC_MESSAGES/django.po b/apps/wiki/locale/pl/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..159aa85
--- /dev/null
@@ -0,0 +1,272 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-08-03 12:13+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: Radek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: constants.py:6
+msgid "First correction"
+msgstr "Autokorekta"
+
+#: constants.py:7
+msgid "Tagging"
+msgstr "Tagowanie"
+
+#: constants.py:8
+msgid "Initial Proofreading"
+msgstr "Korekta"
+
+#: constants.py:9
+msgid "Annotation Proofreading"
+msgstr "Sprawdzenie przypisów źródła"
+
+#: constants.py:10
+msgid "Modernisation"
+msgstr "Uwspółcześnienie"
+
+#: constants.py:11
+msgid "Themes"
+msgstr "Motywy"
+
+#: constants.py:12
+msgid "Editor's Proofreading"
+msgstr "Ostateczna redakcja literacka"
+
+#: constants.py:13
+msgid "Technical Editor's Proofreading"
+msgstr "Ostateczna redakcja techniczna"
+
+#: constants.py:17
+msgid "Ready to publish"
+msgstr "Gotowe do publikacji"
+
+#: forms.py:62
+msgid "Author"
+msgstr "Autor"
+
+#: forms.py:63
+msgid "Your name/"
+msgstr "Imię i nazwisko/"
+
+#: forms.py:68
+msgid "Author's email"
+msgstr "E-mail autora"
+
+#: forms.py:69
+msgid "Your email address, so we can show a gravatar :)"
+msgstr "Adres e-mail, żebyśmy mogli pokazać gravatar :)"
+
+#: forms.py:75
+msgid "Your comments"
+msgstr "Twój komentarz"
+
+#: forms.py:76
+msgid "Describe changes you made."
+msgstr "Opisz swoje zmiany"
+
+#: forms.py:82
+msgid "Completed"
+msgstr "Ukończono"
+
+#: forms.py:83
+msgid "If you completed a life cycle stage, select it."
+msgstr "Jeśli został ukończony etap prac, wskaż go."
+
+#: models.py:93
+#, python-format
+msgid "Finished stage: %s"
+msgstr "Ukończony etap: %s"
+
+#: models.py:149
+msgid "name"
+msgstr "nazwa"
+
+#: models.py:153
+msgid "theme"
+msgstr "motyw"
+
+#: models.py:154
+msgid "themes"
+msgstr "motywy"
+
+#: views.py:279
+msgid "Tag added"
+msgstr "Dodano tag"
+
+#: templates/wiki/base.html:15
+msgid "Platforma Redakcyjna"
+msgstr ""
+
+#: templates/wiki/diff_table.html:5
+msgid "Old version"
+msgstr "Stara wersja"
+
+#: templates/wiki/diff_table.html:6
+msgid "New version"
+msgstr "Nowa wersja"
+
+#: templates/wiki/document_create_missing.html:8
+msgid "Create document"
+msgstr "Utwórz dokument"
+
+#: templates/wiki/document_details.html:31
+msgid "Click to open/close gallery"
+msgstr "Kliknij, aby (ro)zwinąć galerię"
+
+#: templates/wiki/document_details_base.html:36
+msgid "Help"
+msgstr "Pomoc"
+
+#: templates/wiki/document_details_base.html:38
+msgid "Version"
+msgstr "Wersja"
+
+#: templates/wiki/document_details_base.html:38
+msgid "Unknown"
+msgstr "nieznana"
+
+#: templates/wiki/document_details_base.html:40
+#: templates/wiki/tag_dialog.html:15
+msgid "Save"
+msgstr "Zapisz"
+
+#: templates/wiki/document_details_base.html:41
+msgid "Save attempt in progress"
+msgstr ""
+
+#: templates/wiki/document_list.html:30
+msgid "Clear filter"
+msgstr "Wyczyść filtr"
+
+#: templates/wiki/document_list.html:48
+msgid "Your last edited documents"
+msgstr "Twoje ostatnie edycje"
+
+#: templates/wiki/tag_dialog.html:16
+msgid "Cancel"
+msgstr "Anuluj"
+
+#: templates/wiki/tabs/gallery_view.html:7
+msgid "Previous"
+msgstr "Poprzednie"
+
+#: templates/wiki/tabs/gallery_view.html:13
+msgid "Next"
+msgstr "Następne"
+
+#: templates/wiki/tabs/gallery_view.html:15
+msgid "Zoom in"
+msgstr "Powiększ"
+
+#: templates/wiki/tabs/gallery_view.html:16
+msgid "Zoom out"
+msgstr "Zmniejsz"
+
+#: templates/wiki/tabs/gallery_view_item.html:3
+msgid "Gallery"
+msgstr "Galeria"
+
+#: templates/wiki/tabs/history_view.html:5
+msgid "Compare versions"
+msgstr "Porównaj wersje"
+
+#: templates/wiki/tabs/history_view.html:7
+msgid "Mark version"
+msgstr "Oznacz wersję"
+
+#: templates/wiki/tabs/history_view.html:9
+msgid "Revert document"
+msgstr "Przywróć wersję"
+
+#: templates/wiki/tabs/history_view.html:12
+msgid "View version"
+msgstr "Zobacz wersję"
+
+#: templates/wiki/tabs/history_view_item.html:3
+msgid "History"
+msgstr "Historia"
+
+#: templates/wiki/tabs/search_view.html:3
+#: templates/wiki/tabs/search_view.html:5
+msgid "Search"
+msgstr "Szukaj"
+
+#: templates/wiki/tabs/search_view.html:8
+msgid "Replace with"
+msgstr "Zamień na"
+
+#: templates/wiki/tabs/search_view.html:10
+msgid "Replace"
+msgstr "Zamień"
+
+#: templates/wiki/tabs/search_view.html:13
+msgid "Options"
+msgstr "Opcje"
+
+#: templates/wiki/tabs/search_view.html:15
+msgid "Case sensitive"
+msgstr "Rozróżniaj wielkość liter"
+
+#: templates/wiki/tabs/search_view.html:17
+msgid "From cursor"
+msgstr "Zacznij od kursora"
+
+#: templates/wiki/tabs/search_view_item.html:3
+msgid "Search and replace"
+msgstr "Znajdź i zamień"
+
+#: templates/wiki/tabs/source_editor_item.html:5
+msgid "Source code"
+msgstr "Kod źródłowy"
+
+#: templates/wiki/tabs/summary_view.html:10
+msgid "Title"
+msgstr "Tytuł"
+
+#: templates/wiki/tabs/summary_view.html:15
+msgid "Document ID"
+msgstr "ID dokumentu"
+
+#: templates/wiki/tabs/summary_view.html:19
+msgid "Current version"
+msgstr "Aktualna wersja"
+
+#: templates/wiki/tabs/summary_view.html:22
+msgid "Last edited by"
+msgstr "Ostatnio edytowane przez"
+
+#: templates/wiki/tabs/summary_view.html:26
+msgid "Link to gallery"
+msgstr "Link do galerii"
+
+#: templates/wiki/tabs/summary_view.html:31
+msgid "Publish"
+msgstr "Opublikuj"
+
+#: templates/wiki/tabs/summary_view_item.html:4
+msgid "Summary"
+msgstr "Podsumowanie"
+
+#: templates/wiki/tabs/wysiwyg_editor.html:9
+msgid "Insert theme"
+msgstr "Wstaw motyw"
+
+#: templates/wiki/tabs/wysiwyg_editor.html:12
+msgid "Insert annotation"
+msgstr "Wstaw przypis"
+
+#: templates/wiki/tabs/wysiwyg_editor_item.html:3
+msgid "Visual editor"
+msgstr "Edytor wizualny"
diff --git a/apps/wiki/migrations/0001_initial.py b/apps/wiki/migrations/0001_initial.py
new file mode 100644 (file)
index 0000000..4acf5ba
--- /dev/null
@@ -0,0 +1,21 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+    
+    def forwards(self, orm):
+        pass
+    
+    
+    def backwards(self, orm):
+        pass
+    
+    
+    models = {
+        
+    }
+    
+    complete_apps = ['wiki']
diff --git a/apps/wiki/migrations/0002_auto__add_theme.py b/apps/wiki/migrations/0002_auto__add_theme.py
new file mode 100644 (file)
index 0000000..6688139
--- /dev/null
@@ -0,0 +1,38 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+    
+    def forwards(self, orm):
+        
+        # Adding model 'Theme'
+        db.create_table('wiki_theme', (
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('name', self.gf('django.db.models.fields.CharField')(unique=True, max_length=50)),
+        ))
+        db.send_create_signal('wiki', ['Theme'])
+        
+        if not db.dry_run:
+            from django.core.management import call_command
+            call_command("loaddata", "initial_themes.yaml")
+
+    
+    
+    def backwards(self, orm):
+        
+        # Deleting model 'Theme'
+        db.delete_table('wiki_theme')
+    
+    
+    models = {
+        'wiki.theme': {
+            'Meta': {'object_name': 'Theme'},
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '50'})
+        }
+    }
+    
+    complete_apps = ['wiki']
diff --git a/apps/wiki/migrations/__init__.py b/apps/wiki/migrations/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
index f800481..5faf1d3 100644 (file)
@@ -3,11 +3,13 @@
 # This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
 #
+from django.db import models
 import re
 import os
 import vstorage
 from vstorage import DocumentNotFound
-from wiki import settings
+from wiki import settings, constants
+from django.utils.translation import ugettext_lazy as _
 
 from django.http import Http404
 
@@ -15,6 +17,29 @@ import logging
 logger = logging.getLogger("fnp.wiki")
 
 
+# _PCHARS_DICT = dict(zip((ord(x) for x in u"ĄĆĘŁŃÓŚŻŹąćęłńóśżź "), u"ACELNOSZZacelnoszz_"))
+_PCHARS_DICT = dict(zip((ord(x) for x in u" "), u"_"))
+
+# I know this is barbaric, but I didn't find a better solution ;(
+def split_name(name):
+    parts = name.translate(_PCHARS_DICT).split('__')
+    return parts
+
+def join_name(*parts, **kwargs):
+    name = u'__'.join(p.translate(_PCHARS_DICT) for p in parts)
+    logger.info("JOIN %r -> %r", parts, name)
+    return name
+
+def normalize_name(name):
+    """
+    >>> normalize_name("gąska".decode('utf-8'))
+    u'g\u0105ska'
+    """
+    return name.translate(_PCHARS_DICT).lower()
+
+STAGE_TAGS_RE = re.compile(r'^#stage-finished: (.*)$', re.MULTILINE)
+
+
 class DocumentStorage(object):
     def __init__(self, path):
         self.vstorage = vstorage.VersionedStorage(path)
@@ -27,13 +52,17 @@ class DocumentStorage(object):
         text, rev = self.vstorage.page_text_by_tag(name, tag)
         return Document(self, name=name, text=text, revision=rev)
 
+    def revert(self, name, revision):
+        text, rev = self.vstorage.revert(name, revision)
+        return Document(self, name=name, text=text, revision=rev)
+
     def get_or_404(self, *args, **kwargs):
         try:
             return self.get(*args, **kwargs)
         except DocumentNotFound:
             raise Http404
 
-    def put(self, document, author, comment, parent):
+    def put(self, document, author, comment, parent=None):
         self.vstorage.save_text(
                 title=document.name,
                 text=document.text,
@@ -43,15 +72,14 @@ class DocumentStorage(object):
 
         return document
 
-    def create_document(self, id, text, title=None):
-        if title is None:
-            title = id.title()
+    def create_document(self, text, name):
+        title = u', '.join(p.title for p in split_name(name))
 
         if text is None:
             text = u''
 
-        document = Document(self, name=id, text=text, title=title)
-        return self.put(document, u"<wiki>", u"Document created.", None)
+        document = Document(self, name=name, text=text, title=title)
+        return self.put(document, u"<wiki>", u"Document created.")
 
     def delete(self, name, author, comment):
         self.vstorage.delete_page(name, author, comment)
@@ -60,7 +88,14 @@ class DocumentStorage(object):
         return list(self.vstorage.all_pages())
 
     def history(self, title):
-        return list(self.vstorage.page_history(title))
+        def stage_desc(match):
+            stage = match.group(1)
+            return _("Finished stage: %s") % constants.DOCUMENT_STAGES_DICT[stage]
+
+        for changeset in self.vstorage.page_history(title):
+            changeset['description'] = STAGE_TAGS_RE.sub(stage_desc, changeset['description'])
+            yield changeset
+
 
 
 class Document(object):
@@ -98,15 +133,29 @@ class Document(object):
             gallery = os.path.basename(gallery)
 
         result['gallery'] = gallery
-
-        if 'title' not in result:
-            result['title'] = self.name.title()
-
         return result
 
     def info(self):
         return self.storage.vstorage.page_meta(self.name, self.revision)
 
-
 def getstorage():
     return DocumentStorage(settings.REPOSITORY_PATH)
+
+#
+# Django models
+#
+
+class Theme(models.Model):
+    name = models.CharField(_('name'), max_length=50, unique=True)
+
+    class Meta:
+        ordering = ('name',)
+        verbose_name = _('theme')
+        verbose_name_plural = _('themes')
+
+    def __unicode__(self):
+        return self.name
+
+    def __repr__(self):
+        return "Theme(name=%r)" % self.name
+
old mode 100755 (executable)
new mode 100644 (file)
index b6cfe60..f88fac3 100644 (file)
@@ -1,5 +1,5 @@
 {% extends "base.html" %}
-{% load compressed %}
+{% load compressed i18n %}
 
 {% block title %}{{ document_name }} - {{ block.super }}{% endblock %}
 
@@ -12,7 +12,7 @@
 {% endblock %}
 
 {% block maincontent %}
-<h1><img src="{{STATIC_URL}}/img/logo.png">Platforma Redakcyjna</h1>
+<h1><img src="{{ STATIC_URL }}img/logo.png">{% trans "Platforma Redakcyjna" %}</h1>
 <div id="wiki_layout_left_column">
        {% block leftcolumn %}
        {% endblock leftcolumn %}
index 91ac55c..818c38c 100644 (file)
@@ -1,8 +1,9 @@
+{% load i18n %}
 <table class="diff_table">
        <thead>
                <tr>
-                       <th colspan="2">Stara wersja</th>
-                       <th colspan="2">Nowa wersja</th>
+                       <th colspan="2">{% trans "Old version" %}</th>
+                       <th colspan="2">{% trans "New version" %}</th>
                </tr>
        </thead>
 <tbody>
index 0dcf378..351e87a 100644 (file)
@@ -1,13 +1,13 @@
 {% extends "wiki/base.html" %}
+{% load i18n %}
 
 {% block leftcolumn %}
        <form enctype="multipart/form-data" method="POST" action="">
        {{ form.as_p }}
 
-       <p><button type="submit">Stwórz utwór</button></p>
+       <p><button type="submit">{% trans "Create document" %}</button></p>
        </form>
 {% endblock leftcolumn %}
 
 {% block rightcolumn %}
-
 {% endblock rightcolumn %}
\ No newline at end of file
index 81d76dd..9657e0f 100644 (file)
@@ -1,10 +1,11 @@
 {% extends "wiki/document_details_base.html" %}
+{% load i18n %}
 
 {% block extrabody %}
 {{ block.super }}
-<script src="{{STATIC_URL}}js/lib/codemirror/codemirror.js" type="text/javascript" charset="utf-8">
+<script src="{{ STATIC_URL }}js/lib/codemirror/codemirror.js" type="text/javascript" charset="utf-8">
 </script>
-<script src="{{STATIC_URL}}js/wiki/loader.js" type="text/javascript" charset="utf-8"> </script>
+<script src="{{ STATIC_URL }}js/wiki/loader.js" type="text/javascript" charset="utf-8"> </script>
 {% endblock %}
 
 {% block tabs-menu %}
        {% include "wiki/tabs/source_editor.html" %}
 {% endblock %}
 
+{% block tabs-right %}
+    {% include "wiki/tabs/gallery_view_item.html" %}
+    {% include "wiki/tabs/search_view_item.html" %}
+{% endblock %}
+
 {% block splitter-extra %}
-    {% include "wiki/tabs/gallery_view.html" %}
+<div class="vsplitbar" title="{% trans "Click to open/close gallery" %}">
+    </div>
+    <div id="sidebar">
+        {% include "wiki/tabs/gallery_view.html" %}
+        {% include "wiki/tabs/search_view.html" %}
+    </div>
 {% endblock %}
 
 {% block dialogs %}
index 576ee1e..3c6843d 100644 (file)
@@ -1,5 +1,6 @@
 {% extends "base.html" %}
-{% load toolbar_tags %}
+{% load toolbar_tags i18n %}
+
 {% block title %}{{ document.name }} - {{ block.super }}{% endblock %}
 {% block extrahead %}
 {% load compressed %}
 {% endblock %}
 
 {% block maincontent %}
-<div id="loading-overlay">
-    <div id="loading-message">
-        <img src="{{STATIC_URL}}img/spinner.gif" />
-        <p>Ładowanie</p>
-    </div>
-</div>
-
 <div id="document-meta"
        data-document-name="{{ document.name }}" style="display:none">
 
 </div>
 
 <div id="header">
-    <h1><a href="{% url wiki.views.document_list %}">Platforma</a></h1>
+    <h1><a href="{% url wiki_document_list %}">Platforma</a></h1>
     <div id="tools">
-        <a href="{{ REDMINE_URL }}projects/wl-publikacje/wiki/Pomoc" target="_blank">Pomoc</a>
+        <a href="{{ REDMINE_URL }}projects/wl-publikacje/wiki/Pomoc" target="_blank">
+        {% trans "Help" %}</a>
         | {% include "registration/head_login.html" %}
-        | Wersja: <span id="document-revision">unknown</span>
+        | {% trans "Version" %}: <span id="document-revision">{% trans "Unknown" %}</span>
                {% if not readonly %}
-            | <button style="margin-left: 6px" id="save-button">Zapisz</button>
+            | <button style="margin-left: 6px" id="save-button">{% trans "Save" %}</button>
+                       <span id='save-attempt-info'>{% trans "Save attempt in progress" %}</span>
                {% endif %}
     </div>
-    <ol id="tabs">
+    <ol id="tabs" class="tabs">
        {% block tabs-menu %} {% endblock %}
     </ol>
+    <ol id="tabs-right" class="tabs">
+        {% block tabs-right %} {% endblock %}
+    </ol>
 </div>
 <div id="splitter">
     <div id="editor" class="{% block editor-class %} {% endblock %}">
index c0ed66f..69d085b 100644 (file)
@@ -1,4 +1,5 @@
 {% extends "wiki/document_details_base.html" %}
+{% load i18n %}
 
 {% block editor-class %}readonly{% endblock %}
 
index 2ab5ab9..6853801 100644 (file)
@@ -1,5 +1,7 @@
 {% extends "wiki/base.html" %}
 
+{% load i18n %}
+{% load wiki %}
 
 {% block extrabody %}
 {{ block.super }}
@@ -9,7 +11,7 @@ $(function() {
         event.preventDefault();
         var expr = new RegExp(slugify($('#file-list-filter').val()), 'i');
         $('#file-list tbody tr').hide().filter(function(index) {
-            return expr.test(slugify($('a', this).text()));
+            return expr.test(slugify( $('a', this).attr('data-id') ));
         }).show();
     }
 
@@ -25,13 +27,14 @@ $(function() {
        <thead>
                <tr><th>Filtr:</th>
                        <th><input autocomplete="off" name="filter" id="file-list-filter" type="text" size="40" /></th>
-                       <th><input type="reset" value="Wyczyść" id="file-list-reset-button"/></th>
+                       <th><input type="reset" value="{% trans "Clear filter" %}" id="file-list-reset-button"/></th>
                        </tr>
                </thead>
                <tbody>
-       {% for file in document_list %}
+       {% for doc in docs %}
             <tr>
-               <td colspan="3"><a target="_blank" href="{% url wiki.views.document_detail file|urlencode %}">{{ file }}</a></td>
+               <td colspan="3"><a target="_blank" data-id="{{doc}}"
+                                       href="{% url wiki_editor doc %}">{{ doc|wiki_title }}</a></td>
                                <!-- placeholder </td> -->
                        </tr>
        {% endfor %}
@@ -42,11 +45,11 @@ $(function() {
 
 {% block rightcolumn %}
        <div id="last-edited-list">
-               <h2>Twoje ostatnio otwierane dokumenty:</h2>
-               <ol>
-                       {% for   name, date in last_docs %}
-                       <li><a href="{% url wiki.views.document_detail name|urlencode %}"
-                               target="_blank">{{ name }}</a><br/><span class="date">({{ date|date:"H:i:s, d/m/Y" }})</span></li>
+               <h2>{% trans "Your last edited documents" %}</h2>
+           <ol>
+                       {% for name, date in last_docs %}
+                       <li><a href="{% url wiki_editor name %}"
+                               target="_blank">{{ name|wiki_title }}</a><br/><span class="date">({{ date|date:"H:i:s, d/m/Y" }})</span></li>
                        {% endfor %}
                </ol>
        </div>
index 7155964..71c999b 100644 (file)
@@ -1,3 +1,4 @@
+{% load i18n %}
 <div id="save_dialog" class="dialog" data-ui-jsclass="SaveDialog">
        <form method="POST" action="">
        <p>{{ forms.text_save.comment.label }}</p>
index ec5f6e4..7bf6584 100644 (file)
@@ -1,26 +1,25 @@
-<div class="vsplitbar" title="Klinknij aby (ro)zwinąć galerię.">
-</div>
+{% load i18n %}
 <div id="side-gallery">
     <!-- gallery toolbar -->
     <div class="toolbar">
         <button class="previous-page">
-            <img src="{{STATIC_URL}}icons/go-previous.png" alt="Poprzednia" title="Poprzednia"/>
-        </button><input type="text" size="3" maxlength="3" value="1" class="page-number" />
-        <button class="next-page">
-            <img src="{{STATIC_URL}}icons/go-next.png" alt="Następna" title="Następna"/>
-        </button>
-        <button class="zoom-in">
-            Powiększ
+            <img src="{{STATIC_URL}}icons/go-previous.png"
+               alt="{% trans "Previous" %}" title="{% trans "Previous" %}"/>
         </button>
-        <button class="zoom-out">
-            Pomniejsz
+        <input type="text" size="3" maxlength="3" value="0" class="page-number" />
+        <input type="text" id="imagesCount" disabled="disabled" value="0" maxlength="3" size="3">
+        <button class="next-page">
+            <img src="{{STATIC_URL}}icons/go-next.png"
+               alt="{% trans "Next" %}" title="{% trans "Next" %}"/>
         </button>
+        <button class="zoom-in">{% trans "Zoom in" %}</button>
+        <button class="zoom-out">{% trans "Zoom out" %}</button>
         <div class="toolbar-end">
         </div>
     </div>
     <div class="error_message">
     </div>
     <div class="gallery-image">
-        <img src="{{MEDIA_URL}}/images/empty.png" />
+        <img src="{{MEDIA_URL}}images/empty.png" />
     </div>
-</div>
\ No newline at end of file
+</div>
diff --git a/apps/wiki/templates/wiki/tabs/gallery_view_item.html b/apps/wiki/templates/wiki/tabs/gallery_view_item.html
new file mode 100644 (file)
index 0000000..7325c82
--- /dev/null
@@ -0,0 +1,4 @@
+{% load i18n %}
+<li id="ScanGalleryPerspective" data-ui-related="side-gallery" data-ui-jsclass="ScanGalleryPerspective" class='active'>
+    <span>{% trans "Gallery" %}</span>
+</li>
index 6d82785..d9b74dc 100644 (file)
@@ -1,9 +1,16 @@
+{% load i18n %}
 <div id="history-view-editor" class="editor" style="display: none">
     <div class="toolbar">
-       <button type="button" id="make-diff-button">Porównaj</button>
-               <button type="button" id="tag-changeset-button">Oznacz wersje</button>
-               <button id="open-preview-button"
-                       data-basehref="{% url wiki_details_readonly document_name %}">Podejrzyj wersje</button>
+       <button type="button" id="make-diff-button"
+                       data-enabled-when="2" disabled="disabled">{% trans "Compare versions" %}</button>
+               <button type="button" id="tag-changeset-button"
+                       data-enabled-when="1" disabled="disabled">{% trans "Mark version" %}</button>
+               <button type="button" id="doc-revert-button"
+                       data-enabled-when="1" disabled="disabled">{% trans "Revert document" %}</button>
+               <button id="open-preview-button" disabled="disabled"
+                       data-enabled-when="1"
+                       data-basehref="{% url wiki_editor_readonly document_name %}">{% trans "View version" %}</button>
+
        </div>
     <div id="history-view">
         <p class="message-box" style="display:none;"></p>
index 3a90ea8..bf39a33 100644 (file)
@@ -1,3 +1,4 @@
+{% load i18n %}
 <li id="HistoryPerspective" data-ui-related="history-view-editor" data-ui-jsclass="HistoryPerspective">
-    <span>Historia</span>
+    <span>{% trans "History" %}</span>
 </li>
diff --git a/apps/wiki/templates/wiki/tabs/search_view.html b/apps/wiki/templates/wiki/tabs/search_view.html
new file mode 100644 (file)
index 0000000..4bf1e89
--- /dev/null
@@ -0,0 +1,19 @@
+{% load i18n %}
+<div id='side-search'>
+    <p>{% trans "Search" %}:<br/>
+    <input id='search-input' /><br/>
+    <button id='search-button'>{% trans "Search" %}</button>
+    </p>
+
+    <p>{% trans "Replace with" %}:<br/>
+        <input id='replace-input' /><br/>
+        <button id='replace-button'>{% trans "Replace" %}</button><br/>
+    </p>
+
+    <p>{% trans "Options" %}<br/>
+        <input type="checkbox" id="search-case-sensitive" />
+            <label for="search-case-sensitive">{% trans "Case sensitive" %}</label><br/>
+        <input type="checkbox" id="search-from-cursor" />
+            <label for="search-from-cursor">{% trans "From cursor" %}</label><br/>
+    </p>
+</div>
\ No newline at end of file
diff --git a/apps/wiki/templates/wiki/tabs/search_view_item.html b/apps/wiki/templates/wiki/tabs/search_view_item.html
new file mode 100644 (file)
index 0000000..dbd4e09
--- /dev/null
@@ -0,0 +1,4 @@
+{% load i18n %}
+<li id="SearchPerspective" data-ui-related="side-search" data-ui-jsclass="SearchPerspective">
+    <span>{% trans "Search and replace" %}</span>
+</li>
index 10ca334..72d881c 100644 (file)
@@ -1,4 +1,4 @@
-{% load toolbar_tags %}
+{% load toolbar_tags i18n %}
 <div id="source-editor" class="editor">
     {% if not document_info.readonly %}{% toolbar %}{% endif %}
     <textarea id="codemirror_placeholder">&lt;br/&gt;</textarea>
index 0382982..89e0fae 100644 (file)
@@ -1,5 +1,6 @@
+{% load i18n %}
 <li id="CodeMirrorPerspective"
        data-ui-related="source-editor"
        data-ui-jsclass="CodeMirrorPerspective">
-    <span>Kod źródłowy</span>
+    <span>{% trans "Source code" %}</span>
 </li>
\ No newline at end of file
index f6dd3de..c33baec 100644 (file)
@@ -1,31 +1,33 @@
+{% load i18n %}
+{% load wiki %}
 <div id="summary-view-editor" class="editor" style="display: none">
     <!-- <div class="toolbar">
     </div> -->
     <div id="summary-view">
-               <img class="book-cover" src="{{STATIC_URL}}img/sample_cover.png">
+               <img class="book-cover" src="{{ STATIC_URL }}img/sample_cover.png">
 
                <h2>
-                       <label for="title">Tytuł:</label>
+                       <label for="title">{% trans "Title" %}:</label>
                        <span data-ui-editable="true" data-edit-target="meta.displayTitle"
-                       >{{ document_meta.title }}</span>
+                       >{{ document.name|wiki_title }}</span>
                </h2>
                <p>
-                       <label>ID dokumentu:</label>
-                       <span>{{ document.name|urlencode }}</span>
+                       <label>{% trans "Document ID" %}:</label>
+                       <span>{{ document.name }}</span>
                </p>
                <p>
-                       <label>Aktulana wersja:</label>
-                       {{ document_info.revision }} ({{document_info.last_update}})
+                       <label>{% trans "Current version" %}:</label>
+                       {{ document_info.revision }} ({{document_info.date}})
                <p>
-                       <label>Ostatnio edytowane przez:</label>
-                       {{document_info.last_comitter}}
+                       <label>{% trans "Last edited by" %}:</label>
+                       {{document_info.author}}
                </p>
                <p>
-                       <label for="gallery">Link do galerii:</label>
+                       <label for="gallery">{% trans "Link to gallery" %}:</label>
                        <span data-ui-editable="true" data-edit-target="meta.galleryLink"
                        >{{ document_meta.gallery}}</span>
                </p>
 
-               <p><button type="button" id="publish_button">Publikuj na wolnelektury.pl</button></p>
+               <p><button type="button" id="publish_button">{% trans "Publish" %}</button></p>
        </div>
-</div>
\ No newline at end of file
+</div>
index d973d4d..2b4daeb 100644 (file)
@@ -1,3 +1,5 @@
+{% load i18n %}
+{% load wiki %}
 <li id="SummaryPerspective" data-ui-related="summary-view-editor" data-ui-jsclass="SummaryPerspective">
-    <span>{{ document_meta.title }}</span>
+    <span>{% trans "Summary" %}</span>
 </li>
index dbf1b6a..5e3c46f 100644 (file)
@@ -1,3 +1,4 @@
+{% load i18n %}
 <div id="simple-editor" class="editor" style="display: none">
     <div id="html-view" class="htmlview">
     </div>
@@ -5,10 +6,10 @@
        <div class="toolbar">
        {% if not document_info.readonly %}
         <button id="insert-theme-button">
-            Wstaw motyw
+            {% trans "Insert theme" %}
         </button>
         <button id="insert-annotation-button">
-            Wstaw przypis
+            {% trans "Insert annotation" %}
         </button>
                {% endif %}
         <div class="toolbar-end">
index bd4dc62..718ec49 100644 (file)
@@ -1,3 +1,4 @@
+{% load i18n %}
 <li id="VisualPerspective" data-ui-related="simple-editor" data-ui-jsclass="VisualPerspective">
-    <span>Edytor</span>
+    <span>{% trans "Visual editor" %}</span>
 </li>
index 66b488c..bc601cb 100644 (file)
@@ -1,3 +1,4 @@
+{% load i18n %}
 <div id="add_tag_dialog" class="dialog" data-ui-jsclass="AddTagDialog">
        <form method="POST" action="#">
                {% for field in forms.add_tag.visible_fields %}
@@ -11,8 +12,8 @@
                <p data-ui-error-for="__all__"> </p>
 
                <p class="action_area">
-                       <button type="submit" class"ok" data-ui-action="save">Zapisz</button>
-                       <button type="button" class="cancel" data-ui-action="cancel">Anuluj</button>
+                       <button type="submit" class"ok" data-ui-action="save">{% trans "Save" %}</button>
+                       <button type="button" class="cancel" data-ui-action="cancel">{% trans "Cancel" %}</button>
                </p>
        </form>
 </div>
diff --git a/apps/wiki/templatetags/__init__.py b/apps/wiki/templatetags/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/apps/wiki/templatetags/wiki.py b/apps/wiki/templatetags/wiki.py
new file mode 100644 (file)
index 0000000..cb5bf20
--- /dev/null
@@ -0,0 +1,14 @@
+from __future__ import absolute_import
+
+from django.template.defaultfilters import stringfilter
+from django import template
+
+register = template.Library()
+
+from wiki.models import split_name
+
+@register.filter
+@stringfilter
+def wiki_title(value):
+    parts = (p.replace('_', ' ').title() for p in split_name(value))
+    return ' / '.join(parts)
index bfc799f..351ecbc 100644 (file)
@@ -1,29 +1,43 @@
+# -*- coding: utf-8
 from django.conf.urls.defaults import *
+from django.views.generic.simple import redirect_to
+from django.conf import settings
+
+
+PART = ur"""[ ĄĆĘŁŃÓŚŻŹąćęłńóśżź0-9\w_.-]+"""
 
 urlpatterns = patterns('wiki.views',
-    url(r'^$',
-        'document_list', name='wiki_doclist'),
+    url(r'^$', redirect_to, {'url': 'catalogue/'}),
+
+    url(r'^catalogue/$', 'document_list', name='wiki_document_list'),
+    url(r'^catalogue/([^/]+)/$', 'document_list'),
+    url(r'^catalogue/([^/]+)/([^/]+)/$', 'document_list'),
+    url(r'^catalogue/([^/]+)/([^/]+)/([^/]+)$', 'document_list'),
+
+    url(r'^(?P<name>%s)$' % PART,
+        'editor', name="wiki_editor"),
+
+    url(r'^(?P<name>[^/]+)/readonly$',
+        'editor_readonly', name="wiki_editor_readonly"),
 
     url(r'^create/(?P<name>[^/]+)',
-        'document_create_missing', name='wiki_create_missing'),
+        'create_missing', name='wiki_create_missing'),
+
+    url(r'^(?P<directory>[^/]+)/gallery$',
+        'gallery', name="wiki_gallery"),
 
-    url(r'^gallery/(?P<directory>[^/]+)$',
-        'document_gallery', name="wiki_gallery"),
     url(r'^(?P<name>[^/]+)/history$',
-        'document_history', name="wiki_history"),
+        'history', name="wiki_history"),
+
     url(r'^(?P<name>[^/]+)/text$',
-        'document_text', name="wiki_text"),
-    url(r'^(?P<name>[^/]+)/publish/(?P<version>\d+)$',
-        'document_publish', name="wiki_publish"),
-    url(r'^(?P<name>[^/]+)/diff$',
-        'document_diff', name="wiki_diff"),
-    url(r'^(?P<name>[^/]+)/tags$',
-        'document_add_tag', name="wiki_add_tag"),
-    url(r'^(?P<name>[^/]+)/publish$', 'document_publish'),
+        'text', name="wiki_text"),
+
+    url(r'^(?P<name>[^/]+)/publish$', 'publish', name="wiki_publish"),
+    url(r'^(?P<name>[^/]+)/publish/(?P<version>\d+)$', 'publish', name="wiki_publish"),
+
+    url(r'^(?P<name>[^/]+)/diff$', 'diff', name="wiki_diff"),
+    url(r'^(?P<name>[^/]+)/tags$', 'add_tag', name="wiki_add_tag"),
+
 
-    url(r'^(?P<name>[^/]+)/readonly$',
-        'document_detail_readonly', name="wiki_details_readonly"),
 
-    url(r'^(?P<name>[^/]+)$',
-        'document_detail', name="wiki_details"),
 )
index 46f0665..48e05c5 100644 (file)
@@ -1,47 +1,64 @@
 import os
+import functools
+import logging
+logger = logging.getLogger("fnp.wiki")
 
 from django.conf import settings
 
 from django.views.generic.simple import direct_to_template
 from django.views.decorators.http import require_POST, require_GET
 from django.core.urlresolvers import reverse
-from wiki.helpers import JSONResponse, JSONFormInvalid, JSONServerError, ajax_require_permission
+from wiki.helpers import (JSONResponse, JSONFormInvalid, JSONServerError,
+                ajax_require_permission, recursive_groupby)
 from django import http
 
-from wiki.models import getstorage, DocumentNotFound
+from wiki.models import getstorage, DocumentNotFound, normalize_name, split_name, join_name, Theme
 from wiki.forms import DocumentTextSaveForm, DocumentTagForm, DocumentCreateForm
 from datetime import datetime
 from django.utils.encoding import smart_unicode
 from django.utils.translation import ugettext_lazy as _
 
-import wlapi
 
 #
 # Quick hack around caching problems, TODO: use ETags
 #
 from django.views.decorators.cache import never_cache
 
-import logging
-logger = logging.getLogger("fnp.peanut.api")
-
+import wlapi
 import nice_diff
 import operator
 
 MAX_LAST_DOCS = 10
 
 
+def normalized_name(view):
+
+    @functools.wraps(view)
+    def decorated(request, name, *args):
+        normalized = normalize_name(name)
+        logger.debug('View check %r -> %r', name, normalized)
+
+        if normalized != name:
+            return http.HttpResponseRedirect(
+                        reverse('wiki_' + view.__name__, kwargs={'name': normalized}))
+
+        return view(request, name, *args)
+
+    return decorated
+
+
 @never_cache
-def document_list(request, template_name='wiki/document_list.html'):
-    # TODO: find a way to cache "Storage All"
-    return direct_to_template(request, template_name, extra_context={
-        'document_list': getstorage().all(),
+def document_list(request):
+    return direct_to_template(request, 'wiki/document_list.html', extra_context={
+        'docs': getstorage().all(),
         'last_docs': sorted(request.session.get("wiki_last_docs", {}).items(),
                         key=operator.itemgetter(1), reverse=True),
     })
 
 
 @never_cache
-def document_detail(request, name, template_name='wiki/document_details.html'):
+@normalized_name
+def editor(request, name, template_name='wiki/document_details.html'):
     storage = getstorage()
 
     try:
@@ -67,17 +84,20 @@ def document_detail(request, name, template_name='wiki/document_details.html'):
             "text_save": DocumentTextSaveForm(prefix="textsave"),
             "add_tag": DocumentTagForm(prefix="addtag"),
         },
+        'REDMINE_URL': settings.REDMINE_URL,
     })
 
 
 @require_GET
-def document_detail_readonly(request, name, template_name='wiki/document_details_readonly.html'):
+@normalized_name
+def editor_readonly(request, name, template_name='wiki/document_details_readonly.html'):
+    name = normalize_name(name)
     storage = getstorage()
 
     try:
         revision = request.GET['revision']
         document = storage.get(name, revision)
-    except (KeyError, DocumentNotFound) as e:
+    except (KeyError, DocumentNotFound):
         raise http.Http404
 
     access_time = datetime.now()
@@ -94,10 +114,12 @@ def document_detail_readonly(request, name, template_name='wiki/document_details
         'document_name': document.name,
         'document_info': dict(document.info(), readonly=True),
         'document_meta': document.meta,
+        'REDMINE_URL': settings.REDMINE_URL,
     })
 
 
-def document_create_missing(request, name):
+@normalized_name
+def create_missing(request, name):
     storage = getstorage()
 
     if request.method == "POST":
@@ -122,26 +144,22 @@ def document_create_missing(request, name):
 
 
 @never_cache
-def document_text(request, name):
+@normalized_name
+def text(request, name):
     storage = getstorage()
 
     if request.method == 'POST':
         form = DocumentTextSaveForm(request.POST, prefix="textsave")
-
         if form.is_valid():
             revision = form.cleaned_data['parent_revision']
-
-            document = storage.get_or_404(name, revision)
+            document = storage.get_or_404(name, revision)          
             document.text = form.cleaned_data['text']
-
-            storage.put(document,
-                author=form.cleaned_data['author'] or request.user.username,
-                comment=form.cleaned_data['comment'],
-                parent=revision,
-            )
-
-            document = storage.get(name)
-
+            comment = form.cleaned_data['comment']
+            if form.cleaned_data['stage_completed']:        
+                comment += '\n#stage-finished: %s\n' % form.cleaned_data['stage_completed']         
+            author = "%s <%s>" % (form.cleaned_data['author_name'], form.cleaned_data['author_email'])           
+            storage.put(document, author=author, comment=comment, parent=revision)           
+            document = storage.get(name)          
             return JSONResponse({
                 'text': document.plain_text if revision != document.revision else None,
                 'meta': document.meta(),
@@ -172,7 +190,25 @@ def document_text(request, name):
 
 
 @never_cache
-def document_gallery(request, directory):
+@normalized_name
+@require_POST
+def revert(request, name):
+    storage = getstorage()
+    revision = request.POST['target_revision']
+
+    try:
+        document = storage.revert(name, revision)
+
+        return JSONResponse({
+            'text': document.plain_text if revision != document.revision else None,
+            'meta': document.meta(),
+            'revision': document.revision,
+        })
+    except DocumentNotFound:
+        raise http.Http404
+
+@never_cache
+def gallery(request, directory):
     try:
         base_url = ''.join((
                         smart_unicode(settings.MEDIA_URL),
@@ -193,13 +229,14 @@ def document_gallery(request, directory):
         images = [map_to_url(f) for f in map(smart_unicode, os.listdir(base_dir)) if is_image(f)]
         images.sort()
         return JSONResponse(images)
-    except (IndexError, OSError) as e:
+    except (IndexError, OSError):
         logger.exception("Unable to fetch gallery")
         raise http.Http404
 
 
 @never_cache
-def document_diff(request, name):
+@normalized_name
+def diff(request, name):
     storage = getstorage()
 
     revA = int(request.GET.get('from', 0))
@@ -219,7 +256,8 @@ def document_diff(request, name):
 
 
 @never_cache
-def document_history(request, name):
+@normalized_name
+def history(request, name):
     storage = getstorage()
 
     # TODO: pagination
@@ -230,7 +268,8 @@ def document_history(request, name):
 
 @require_POST
 @ajax_require_permission('wiki.can_change_tags')
-def document_add_tag(request, name):
+def add_tag(request, name):
+    name = normalize_name(name)
     storage = getstorage()
 
     form = DocumentTagForm(request.POST, prefix="addtag")
@@ -246,7 +285,9 @@ def document_add_tag(request, name):
 
 @require_POST
 @ajax_require_permission('wiki.can_publish')
-def document_publish(request, name):
+def publish(request, name):
+    name = normalize_name(name)
+
     storage = getstorage()
     document = storage.get_by_tag(name, "ready_to_publish")
 
@@ -256,3 +297,8 @@ def document_publish(request, name):
         return JSONResponse({"result": api.publish_book(document)})
     except wlapi.APICallException, e:
         return JSONServerError({"message": str(e)})
+
+
+def themes(request):
+    prefix = request.GET.get('q', '')
+    return http.HttpResponse('\n'.join([str(t) for t in Theme.objects.filter(name__istartswith=prefix)]))
index 041b58c..b989fc7 100644 (file)
-#!/srv/library/redakcja/pythonenv/bin/python
 from __future__ import with_statement
 
 import shutil
 import os
 import sys
+import logging
+
+logging.basicConfig(stream=sys.stderr, format="%(levelname)s:: %(message)s", level=logging.INFO)
 
 from string import Template
 
-def render_template(source, dest, context={}):
-    print "Rendering template:",
-    with open(source, 'rb') as source_file:
-        t = Template(source_file.read())
-    with open(dest, 'wb') as dest_file:
-        dest_file.write(t.safe_substitute(context))
-    print "done."
+class DeploySite(object):
+
+    def __init__(self, **env):
+        self.env = env
+
+        for arg in ('ROOT', 'PROJECT_NAME', 'PYTHON_VERSION'):
+            if arg not in self.env:
+                raise ValueError("Argument '%s' is required." % arg)
+
+        if 'PYTHON_BASE' not in self.env:
+            self.env['PYTHON_BASE'] = os.path.join(self.env['ROOT'], 'pythonenv')
+
+        if 'PYTHON_BIN' not in self.env:
+            self.env['PYTHON_BIN'] = os.path.join(
+                        self.env['PYTHON_BASE'], 'bin', 'python') + self.env['PYTHON_VERSION']
+
+        if 'PIP_BIN' not in self.env:
+            self.env['PIP_BIN'] = os.path.join(self.env['PYTHON_BASE'], 'bin', 'pip')
+
+        if 'PYTHON_SITE' not in self.env:
+            self.env['PYTHON_SITE'] = os.path.join(
+                        self.env['PYTHON_BASE'], 'lib',
+                        'python' + self.env['PYTHON_VERSION'], 'site-packages')
+
+        if 'APP_DIR' not in self.env:
+            self.env['APP_DIR'] = os.path.join(self.env['ROOT'], 'application')
+
+        if 'CONFIG_DIR' not in self.env:
+            self.env['CONFIG_DIR'] = os.path.join(self.env['ROOT'], 'etc')
+
+        if 'MEDIA_DIR' not in self.env:
+            self.env['MEDIA_DIR'] = os.path.join(self.env['ROOT'], 'www', 'media')
+
+        self._logger = logging.getLogger("deployment")
+
+    def info(self, *args, **kwargs):
+        self._logger.info(*args, **kwargs)
+
+    def render_template(self, source, dest, extra_context={}):
+        self.info("Rendering template: %s", source)
+
+        with open(source, 'rb') as source_file:
+            t = Template(source_file.read())
+
+        context = dict(self.env)
+        context.update(extra_context)
+
+        with open(dest, 'wb') as dest_file:
+            dest_file.write(t.safe_substitute(context))
+
+        self.info("Done.")
+
+    def restart_app(self):
+        pass
+
+    def update_app(self):
+        pass
+
+    def update_config(self):
+        pass
+
+    def install_dependencies(self):
+        pass
+
+    def deploy(self):
+        self.update_app()
+        self.install_dependencies()
+        self.update_config()
+        self.restart_app()
+
+    def find_resource(self, path):
+        for dir in (self.env['CONFIG_DIR'], self.env['APP_DIR']):
+            full_path = os.path.join(dir, path)
+            if os.path.isfile(full_path):
+                return full_path
+
+        raise ValueError("Resource '%s' not found" % path)
+
+    @classmethod
+    def run_deploy(cls, *args, **kwargs):
+        site = cls(*args, **kwargs)
+        return site.deploy()
+
+class WSGISite(DeploySite):
+
+    def __init__(self, **env):
+        super(WSGISite, self).__init__(**env)
+
+        if 'WSGI_FILE' not in self.env:
+            self.env['WSGI_FILE'] = os.path.join(self.env['ROOT'], 'www',
+                                        'wsgi', self.env['PROJECT_NAME']) + '.wsgi'
+
+        self.env['WSGI_DIR'] = os.path.dirname(self.env['WSGI_FILE'])
+
+        if 'WSGI_SOURCE_FILE' not in self.env:
+            self.env['WSGI_SOURCE_FILE'] = 'wsgi_app.template'
+
+        if 'WSGI_USER' not in self.env:
+            self.env['WSGI_USER'] = 'www-data'
+
+    def restart_app(self):
+        self.info("Restarting wsgi application: %s", self.env['WSGI_FILE'])
+        os.system("touch %s" % self.env['WSGI_FILE'])
 
-def restart_wsgi():
-    print "Restarting wsgi application:",
-    os.system("touch %s" % WSGI_TARGET)
-    print "done."
+    def update_config(self):
+        super(WSGISite, self).update_config()
 
-def update_application():
-    print "Updating repository.",
-    os.system("cd %s; git pull" % PROJECT_ROOT)
-    print "Installing requirements"
-    os.system("pip install -r %s" % os.path.join(PROJECT_ROOT, 'requirements.txt'))
-    print "Installing local requirements"
-    os.system("pip install -r %s" % os.path.join(ROOT, 'etc', 'requirements.txt'))
-    print "done."
+        source = self.find_resource(self.env['WSGI_SOURCE_FILE'])
+        self.render_template(source, self.env['WSGI_FILE'])
 
-ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+class PIPSite(DeploySite):
 
-PYTHON = os.path.join(ROOT, 'pythonenv', 'bin', 'python')
-PYTHON_SITE = os.path.join(ROOT, 'pythonenv', 'lib', 'python2.6', 'site-packages')
+    def install_dependencies(self):
+        self.info("Installing requirements")
+        os.system("%s install -r %s" % (self.env['PIP_BIN'], self.find_resource('requirements.txt')))
 
-PROJECT_NAME = 'redakcja'
-PROJECT_ROOT = os.path.join(ROOT, 'app')
+        try:
+            self.info("Installing local requirements")
+            os.system("%s install -r %s" % (self.env['PIP_BIN'], self.find_resource('requirements_local.txt')))
+        except ValueError:
+            pass
 
-MEDIA_ROOT = os.path.join(ROOT, 'www', 'media')
+class GitSite(DeploySite):
 
-ADMIN_EMAIL = 'lrekucki@gmail.com'
+    def update_app(self):
+        self.info("Updating repository.")
+        os.system("cd %s; git pull" % self.env['APP_DIR'])
 
-WSGI_TARGET = os.path.join(ROOT, 'www', 'wsgi', PROJECT_NAME + '.wsgi')
-WSGI_DIR = os.path.dirname(WSGI_TARGET)
+class ApacheSite(DeploySite):
 
-WSGI_USER = PROJECT_NAME
-WSGI_PROCESSES = 5
-WSGI_THREADS = 1
+    def __init__(self, **env):
+        super(ApacheSite, self).__init__(**env)
 
-DOMAIN = 'redakcja.wolnelektury.pl'
-DOMAIN_ALIASES = 'redakcja.nowoczesnapolska.org.pl'
+        if 'VHOST_SOURCE_FILE' not in self.env:
+            self.env['VHOST_SOURCE_FILE'] = 'apache_vhost.template'
 
-#
-# Load local configuration
-#
-sys.path = [ os.path.join(ROOT, 'etc') ] + sys.path
+        if 'VHOST_FILE' not in self.env:
+            self.env['VHOST_FILE'] = os.path.join(self.env['CONFIG_DIR'], self.env['PROJECT_NAME'] + '.vhost')
 
-from local_deployment import *
+    def update_config(self):
+        super(ApacheSite, self).update_config()
 
-if __name__ == '__main__':
-    update_application()
-    render_template(os.path.join(PROJECT_ROOT, PROJECT_NAME + '.wsgi.template'), WSGI_TARGET, context=globals())
-    render_template(os.path.join(PROJECT_ROOT, PROJECT_NAME + '.vhost.template'), os.path.join(ROOT, 'etc', PROJECT_NAME + '.vhost'), context=globals())
-    restart_wsgi()
+        source = self.find_resource(self.env['VHOST_SOURCE_FILE'])
+        self.render_template(source, self.env['VHOST_FILE'])
diff --git a/hudson_build.sh b/hudson_build.sh
new file mode 100644 (file)
index 0000000..c2b85df
--- /dev/null
@@ -0,0 +1,6 @@
+cd $WORKSPACE
+virtualenv -q ve
+source ./ve/bin/activate
+pip install -q -E ./ve -r requirements.txt
+pip install -q -E ./ve -r requirements-test.txt
+django-admin.py test --settings=redakcja.settings.test
diff --git a/lib/test_vstorage.py b/lib/test_vstorage.py
deleted file mode 100644 (file)
index 23375f0..0000000
+++ /dev/null
@@ -1,218 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
-#
-
-import os
-import tempfile
-from nose.tools import *
-from nose.core import runmodule
-
-import vstorage
-
-NULL_PARENT = -1
-
-
-def clear_directory(top):
-    for root, dirs, files in os.walk(top, topdown=False):
-        for name in files:
-            os.remove(os.path.join(root, name))
-        for name in dirs:
-            os.rmdir(os.path.join(root, name))
-    try:
-        os.removedirs(top)
-    except OSError:
-        pass
-
-
-class TestVersionedStorage(object):
-    def setUp(self):
-        self.repo_path = tempfile.mkdtemp()
-        self.repo = vstorage.VersionedStorage(self.repo_path)
-
-    def tearDown(self):
-        clear_directory(self.repo_path)
-
-    def test_save_text(self):
-        text = u"test text"
-        title = u"test title"
-        author = u"test author"
-        comment = u"test comment"
-
-        self.repo.save_text(
-            title=title,
-            text=text,
-            author=author,
-            comment=comment,
-            parent=NULL_PARENT,
-        )
-
-        saved = self.repo.open_page(title).read()
-        assert_equal(saved, text)
-
-    def test_save_text_noparent(self):
-        text = u"test text"
-        title = u"test title"
-        author = u"test author"
-        comment = u"test comment"
-
-        self.repo.save_text(title=title,
-                    text=text, author=author,
-                    comment=comment, parent=None)
-
-        saved = self.repo.open_page(title).read()
-        assert_equal(saved, text)
-
-    def test_save_merge_no_conflict(self):
-        text = u"test\ntext"
-        title = u"test title"
-        author = u"test author"
-        comment = u"test comment"
-        self.repo.save_text(title=title,
-                    text=text, author=author,
-                    comment=comment, parent=NULL_PARENT)
-        self.repo.save_text(title=title,
-                    text=text, author=author,
-                    comment=comment, parent=NULL_PARENT)
-        saved = self.repo.open_page(title).read()
-        assert_equal(saved, text)
-
-    def test_save_merge_line_conflict(self):
-        text = u"test\ntest\n"
-        text1 = u"test\ntext\n"
-        text2 = u"text\ntest\n"
-        title = u"test title"
-        author = u"test author"
-        comment = u"test comment"
-
-        self.repo.save_text(title=title,
-                    text=text, author=author,
-                    comment=comment, parent=NULL_PARENT)
-
-        self.repo.save_text(title=title,
-                    text=text1, author=author,
-                    comment=comment, parent=0)
-
-        self.repo.save_text(title=title,
-                    text=text2, author=author,
-                    comment=comment, parent=0)
-
-        saved = self.repo.open_page(title).read()
-
-        # Other conflict markers placement can also be correct
-        assert_equal(saved, u'''\
-text
-test
-<<<<<<< local
-=======
-text
->>>>>>> other
-''')
-
-    def test_delete(self):
-        text = u"text test"
-        title = u"test title"
-        author = u"test author"
-        comment = u"test comment"
-        self.repo.save_text(title=title,
-                    text=text, author=author,
-                    comment=comment, parent=NULL_PARENT)
-
-        assert title in self.repo
-
-        self.repo.delete_page(title, author, comment)
-
-        assert title not in self.repo
-
-    @raises(vstorage.DocumentNotFound)
-    def test_document_not_found(self):
-        self.repo.open_page(u'unknown entity')
-
-    def test_open_existing_repository(self):
-        self.repo.save_text(title=u'Python!', text=u'ham and spam')
-        current_repo_revision = self.repo.repo_revision()
-        same_repo = vstorage.VersionedStorage(self.repo_path)
-        assert_equal(same_repo.repo_revision(), current_repo_revision)
-
-    def test_history(self):
-        COMMITS = [
-            {"author": "bunny", "text":"1", "comment": "Oh yeah!"},
-            {"author": "frank", "text":"2", "comment": "Second is the best!"},
-            {"text":"3", "comment": "Third"},
-            {"author": "welma", "text":"4", "comment": "Fourth"},
-        ]
-
-        for commit in COMMITS:
-            self.repo.save_text(title=u"Sample", **commit)
-
-        for n, entry in enumerate(reversed(list(self.repo.page_history(u"Sample")))):
-            assert_equal(entry["version"], n)
-            assert_equal(entry["author"], COMMITS[n].get("author", "anonymous"))
-            assert_equal(entry["description"], COMMITS[n]["comment"])
-            assert_equal(entry["tag"], [])
-
-
-class TestVSTags(object):
-
-    TITLE_1 = "Sample"
-
-    COMMITS = [
-        {"author": "bunny", "text":"1", "comment": "Oh yeah!"},
-        {"author": "frank", "text":"2", "comment": "Second is the best!"},
-        {"text":"3", "comment": "Third"},
-        {"author": "welma", "text":"4", "comment": "Fourth"},
-    ]
-
-    def setUp(self):
-        self.repo_path = tempfile.mkdtemp()
-        self.repo = vstorage.VersionedStorage(self.repo_path)
-
-        # generate some history
-        for commit in self.COMMITS:
-            self.repo.save_text(title=u"Sample", **commit)
-
-        # verify
-        for n, entry in enumerate(reversed(list(self.repo.page_history(self.TITLE_1)))):
-            assert_equal(entry["tag"], [])
-
-    def tearDown(self):
-        clear_directory(self.repo_path)
-
-    def test_add_tag(self):
-        TAG_USER = "mike_the_tagger"
-        TAG_NAME = "production"
-        TAG_VERSION = 2
-
-        # Add tag
-        self.repo.add_page_tag(self.TITLE_1, TAG_VERSION, TAG_NAME, TAG_USER)
-
-        # check history again
-        history = list(self.repo.page_history(self.TITLE_1))
-        for entry in reversed(history):
-            if entry["version"] == TAG_VERSION:
-                assert_equal(entry["tag"], [TAG_NAME])
-            else:
-                assert_equal(entry["tag"], [])
-
-    def test_add_many_tags(self):
-        TAG_USER = "mike_the_tagger"
-        tags = [
-            (2, "production", "mike"),
-            (2, "finished", "jeremy"),
-            (0, "original", "jeremy"),
-        ]
-
-        for rev, name, user in tags:
-            self.repo.add_page_tag(self.TITLE_1, rev, name, user)
-
-        # check history again
-        history = list(self.repo.page_history(self.TITLE_1))
-        for entry in reversed(history):
-            expected = [tag[1] for tag in tags if tag[0] == entry["version"]]
-            assert_equal(set(entry["tag"]), set(expected))
-
-
-if __name__ == '__main__':
-    runmodule()
diff --git a/lib/test_wlapi.py b/lib/test_wlapi.py
deleted file mode 100644 (file)
index a12ab06..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
-#
-
-from nose.tools import *
-from nose.core import runmodule
-
-import wlapi
-
-
-class FakeDocument():
-
-    def __init__(self):
-        self.text = "Some Text"
-
-
-class TestWLAPI(object):
-
-    def setUp(self):
-        self.api = wlapi.WLAPI(
-            URL="http://localhost:7000/api/",
-            AUTH_REALM="WL API",
-            AUTH_USER="platforma",
-            AUTH_PASSWD="platforma",
-        )
-
-    def test_basic_call(self):
-        assert_equal(self.api.list_books(), [])
-
-    def test_publish_book(self):
-        self.api.publish_book(FakeDocument())
-
-if __name__ == '__main__':
-    runmodule()
diff --git a/lib/vstorage.py b/lib/vstorage.py
deleted file mode 100644 (file)
index b4acaf3..0000000
+++ /dev/null
@@ -1,433 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
-#
-import os
-import tempfile
-import datetime
-import mimetypes
-import urllib
-import functools
-
-import logging
-logger = logging.getLogger('fnp.hazlenut.vstorage')
-
-# Note: we have to set these before importing Mercurial
-os.environ['HGENCODING'] = 'utf-8'
-os.environ['HGMERGE'] = "internal:merge"
-
-import mercurial.hg
-import mercurial.ui
-import mercurial.revlog
-import mercurial.util
-
-
-def urlquote(url, safe='/'):
-    """Quotes URL
-
-    >>> urlquote(u'Za\u017c\xf3\u0142\u0107 g\u0119\u015bl\u0105 ja\u017a\u0144')
-    'Za%C5%BC%C3%B3%C5%82%C4%87_g%C4%99%C5%9Bl%C4%85_ja%C5%BA%C5%84'
-    """
-    return urllib.quote(url.replace(' ', '_').encode('utf-8', 'ignore'), safe)
-
-
-def urlunquote(url):
-    """Unqotes URL
-
-    # >>> urlunquote('Za%C5%BC%C3%B3%C5%82%C4%87_g%C4%99%C5%9Bl%C4%85_ja%C5%BA%C5%84')
-    # u'Za\u017c\xf3\u0142\u0107 g\u0119\u015bl\u0105 ja\u017a\u0144'
-    """
-    return unicode(urllib.unquote(url), 'utf-8', 'ignore').replace('_', ' ')
-
-
-def find_repo_path(path):
-    """Go up the directory tree looking for a Mercurial repository (a directory containing a .hg subdirectory)."""
-    while not os.path.isdir(os.path.join(path, ".hg")):
-        old_path, path = path, os.path.dirname(path)
-        if path == old_path:
-            return None
-    return path
-
-
-def with_working_copy_locked(func):
-    """A decorator for locking the repository when calling a method."""
-
-    @functools.wraps(func)
-    def wrapped(self, *args, **kwargs):
-        """Wrap the original function in locks."""
-        wlock = self.repo.wlock()
-        try:
-            return func(self, *args, **kwargs)
-        finally:
-            wlock.release()
-    return wrapped
-
-
-def with_storage_locked(func):
-    """A decorator for locking the repository when calling a method."""
-
-    @functools.wraps(func)
-    def wrapped(self, *args, **kwargs):
-        """Wrap the original function in locks."""
-        lock = self.repo.lock()
-        try:
-            return func(self, *args, **kwargs)
-        finally:
-            lock.release()
-    return wrapped
-
-
-def guess_mime(file_name):
-    """
-    Guess file's mime type based on extension.
-    Default of text/x-wiki for files without an extension.
-
-    >>> guess_mime('something.txt')
-    'text/plain'
-    >>> guess_mime('SomePage')
-    'text/x-wiki'
-    >>> guess_mime(u'ąęśUnicodePage')
-    'text/x-wiki'
-    >>> guess_mime('image.png')
-    'image/png'
-    >>> guess_mime('style.css')
-    'text/css'
-    >>> guess_mime('archive.tar.gz')
-    'archive/gzip'
-    """
-
-    mime, encoding = mimetypes.guess_type(file_name, strict=False)
-    if encoding:
-        mime = 'archive/%s' % encoding
-    if mime is None:
-        mime = 'text/x-wiki'
-    return mime
-
-
-class DocumentNotFound(Exception):
-    pass
-
-
-class VersionedStorage(object):
-    """
-    Provides means of storing text pages and keeping track of their
-    change history, using Mercurial repository as the storage method.
-    """
-
-    def __init__(self, path, charset=None):
-        """
-        Takes the path to the directory where the pages are to be kept.
-        If the directory doen't exist, it will be created. If it's inside
-        a Mercurial repository, that repository will be used, otherwise
-        a new repository will be created in it.
-        """
-
-        self.charset = charset or 'utf-8'
-        self.path = path
-        if not os.path.exists(self.path):
-            os.makedirs(self.path)
-        self.repo_path = find_repo_path(self.path)
-
-        self.ui = mercurial.ui.ui()
-        self.ui.quiet = True
-        self.ui._report_untrusted = False
-        self.ui.setconfig('ui', 'interactive', False)
-
-        if self.repo_path is None:
-            self.repo_path = self.path
-            create = True
-        else:
-            create = False
-
-        self.repo_prefix = self.path[len(self.repo_path):].strip('/')
-        self.repo = mercurial.hg.repository(self.ui, self.repo_path,
-                                            create=create)
-
-    def reopen(self):
-        """Close and reopen the repo, to make sure we are up to date."""
-        self.repo = mercurial.hg.repository(self.ui, self.repo_path)
-
-    def _file_path(self, title):
-        return os.path.join(self.path, urlquote(title, safe=''))
-
-    def _title_to_file(self, title):
-        return os.path.join(self.repo_prefix, urlquote(title, safe=''))
-
-    def _file_to_title(self, filename):
-        assert filename.startswith(self.repo_prefix)
-        name = filename[len(self.repo_prefix):].strip('/')
-        return urlunquote(name)
-
-    def __contains__(self, title):
-        return urlquote(title) in self.repo['tip']
-
-    def __iter__(self):
-        return self.all_pages()
-
-    def merge_changes(self, changectx, repo_file, text, user, parent):
-        """Commits and merges conflicting changes in the repository."""
-        tip_node = changectx.node()
-        filectx = changectx[repo_file].filectx(parent)
-        parent_node = filectx.changectx().node()
-
-        self.repo.dirstate.setparents(parent_node)
-        node = self._commit([repo_file], text, user)
-
-        partial = lambda filename: repo_file == filename
-
-        # If p1 is equal to p2, there is no work to do. Even the dirstate is correct.
-        p1, p2 = self.repo[None].parents()[0], self.repo[tip_node]
-        if p1 == p2:
-            return text
-
-        try:
-            mercurial.merge.update(self.repo, tip_node, True, False, partial)
-            msg = 'merge of edit conflict'
-        except mercurial.util.Abort:
-            msg = 'failed merge of edit conflict'
-
-        self.repo.dirstate.setparents(tip_node, node)
-        # Mercurial 1.1 and later need updating the merge state
-        try:
-            mercurial.merge.mergestate(self.repo).mark(repo_file, "r")
-        except (AttributeError, KeyError):
-            pass
-        return msg
-
-    @with_working_copy_locked
-    @with_storage_locked
-    def save_file(self, title, file_name, **kwargs):
-        """Save an existing file as specified page."""
-
-        author = kwargs.get('author', u'anonymous').encode('utf-8')
-        comment = kwargs.get('comment', u'Empty comment.').encode('utf-8')
-        parent = kwargs.get('parent', None)
-
-        repo_file = self._title_to_file(title)
-        file_path = self._file_path(title)
-        mercurial.util.rename(file_name, file_path)
-        changectx = self._changectx()
-
-        try:
-            filectx_tip = changectx[repo_file]
-            current_page_rev = filectx_tip.filerev()
-        except mercurial.revlog.LookupError:
-            self.repo.add([repo_file])
-            current_page_rev = -1
-
-        if parent is not None and current_page_rev != parent:
-            msg = self.merge_changes(changectx, repo_file, comment, author, parent)
-            author = '<wiki>'
-            comment = msg.encode('utf-8')
-
-        self._commit([repo_file], comment, author)
-
-    def save_data(self, title, data, **kwargs):
-        """Save data as specified page."""
-        try:
-            temp_path = tempfile.mkdtemp(dir=self.path)
-            file_path = os.path.join(temp_path, 'saved')
-            f = open(file_path, "wb")
-            f.write(data)
-            f.close()
-
-            return self.save_file(title=title, file_name=file_path, **kwargs)
-        finally:
-            try:
-                os.unlink(file_path)
-            except OSError:
-                pass
-            try:
-                os.rmdir(temp_path)
-            except OSError:
-                pass
-
-    def save_text(self, **kwargs):
-        """Save text as specified page, encoded to charset."""
-        text = kwargs.pop('text')
-        return self.save_data(data=text.encode(self.charset), **kwargs)
-
-    def _commit(self, files, comment, user):
-        match = mercurial.match.exact(self.repo_path, '', list(files))
-        return self.repo.commit(match=match, text=comment, user=user, force=True)
-
-    @with_working_copy_locked
-    @with_storage_locked
-    def delete_page(self, title, author=u'', comment=u''):
-        user = author.encode('utf-8') or 'anon'
-        text = comment.encode('utf-8') or 'deleted'
-        repo_file = self._title_to_file(title)
-        file_path = self._file_path(title)
-        try:
-            os.unlink(file_path)
-        except OSError:
-            pass
-        self.repo.remove([repo_file])
-        self._commit([repo_file], text, user)
-
-    def page_text(self, title, revision=None):
-        """Read unicode text of a page."""
-        ctx = self._find_filectx(title, revision)
-
-        if ctx is None:
-            raise DocumentNotFound(title)
-
-        return ctx.data().decode(self.charset, 'replace'), ctx.filerev()
-
-    def page_text_by_tag(self, title, tag):
-        """Read unicode text of a taged page."""
-        fname = self._title_to_file(title)
-        tag = u"{fname}#{tag}".format(**locals()).encode('utf-8')
-
-        try:
-            ctx = self.repo[tag][fname]
-            return ctx.data().decode(self.charset, 'replace'), ctx.filerev()
-        except IndexError:
-            raise DocumentNotFound(fname)
-
-    @with_working_copy_locked
-    def page_file_meta(self, title):
-        """Get page's inode number, size and last modification time."""
-        try:
-            (_st_mode, st_ino, _st_dev, _st_nlink, _st_uid, _st_gid, st_size,
-             _st_atime, st_mtime, _st_ctime) = os.stat(self._file_path(title))
-        except OSError:
-            return 0, 0, 0
-        return st_ino, st_size, st_mtime
-
-    @with_working_copy_locked
-    def page_meta(self, title, revision=None):
-        """Get page's revision, date, last editor and his edit comment."""
-        fctx = self._find_filectx(title, revision)
-
-        if fctx is None:
-            raise DocumentNotFound(title)
-
-        return {
-            "revision": fctx.filerev(),
-            "date": datetime.datetime.fromtimestamp(fctx.date()[0]),
-            "author": fctx.user().decode("utf-8", 'replace'),
-            "comment": fctx.description().decode("utf-8", 'replace'),
-        }
-
-    def repo_revision(self):
-        return self.repo['tip'].rev()
-
-    def _changectx(self):
-        return self.repo['tip']
-
-    def page_mime(self, title):
-        """
-        Guess page's mime type based on corresponding file name.
-        Default ot text/x-wiki for files without an extension.
-        """
-        return guess_mime(self._file_path(title))
-
-    def _find_filectx(self, title, rev=None):
-        """Find the last revision in which the file existed."""
-        repo_file = self._title_to_file(title)
-        changectx = self._changectx()  # start with tip
-        visited = set()
-
-        stack = [changectx]
-        visited.add(changectx)
-
-        while repo_file not in changectx:
-            if not stack:
-                raise DocumentNotFound(title)
-
-            changectx = stack.pop()
-            for parent in changectx.parents():
-                if parent not in visited:
-                    stack.append(parent)
-                    visited.add(parent)
-
-        try:
-            fctx = changectx[repo_file]
-
-            if rev is not None:
-                fctx = fctx.filectx(rev)
-                fctx.filerev()
-
-            return fctx
-        except (IndexError, LookupError) as e:
-            raise DocumentNotFound(title)
-
-    def page_history(self, title):
-        """Iterate over the page's history."""
-
-        filectx_tip = self._find_filectx(title)
-
-        maxrev = filectx_tip.filerev()
-        minrev = 0
-        for rev in range(maxrev, minrev - 1, -1):
-            filectx = filectx_tip.filectx(rev)
-            date = datetime.datetime.fromtimestamp(filectx.date()[0])
-            author = filectx.user().decode('utf-8', 'replace')
-            comment = filectx.description().decode("utf-8", 'replace')
-            tags = [t.rsplit('#', 1)[-1] for t in filectx.changectx().tags() if '#' in t]
-
-            yield {
-                "version": rev,
-                "date": date,
-                "author": author,
-                "description": comment,
-                "tag": tags,
-            }
-
-    @with_working_copy_locked
-    def add_page_tag(self, title, rev, tag, user, doctag=True):
-        ctitle = self._title_to_file(title)
-
-        if doctag:
-            tag = u"{ctitle}#{tag}".format(**locals()).encode('utf-8')
-
-        message = u"Assigned tag {tag!r} to version {rev!r} of {ctitle!r}".format(**locals()).encode('utf-8')
-
-        fctx = self._find_filectx(title, rev)
-        self.repo.tag(
-            names=tag, node=fctx.node(), local=False,
-            user=user, message=message, date=None,
-        )
-
-    def history(self):
-        """Iterate over the history of entire wiki."""
-
-        changectx = self._changectx()
-        maxrev = changectx.rev()
-        minrev = 0
-        for wiki_rev in range(maxrev, minrev - 1, -1):
-            change = self.repo.changectx(wiki_rev)
-            date = datetime.datetime.fromtimestamp(change.date()[0])
-            author = change.user().decode('utf-8', 'replace')
-            comment = change.description().decode("utf-8", 'replace')
-            for repo_file in change.files():
-                if repo_file.startswith(self.repo_prefix):
-                    title = self._file_to_title(repo_file)
-                    try:
-                        rev = change[repo_file].filerev()
-                    except mercurial.revlog.LookupError:
-                        rev = -1
-                    yield title, rev, date, author, comment
-
-    def all_pages(self):
-        tip = self.repo['tip']
-        """Iterate over the titles of all pages in the wiki."""
-        return [urlunquote(filename) for filename in tip]
-
-    def changed_since(self, rev):
-        """Return all pages that changed since specified repository revision."""
-
-        try:
-            last = self.repo.lookup(int(rev))
-        except IndexError:
-            for page in self.all_pages():
-                yield page
-                return
-        current = self.repo.lookup('tip')
-        status = self.repo.status(current, last)
-        modified, added, removed, deleted, unknown, ignored, clean = status
-        for filename in modified + added + removed + deleted:
-            if filename.startswith(self.repo_prefix):
-                yield self._file_to_title(filename)
diff --git a/lib/vstorage/__init__.py b/lib/vstorage/__init__.py
new file mode 100644 (file)
index 0000000..843bb6b
--- /dev/null
@@ -0,0 +1,451 @@
+# -*- coding: utf-8 -*-
+#
+# This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
+import os
+import tempfile
+import datetime
+import mimetypes
+import urllib
+import functools
+
+import logging
+logger = logging.getLogger('fnp.hazlenut.vstorage')
+
+# Note: we have to set these before importing Mercurial
+os.environ['HGENCODING'] = 'utf-8'
+os.environ['HGMERGE'] = "internal:merge"
+
+import mercurial.hg
+import mercurial.revlog
+import mercurial.util
+
+from vstorage.hgui import SilentUI
+
+
+def urlquote(url, safe='/'):
+    """Quotes URL
+
+    >>> urlquote(u'Za\u017c\xf3\u0142\u0107 g\u0119\u015bl\u0105 ja\u017a\u0144')
+    'Za%C5%BC%C3%B3%C5%82%C4%87%20g%C4%99%C5%9Bl%C4%85%20ja%C5%BA%C5%84'
+    """
+    return urllib.quote(url.encode('utf-8', 'ignore'), safe)
+
+
+def urlunquote(url):
+    """Unqotes URL
+
+    # >>> urlunquote('Za%C5%BC%C3%B3%C5%82%C4%87_g%C4%99%C5%9Bl%C4%85_ja%C5%BA%C5%84')
+    # u'Za\u017c\xf3\u0142\u0107_g\u0119\u015bl\u0105 ja\u017a\u0144'
+    """
+    return unicode(urllib.unquote(url), 'utf-8', 'ignore')
+
+
+def find_repo_path(path):
+    """Go up the directory tree looking for a Mercurial repository (a directory containing a .hg subdirectory)."""
+    while not os.path.isdir(os.path.join(path, ".hg")):
+        old_path, path = path, os.path.dirname(path)
+        if path == old_path:
+            return None
+    return path
+
+
+def with_working_copy_locked(func):
+    """A decorator for locking the repository when calling a method."""
+
+    @functools.wraps(func)
+    def wrapped(self, *args, **kwargs):
+        """Wrap the original function in locks."""
+        wlock = self.repo.wlock()
+        try:
+            return func(self, *args, **kwargs)
+        finally:
+            wlock.release()
+    return wrapped
+
+
+def with_storage_locked(func):
+    """A decorator for locking the repository when calling a method."""
+
+    @functools.wraps(func)
+    def wrapped(self, *args, **kwargs):
+        """Wrap the original function in locks."""
+        lock = self.repo.lock()
+        try:
+            return func(self, *args, **kwargs)
+        finally:
+            lock.release()
+    return wrapped
+
+
+def guess_mime(file_name):
+    """
+    Guess file's mime type based on extension.
+    Default of text/x-wiki for files without an extension.
+
+    >>> guess_mime('something.txt')
+    'text/plain'
+    >>> guess_mime('SomePage')
+    'text/x-wiki'
+    >>> guess_mime(u'ąęśUnicodePage')
+    'text/x-wiki'
+    >>> guess_mime('image.png')
+    'image/png'
+    >>> guess_mime('style.css')
+    'text/css'
+    >>> guess_mime('archive.tar.gz')
+    'archive/gzip'
+    """
+
+    mime, encoding = mimetypes.guess_type(file_name, strict=False)
+    if encoding:
+        mime = 'archive/%s' % encoding
+    if mime is None:
+        mime = 'text/x-wiki'
+    return mime
+
+
+class DocumentNotFound(Exception):
+    pass
+
+
+class VersionedStorage(object):
+    """
+    Provides means of storing text pages and keeping track of their
+    change history, using Mercurial repository as the storage method.
+    """
+
+    def __init__(self, path, charset=None):
+        """
+        Takes the path to the directory where the pages are to be kept.
+        If the directory doen't exist, it will be created. If it's inside
+        a Mercurial repository, that repository will be used, otherwise
+        a new repository will be created in it.
+        """
+
+        self.charset = charset or 'utf-8'
+        self.path = path
+        if not os.path.exists(self.path):
+            os.makedirs(self.path)
+        self.repo_path = find_repo_path(self.path)
+
+        self.ui = SilentUI()
+
+        if self.repo_path is None:
+            self.repo_path = self.path
+            create = True
+        else:
+            create = False
+
+        self.repo_prefix = self.path[len(self.repo_path):].strip('/')
+        self.repo = mercurial.hg.repository(self.ui, self.repo_path,
+                                            create=create)
+
+    def reopen(self):
+        """Close and reopen the repo, to make sure we are up to date."""
+        self.repo = mercurial.hg.repository(self.ui, self.repo_path)
+
+    def _file_path(self, title, type='.xml'):
+        return os.path.join(self.path, urlquote(title, safe='')) + type
+
+    def _title_to_file(self, title, type=".xml"):
+        return os.path.join(self.repo_prefix, urlquote(title, safe='')) + type
+
+    def _file_to_title(self, filename):
+        assert filename.startswith(self.repo_prefix)
+        name = filename[len(self.repo_prefix):].strip('/').split('.', 1)[0]
+        return urlunquote(name)
+
+    def __contains__(self, title):
+        return self._title_to_file(title) in self.repo['tip']
+
+    def __iter__(self):
+        return self.all_pages()
+
+    def merge_changes(self, changectx, repo_file, text, user, parent):
+        """Commits and merges conflicting changes in the repository."""
+        tip_node = changectx.node()
+        filectx = changectx[repo_file].filectx(parent)
+        parent_node = filectx.changectx().node()
+
+        self.repo.dirstate.setparents(parent_node)
+        node = self._commit([repo_file], text, user)
+
+        partial = lambda filename: repo_file == filename
+
+        # If p1 is equal to p2, there is no work to do. Even the dirstate is correct.
+        p1, p2 = self.repo[None].parents()[0], self.repo[tip_node]
+        if p1 == p2:
+            return text
+
+        try:
+            mercurial.merge.update(self.repo, tip_node, True, False, partial)
+            msg = 'merge of edit conflict'
+        except mercurial.util.Abort:
+            msg = 'failed merge of edit conflict'
+
+        self.repo.dirstate.setparents(tip_node, node)
+        # Mercurial 1.1 and later need updating the merge state
+        try:
+            mercurial.merge.mergestate(self.repo).mark(repo_file, "r")
+        except (AttributeError, KeyError):
+            pass
+        return msg
+
+    @with_working_copy_locked
+    @with_storage_locked
+    def save_file(self, title, file_name, **kwargs):
+        """Save an existing file as specified page."""
+
+        author = kwargs.get('author', u'anonymous').encode('utf-8')
+        comment = kwargs.get('comment', u'Empty comment.').encode('utf-8')
+        parent = kwargs.get('parent', None)
+
+        repo_file = self._title_to_file(title)
+        file_path = self._file_path(title)
+        mercurial.util.rename(file_name, file_path)
+        changectx = self._changectx()
+
+        try:
+            filectx_tip = changectx[repo_file]
+            current_page_rev = filectx_tip.filerev()
+        except mercurial.revlog.LookupError:
+            self.repo.add([repo_file])
+            current_page_rev = -1
+
+        if parent is not None and current_page_rev != parent:
+            msg = self.merge_changes(changectx, repo_file, comment, author, parent)
+            author = '<wiki>'
+            comment = msg.encode('utf-8')
+
+        logger.debug("Commiting %r", repo_file)
+
+        self._commit([repo_file], comment, author)
+
+    def save_data(self, title, data, **kwargs):
+        """Save data as specified page."""
+        try:
+            temp_path = tempfile.mkdtemp(dir=self.path)
+            file_path = os.path.join(temp_path, 'saved')
+            f = open(file_path, "wb")
+            f.write(data)
+            f.close()
+
+            return self.save_file(title=title, file_name=file_path, **kwargs)
+        finally:
+            try:
+                os.unlink(file_path)
+            except OSError:
+                pass
+            try:
+                os.rmdir(temp_path)
+            except OSError:
+                pass
+
+    def save_text(self, **kwargs):
+        """Save text as specified page, encoded to charset."""
+        text = kwargs.pop('text')
+        return self.save_data(data=text.encode(self.charset), **kwargs)
+
+    def _commit(self, files, comment, user):
+        match = mercurial.match.exact(self.repo_path, '', list(files))
+        return self.repo.commit(match=match, text=comment, user=user, force=True)
+
+    @with_working_copy_locked
+    @with_storage_locked
+    def delete_page(self, title, author=u'', comment=u''):
+        user = author.encode('utf-8') or 'anon'
+        text = comment.encode('utf-8') or 'deleted'
+        repo_file = self._title_to_file(title)
+        file_path = self._file_path(title)
+        try:
+            os.unlink(file_path)
+        except OSError:
+            pass
+        self.repo.remove([repo_file])
+        self._commit([repo_file], text, user)
+
+    def page_text(self, title, revision=None):
+        """Read unicode text of a page."""
+        ctx = self._find_filectx(title, revision)
+
+        if ctx is None:
+            raise DocumentNotFound(title)
+
+        return ctx.data().decode(self.charset, 'replace'), ctx.filerev()
+
+    def page_text_by_tag(self, title, tag):
+        """Read unicode text of a taged page."""
+        fname = self._title_to_file(title)
+        tag = u"{fname}#{tag}".format(**locals()).encode('utf-8')
+
+        try:
+            ctx = self.repo[tag][fname]
+            return ctx.data().decode(self.charset, 'replace'), ctx.filerev()
+        except IndexError:
+            raise DocumentNotFound(fname)
+
+    @with_working_copy_locked
+    def page_file_meta(self, title):
+        """Get page's inode number, size and last modification time."""
+        try:
+            (_st_mode, st_ino, _st_dev, _st_nlink, _st_uid, _st_gid, st_size,
+             _st_atime, st_mtime, _st_ctime) = os.stat(self._file_path(title))
+        except OSError:
+            return 0, 0, 0
+        return st_ino, st_size, st_mtime
+
+    @with_working_copy_locked
+    def page_meta(self, title, revision=None):
+        """Get page's revision, date, last editor and his edit comment."""
+        fctx = self._find_filectx(title, revision)
+
+        if fctx is None:
+            raise DocumentNotFound(title)
+
+        return {
+            "revision": fctx.filerev(),
+            "date": datetime.datetime.fromtimestamp(fctx.date()[0]),
+            "author": fctx.user().decode("utf-8", 'replace'),
+            "comment": fctx.description().decode("utf-8", 'replace'),
+        }
+
+    def repo_revision(self):
+        return self.repo['tip'].rev()
+
+    def _changectx(self):
+        return self.repo['tip']
+
+    def page_mime(self, title):
+        """
+        Guess page's mime type based on corresponding file name.
+        Default ot text/x-wiki for files without an extension.
+        """
+        return guess_mime(self._file_path(title))
+
+    def _find_filectx(self, title, rev=None):
+        """Find the last revision in which the file existed."""
+        tip = self._changectx()  # start with tip
+
+        def tree_search(tip, repo_file):
+            logging.info("Searching for %r", repo_file)
+            current = tip
+            visited = set()
+
+            stack = [current]
+            visited.add(current)
+
+            while repo_file not in current:
+                if not stack:
+                    raise LookupError
+
+                current = stack.pop()
+                for parent in current.parents():
+                    if parent not in visited:
+                        stack.append(parent)
+                        visited.add(parent)
+
+            fctx = current[repo_file]
+            if rev is not None:
+                fctx = fctx.filectx(rev)
+                fctx.filerev()
+            return fctx
+
+        try:
+            return tree_search(tip, self._title_to_file(title))
+        except (IndexError, LookupError):
+            logging.info("XML file not found, trying plain")
+            try:
+                return tree_search(tip, self._title_to_file(title, type=''))
+            except (IndexError, LookupError):
+                raise DocumentNotFound(title)
+
+    def page_history(self, title):
+        """Iterate over the page's history."""
+
+        filectx_tip = self._find_filectx(title)
+
+        maxrev = filectx_tip.filerev()
+        minrev = 0
+        for rev in range(maxrev, minrev - 1, -1):
+            filectx = filectx_tip.filectx(rev)
+            date = datetime.datetime.fromtimestamp(filectx.date()[0])
+            author = filectx.user().decode('utf-8', 'replace')
+            comment = filectx.description().decode("utf-8", 'replace')
+            tags = [t.rsplit('#', 1)[-1] for t in filectx.changectx().tags() if '#' in t]
+
+            yield {
+                "version": rev,
+                "date": date,
+                "author": author,
+                "description": comment,
+                "tag": tags,
+            }
+
+    @with_working_copy_locked
+    def add_page_tag(self, title, rev, tag, user, doctag=True):
+        ctitle = self._title_to_file(title)
+
+        if doctag:
+            tag = u"{ctitle}#{tag}".format(**locals()).encode('utf-8')
+
+        message = u"Assigned tag {tag!r} to version {rev!r} of {ctitle!r}".format(**locals()).encode('utf-8')
+
+        fctx = self._find_filectx(title, rev)
+        self.repo.tag(
+            names=tag, node=fctx.node(), local=False,
+            user=user, message=message, date=None,
+        )
+
+    def history(self):
+        """Iterate over the history of entire wiki."""
+
+        changectx = self._changectx()
+        maxrev = changectx.rev()
+        minrev = 0
+        for wiki_rev in range(maxrev, minrev - 1, -1):
+            change = self.repo.changectx(wiki_rev)
+            date = datetime.datetime.fromtimestamp(change.date()[0])
+            author = change.user().decode('utf-8', 'replace')
+            comment = change.description().decode("utf-8", 'replace')
+            for repo_file in change.files():
+                if repo_file.startswith(self.repo_prefix):
+                    title = self._file_to_title(repo_file)
+                    try:
+                        rev = change[repo_file].filerev()
+                    except mercurial.revlog.LookupError:
+                        rev = -1
+                    yield title, rev, date, author, comment
+
+    def all_pages(self, type=''):
+        tip = self.repo['tip']
+        """Iterate over the titles of all pages in the wiki."""
+        return [self._file_to_title(filename) for filename in tip
+                  if not filename.startswith('.')
+                    and filename.endswith(type) ]
+
+    def changed_since(self, rev):
+        """Return all pages that changed since specified repository revision."""
+
+        try:
+            last = self.repo.lookup(int(rev))
+        except IndexError:
+            for page in self.all_pages():
+                yield page
+                return
+        current = self.repo.lookup('tip')
+        status = self.repo.status(current, last)
+        modified, added, removed, deleted, unknown, ignored, clean = status
+        for filename in modified + added + removed + deleted:
+            if filename.startswith(self.repo_prefix):
+                yield self._file_to_title(filename)
+
+    def revert(self, pageid, rev, **commit_args):
+        """ Make the given version of page the current version (reverting changes). """
+
+        # Find the old version
+        fctx = self._find_filectx(pageid, rev)
+
+        # Restore the contents
+        self.save_data(pageid, fctx.data(), **commit_args)
diff --git a/lib/vstorage/hgui.py b/lib/vstorage/hgui.py
new file mode 100644 (file)
index 0000000..36c6e23
--- /dev/null
@@ -0,0 +1,57 @@
+"""
+    Mercurial ui module replacement.
+"""
+
+import mercurial.ui
+import logging
+
+class SilentUI(mercurial.ui.ui):
+
+    def __init__(self, *args, **kwargs):
+        super(SilentUI, self).__init__(*args, **kwargs)
+
+        # make sure this doesn't collide with anything in Mercurial
+        self.__logger = logging.getLogger('mercurial')
+
+    def _is_trusted(self, fd, filename):
+        """ Checks if config file is trusted - on server side, this isn't very useful. """
+        return True
+
+    def write(self, *args):
+        if self._buffers:
+            self._buffers[-1].extend([str(a) for a in args])
+        else:
+            self.__logger.info(''.join(args))
+
+    def write_err(self, *args):
+        self.__logger.error(''.join(args))
+
+    def flush(self):
+        pass
+
+    def interactive(self):
+        return False
+
+    def _readline(self, prompt=''):
+        return u''
+
+    def status(self, *msg):
+        self.__logger.debug(''.join(msg))
+
+    def warn(self, *msg):
+        self.__logger.warn(''.join(msg))
+
+    def note(self, *msg):
+        self.__logger.info(''.join(msg))
+
+    def debug(self, *msg):
+        self.__logger.debug(''.join(msg))
+
+    def edit(self, text, user):
+        return text
+
+    def traceback(self, exc=None):
+        if exc is not None: self.__logger.exception()
+
+    def progress(self, *args, **kwargs):
+        pass
diff --git a/lib/vstorage/tests.py b/lib/vstorage/tests.py
new file mode 100644 (file)
index 0000000..25e2b06
--- /dev/null
@@ -0,0 +1,241 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
+
+import os
+import tempfile
+from nose.tools import *
+from nose.core import runmodule
+
+import vstorage
+
+def clear_directory(top):
+    for root, dirs, files in os.walk(top, topdown=False):
+        for name in files:
+            os.remove(os.path.join(root, name))
+        for name in dirs:
+            os.rmdir(os.path.join(root, name))
+    try:
+        os.removedirs(top)
+    except OSError:
+        pass
+
+
+class TestVersionedStorage(object):
+    def setUp(self):
+        self.repo_path = tempfile.mkdtemp()
+        self.repo = vstorage.VersionedStorage(self.repo_path)
+
+    def tearDown(self):
+        clear_directory(self.repo_path)
+
+    def test_save_text(self):
+        text = u"test text"
+        title = u"test title"
+        author = u"test author"
+        comment = u"test comment"
+
+        self.repo.save_text(
+            title=title,
+            text=text,
+            author=author,
+            comment=comment,
+            parent=None,
+        )
+
+        saved_text, rev = self.repo.page_text(title)
+        assert_equal(saved_text, text)
+        assert_equal(rev, 0)
+
+    def test_save_text_noparent(self):
+        text = u"test text"
+        title = u"test title"
+        author = u"test author"
+        comment = u"test comment"
+
+        self.repo.save_text(title=title,
+                    text=text, author=author,
+                    comment=comment, parent=None)
+
+
+        saved_text, rev = self.repo.page_text(title)
+        assert_equal(saved_text, text)
+        assert_equal(rev, 0)
+
+    def test_save_merge_no_conflict(self):
+        text = u"test\ntext"
+        title = u"test title"
+        author = u"test author"
+        comment = u"test comment"
+        self.repo.save_text(title=title,
+                    text=text, author=author,
+                    comment=comment, parent=None)
+        self.repo.save_text(title=title,
+                    text=text, author=author,
+                    comment=comment, parent=None)
+
+        saved_text, rev = self.repo.page_text(title)
+        assert_equal(saved_text, text)
+        assert_equal(rev, 0)
+
+    def test_save_merge_line_conflict(self):
+        text = u"test\ntest\n"
+        text1 = u"test\ntext\n"
+        text2 = u"text\ntest\n"
+        title = u"test title"
+        author = u"test author"
+        comment = u"test comment"
+
+        self.repo.save_text(title=title,
+                    text=text, author=author,
+                    comment=comment, parent=None)
+
+        saved_text, rev = self.repo.page_text(title)
+        assert_equal(saved_text, text)
+        assert_equal(rev, 0)
+
+        self.repo.save_text(title=title,
+                    text=text1, author=author,
+                    comment=comment, parent=0)
+
+        saved_text, rev = self.repo.page_text(title)
+        assert_equal(saved_text, text1)
+        assert_equal(rev, 1)
+
+        self.repo.save_text(title=title,
+                    text=text2, author=author,
+                    comment=comment, parent=0)
+
+        saved_text, rev = self.repo.page_text(title)
+        # Other conflict markers placement can also be correct
+        assert_equal(saved_text, u'''\
+text
+test
+<<<<<<< local
+=======
+text
+>>>>>>> other
+''')
+
+    def test_delete(self):
+        text = u"text test"
+        title = u"test title"
+        author = u"test author"
+        comment = u"test comment"
+        self.repo.save_text(title=title,
+                    text=text, author=author,
+                    comment=comment, parent=None)
+
+        ok_(title in self.repo, "Document not in repository.")
+
+        self.repo.delete_page(title, author, comment)
+
+        ok_(title not in self.repo, "Document in repository after delete")
+
+    @raises(vstorage.DocumentNotFound)
+    def test_document_not_found(self):
+        self.repo.page_text(u'unknown entity')
+
+    def test_open_existing_repository(self):
+        self.repo.save_text(title=u'Python!', text=u'ham and spam')
+        current_repo_revision = self.repo.repo_revision()
+        same_repo = vstorage.VersionedStorage(self.repo_path)
+        assert_equal(same_repo.repo_revision(), current_repo_revision)
+
+    def test_history(self):
+        COMMITS = [
+            {"author": "bunny", "text":"1", "comment": "Oh yeah!"},
+            {"author": "frank", "text":"2", "comment": "Second is the best!"},
+            {"text":"3", "comment": "Third"},
+            {"author": "welma", "text":"4", "comment": "Fourth"},
+        ]
+
+        for commit in COMMITS:
+            self.repo.save_text(title=u"Sample", **commit)
+
+        for n, entry in enumerate(reversed(list(self.repo.page_history(u"Sample")))):
+            assert_equal(entry["version"], n)
+            assert_equal(entry["author"], COMMITS[n].get("author", "anonymous"))
+            assert_equal(entry["description"], COMMITS[n]["comment"])
+            assert_equal(entry["tag"], [])
+
+    def test_data_revert(self):
+        COMMITS = [
+            {u"title": u"one", "author": "bunny", "text":"1.1", "comment": "1"},
+            {u"title": u"one", "author": "frank", "text":"1.2", "comment": "2"},
+            {u"title": u"two", "author": "bunny", "text":"2.1", "comment": "3"},
+            {u"title": u"one", "author": "frank", "text":"1.3", "comment": "4"},
+        ]
+
+        for commit in COMMITS:
+            self.repo.save_text(**commit)
+
+        # now revert last change on one
+        self.repo.revert(u"one", 0)
+        assert_equal(self.repo.page_text(u"one"), (u"1.1", 3))
+        assert_equal(self.repo.page_text(u"two"), (u"2.1", 0))
+
+        self.repo.revert(u"one", 2)
+        assert_equal(self.repo.page_text(u"one"), (u"1.3", 4))
+
+class TestVSTags(object):
+
+    TITLE_1 = "Sample"
+
+    COMMITS = [
+        {"author": "bunny", "text":"1", "comment": "Oh yeah!"},
+        {"author": "frank", "text":"2", "comment": "Second is the best!"},
+        {"text":"3", "comment": "Third"},
+        {"author": "welma", "text":"4", "comment": "Fourth"},
+    ]
+
+    def setUp(self):
+        self.repo_path = tempfile.mkdtemp()
+        self.repo = vstorage.VersionedStorage(self.repo_path)
+
+        # generate some history
+        for commit in self.COMMITS:
+            self.repo.save_text(title=u"Sample", **commit)
+
+        # verify
+        for n, entry in enumerate(reversed(list(self.repo.page_history(self.TITLE_1)))):
+            assert_equal(entry["tag"], [])
+
+    def tearDown(self):
+        clear_directory(self.repo_path)
+
+    def test_add_tag(self):
+        TAG_USER = "mike_the_tagger"
+        TAG_NAME = "production"
+        TAG_VERSION = 2
+
+        # Add tag
+        self.repo.add_page_tag(self.TITLE_1, TAG_VERSION, TAG_NAME, TAG_USER)
+
+        # check history again
+        history = list(self.repo.page_history(self.TITLE_1))
+        for entry in reversed(history):
+            if entry["version"] == TAG_VERSION:
+                assert_equal(entry["tag"], [TAG_NAME])
+            else:
+                assert_equal(entry["tag"], [])
+
+    def test_add_many_tags(self):
+        TAG_USER = "mike_the_tagger"
+        tags = [
+            (2, "production", "mike"),
+            (2, "finished", "jeremy"),
+            (0, "original", "jeremy"),
+        ]
+
+        for rev, name, user in tags:
+            self.repo.add_page_tag(self.TITLE_1, rev, name, user)
+
+        # check history again
+        history = list(self.repo.page_history(self.TITLE_1))
+        for entry in reversed(history):
+            expected = [tag[1] for tag in tags if tag[0] == entry["version"]]
+            assert_equal(set(entry["tag"]), set(expected))
diff --git a/lib/wlapi.py b/lib/wlapi.py
deleted file mode 100644 (file)
index 3284211..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
-#
-"""
-   Abstraction over API for wolnelektury.pl
-"""
-import urllib2
-import functools
-import django.utils.simplejson as json
-import logging
-logger = logging.getLogger("fnp.lib.wlapi")
-
-
-class APICallException(Exception):
-
-    def __init__(self, cause=None):
-        super(Exception, self).__init__()
-        self.cause = cause
-
-    def __unicode__(self):
-        return u"%s, cause: %s" % (type(self).__name__, repr(self.cause))
-
-    def __str__(self):
-        return self.__unicode__().encode('utf-8')
-
-
-def api_call(path, format="json"):
-    def wrapper(func):
-
-        @functools.wraps(func)
-        def wrapped(self, *args, **kwargs):
-            generator = func(self, *args, **kwargs)
-
-            data = generator.next()
-
-            # prepare request
-            rq = urllib2.Request(self.base_url + path + ".json")
-
-            # will send POST when there is data, GET otherwise
-            if data is not None:
-                rq.add_data(json.dumps(data))
-                rq.add_header("Content-Type", "application/json")
-
-            try:
-                anwser = json.load(self.opener.open(rq))
-                return generator.send(anwser)
-            except StopIteration:
-                # by default, just return the anwser as a shorthand
-                return anwser
-            except urllib2.HTTPError, error:
-                return self._http_error(error)
-            except Exception, error:
-                return self._error(error)
-        return wrapped
-
-    return wrapper
-
-
-class WLAPI(object):
-
-    def __init__(self, **config_dict):
-        self.base_url = config_dict['URL']
-        self.auth_realm = config_dict['AUTH_REALM']
-        self.auth_user = config_dict['AUTH_USER']
-
-        digest_handler = urllib2.HTTPDigestAuthHandler()
-        digest_handler.add_password(
-                    realm=self.auth_realm, uri=self.base_url,
-                    user=self.auth_user, passwd=config_dict['AUTH_PASSWD'])
-
-        basic_handler = urllib2.HTTPBasicAuthHandler()
-        basic_handler.add_password(
-                    realm=self.auth_realm, uri=self.base_url,
-                    user=self.auth_user, passwd=config_dict['AUTH_PASSWD'])
-
-        self.opener = urllib2.build_opener(digest_handler, basic_handler)
-
-    def _http_error(self, error):
-        message = error.read()
-        logger.debug("HTTP ERROR: %s", message)
-        return self._error(message)
-
-    def _error(self, error):
-        raise APICallException(error)
-
-    @api_call("books")
-    def list_books(self):
-        yield
-
-    @api_call("books")
-    def publish_book(self, document):
-        yield {"text": document.text, "compressed": False}
diff --git a/lib/wlapi/__init__.py b/lib/wlapi/__init__.py
new file mode 100644 (file)
index 0000000..3284211
--- /dev/null
@@ -0,0 +1,94 @@
+# -*- coding: utf-8 -*-
+#
+# This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
+"""
+   Abstraction over API for wolnelektury.pl
+"""
+import urllib2
+import functools
+import django.utils.simplejson as json
+import logging
+logger = logging.getLogger("fnp.lib.wlapi")
+
+
+class APICallException(Exception):
+
+    def __init__(self, cause=None):
+        super(Exception, self).__init__()
+        self.cause = cause
+
+    def __unicode__(self):
+        return u"%s, cause: %s" % (type(self).__name__, repr(self.cause))
+
+    def __str__(self):
+        return self.__unicode__().encode('utf-8')
+
+
+def api_call(path, format="json"):
+    def wrapper(func):
+
+        @functools.wraps(func)
+        def wrapped(self, *args, **kwargs):
+            generator = func(self, *args, **kwargs)
+
+            data = generator.next()
+
+            # prepare request
+            rq = urllib2.Request(self.base_url + path + ".json")
+
+            # will send POST when there is data, GET otherwise
+            if data is not None:
+                rq.add_data(json.dumps(data))
+                rq.add_header("Content-Type", "application/json")
+
+            try:
+                anwser = json.load(self.opener.open(rq))
+                return generator.send(anwser)
+            except StopIteration:
+                # by default, just return the anwser as a shorthand
+                return anwser
+            except urllib2.HTTPError, error:
+                return self._http_error(error)
+            except Exception, error:
+                return self._error(error)
+        return wrapped
+
+    return wrapper
+
+
+class WLAPI(object):
+
+    def __init__(self, **config_dict):
+        self.base_url = config_dict['URL']
+        self.auth_realm = config_dict['AUTH_REALM']
+        self.auth_user = config_dict['AUTH_USER']
+
+        digest_handler = urllib2.HTTPDigestAuthHandler()
+        digest_handler.add_password(
+                    realm=self.auth_realm, uri=self.base_url,
+                    user=self.auth_user, passwd=config_dict['AUTH_PASSWD'])
+
+        basic_handler = urllib2.HTTPBasicAuthHandler()
+        basic_handler.add_password(
+                    realm=self.auth_realm, uri=self.base_url,
+                    user=self.auth_user, passwd=config_dict['AUTH_PASSWD'])
+
+        self.opener = urllib2.build_opener(digest_handler, basic_handler)
+
+    def _http_error(self, error):
+        message = error.read()
+        logger.debug("HTTP ERROR: %s", message)
+        return self._error(message)
+
+    def _error(self, error):
+        raise APICallException(error)
+
+    @api_call("books")
+    def list_books(self):
+        yield
+
+    @api_call("books")
+    def publish_book(self, document):
+        yield {"text": document.text, "compressed": False}
diff --git a/lib/wlapi/tests.py b/lib/wlapi/tests.py
new file mode 100644 (file)
index 0000000..a12ab06
--- /dev/null
@@ -0,0 +1,37 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
+
+from nose.tools import *
+from nose.core import runmodule
+
+import wlapi
+
+
+class FakeDocument():
+
+    def __init__(self):
+        self.text = "Some Text"
+
+
+class TestWLAPI(object):
+
+    def setUp(self):
+        self.api = wlapi.WLAPI(
+            URL="http://localhost:7000/api/",
+            AUTH_REALM="WL API",
+            AUTH_USER="platforma",
+            AUTH_PASSWD="platforma",
+        )
+
+    def test_basic_call(self):
+        assert_equal(self.api.list_books(), [])
+
+    def test_publish_book(self):
+        self.api.publish_book(FakeDocument())
+
+if __name__ == '__main__':
+    runmodule()
diff --git a/localsettings.sample b/localsettings.sample
deleted file mode 100644 (file)
index c174cf9..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-# 
-#  localsettings template for Platforma
-#
-#  Duplicate this file as localsettings.py and change it to your liking.
-#  Settings defined in localsettings.py will override settings from 
-#  settings.py file. localsettings.py should never be commited 
-#  to a version control system. Please make changes to settings.py 
-#  or localsettings.sample instead.
-#
-
-# Path to repository with managed documents
-REPOSITORY_PATH = '/home/user/repository'
-
-# Subdirectory of STATIC_ROOT containing images
-IMAGE_DIR = 'images'
-
-CAS_SERVICE_URL = 'http://stigma.nowoczesnapolska.org.pl/cas/'
-
index 9bfa56c..23a7833 100644 (file)
@@ -23,7 +23,7 @@ datefmt=
 class=logging.Formatter
 
 [handler_console]
-class=StreamHandler
+class=FileHandler
 level=DEBUG
 formatter=default
-args=(sys.stderr, ) 
\ No newline at end of file
+args=('redakcja.dev.log', ) 
index fbd21a9..0c56cbd 100644 (file)
@@ -1,20 +1,18 @@
 <VirtualHost *:80>
     ServerName $DOMAIN
-    ServerAlias $DOMAIN_ALIASES
     ServerAdmin $ADMIN_EMAIL
 
     WSGIDaemonProcess $PROJECT_NAME user=$WSGI_USER group=$WSGI_USER processes=$WSGI_PROCESSES threads=$WSGI_THREADS display-name=%{GROUP}
     WSGIProcessGroup $PROJECT_NAME
 
-    WSGIScriptAlias / $WSGI_TARGET
+    WSGIScriptAlias / $WSGI_FILE
     <Directory $WSGI_DIR>
         Order allow,deny
         allow from all
     </Directory>
 
-    Alias /media $MEDIA_ROOT
-    <Directory $MEDIA_ROOT >
-        Options Indexes, FollowLinks
+    Alias /media $MEDIA_DIR
+    <Directory $MEDIA_DIR>
         Order allow,deny
         Allow from all
     </Directory>
index 6b772f3..d271fa1 100644 (file)
@@ -1,4 +1,4 @@
-#!$PYTHON
+#!$PYTHON_BIN
 import site
 site.addsitedir('$PYTHON_SITE')
 
@@ -12,9 +12,9 @@ sys.stdout = sys.stderr
 
 # Add apps and lib directories to PYTHONPATH
 sys.path = [
-    '$PROJECT_ROOT',
-       '$PROJECT_ROOT/lib',
-       '$PROJECT_ROOT/apps',
+    '$APP_DIR',
+       '$APP_DIR/lib',
+       '$APP_DIR/apps',
 ] + sys.path
 
 # Run Django
diff --git a/redakcja/compress_settings.py b/redakcja/compress_settings.py
deleted file mode 100644 (file)
index fa416c4..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-# CSS and JS files to compress
-COMPRESS_CSS = {
-    'detail': {
-         'source_filenames': (
-            'css/master.css',
-            'css/gallery.css',
-            'css/history.css',
-            'css/summary.css',
-            'css/html.css',
-            'css/jquery.autocomplete.css',
-            'css/dialogs.css',
-        ),
-        'output_filename': 'compressed/detail_styles_?.css',
-    },
-    'listing': {
-        'source_filenames': (
-            'css/filelist.css',
-        ),
-        'output_filename': 'compressed/listing_styles_?.css',
-     }
-}
-
-COMPRESS_JS = {
-    # everything except codemirror
-    'detail': {
-        'source_filenames': (
-                # libraries
-                'js/jquery-1.4.2.min.js',
-                'js/jquery.autocomplete.js',
-                'js/jquery.blockui.js',
-                'js/jquery.elastic.js',
-                'js/button_scripts.js',
-                'js/slugify.js',
-
-                # wiki scripts
-                'js/wiki/wikiapi.js',
-                'js/wiki/xslt.js',
-
-                # base UI
-                'js/wiki/base.js',
-
-                # dialogs
-                'js/wiki/dialog_save.js',
-                'js/wiki/dialog_addtag.js',
-
-                # views
-                'js/wiki/view_history.js',
-                'js/wiki/view_summary.js',
-                'js/wiki/view_editor_source.js',
-                'js/wiki/view_editor_wysiwyg.js',
-                'js/wiki/view_gallery.js',
-                'js/wiki/view_column_diff.js',
-        ),
-        'output_filename': 'compressed/detail_scripts_?.js',
-     },
-    'listing': {
-        'source_filenames': (
-                'js/jquery-1.4.2.min.js',
-                'js/slugify.js',
-        ),
-        'output_filename': 'compressed/listing_scripts_?.js',
-     }
-}
-
-COMPRESS = True
-COMPRESS_CSS_FILTERS = None
-COMPRESS_JS_FILTERS = None
-COMPRESS_AUTO = False
-COMPRESS_VERSION = True
-COMPRESS_VERSIONING = 'compress.versioning.hash.MD5Versioning'
index 813d8f3..5e3372e 100644 (file)
@@ -1,9 +1,19 @@
 # -*- coding: utf-8
 
-
 def settings(request):
     from django.conf import settings
+
+    if settings.SHOW_APP_VERSION:
+        import subprocess
+        process = subprocess.Popen(["git", "show", "--oneline"], stdout=subprocess.PIPE)
+        data, _err = process.communicate()
+        # get app version 
+        VERSION = data.splitlines()[0].split()[0]
+    else:
+        VERSION = ''
+
     return {
         'MEDIA_URL': settings.MEDIA_URL,
         'STATIC_URL': settings.STATIC_URL,
+        'APP_VERSION': VERSION,
     }
index 52d7a6d..98523f5 100644 (file)
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2009-10-16 10:52+0000\n"
+"POT-Creation-Date: 2010-05-18 10:57+0200\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -16,49 +16,43 @@ msgstr ""
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: templates/explorer/editor.html:53
-msgid "Refresh panel"
-msgstr "Odśwież panel"
-
-#: templates/explorer/editor.html:67
-msgid "Print version"
-msgstr "Wersja do druku"
-
-#: templates/explorer/editor.html:96
-msgid "Next page"
-msgstr "Następna strona"
+#: templates/admin/index.html:21
+#, python-format
+msgid "Models available in the %(name)s application."
+msgstr ""
 
-#: templates/explorer/editor.html:100
-msgid "Zoom in"
-msgstr "Powiększ"
+#: templates/admin/index.html:22
+#, python-format
+msgid "%(name)s"
+msgstr ""
 
-#: templates/explorer/editor.html:103
-msgid "Zoom out"
-msgstr "Zmniejsz"
+#: templates/admin/index.html:32
+msgid "Add"
+msgstr ""
 
-#: templates/explorer/editor.html:106
-msgid "Reset zoom"
-msgstr "Oryginalny rozmiar"
+#: templates/admin/index.html:38
+msgid "Change"
+msgstr ""
 
-#: templates/explorer/editor.html:155
-msgid "History"
-msgstr "Historia"
+#: templates/admin/index.html:48
+msgid "You don't have permission to edit anything."
+msgstr ""
 
-#: templates/explorer/editor.html:156
-msgid "Push"
-msgstr "Zatwierdź"
+#: templates/admin/index.html:56
+msgid "Recent Actions"
+msgstr ""
 
-#: templates/explorer/editor.html:157
-msgid "Pull"
-msgstr "Uaktualnij"
+#: templates/admin/index.html:57
+msgid "My Actions"
+msgstr ""
 
-#: templates/explorer/editor.html:158
-msgid "Save"
-msgstr "Zapisz"
+#: templates/admin/index.html:61
+msgid "None available"
+msgstr ""
 
-#: templates/explorer/editor.html:159
-msgid "Quick save"
-msgstr "Szybki zapis"
+#: templates/admin/index.html:75
+msgid "Unknown content"
+msgstr ""
 
 #: templates/registration/head_login.html:5
 msgid "Log Out"
@@ -67,3 +61,36 @@ msgstr "Wyloguj"
 #: templates/registration/head_login.html:9
 msgid "Log In"
 msgstr "Logowanie"
+
+#~ msgid "Refresh panel"
+#~ msgstr "Odśwież panel"
+
+#~ msgid "Print version"
+#~ msgstr "Wersja do druku"
+
+#~ msgid "Next page"
+#~ msgstr "Następna strona"
+
+#~ msgid "Zoom in"
+#~ msgstr "Powiększ"
+
+#~ msgid "Zoom out"
+#~ msgstr "Zmniejsz"
+
+#~ msgid "Reset zoom"
+#~ msgstr "Oryginalny rozmiar"
+
+#~ msgid "History"
+#~ msgstr "Historia"
+
+#~ msgid "Push"
+#~ msgstr "Zatwierdź"
+
+#~ msgid "Pull"
+#~ msgstr "Uaktualnij"
+
+#~ msgid "Save"
+#~ msgstr "Zapisz"
+
+#~ msgid "Quick save"
+#~ msgstr "Szybki zapis"
diff --git a/redakcja/localsettings.sample b/redakcja/localsettings.sample
new file mode 100644 (file)
index 0000000..6f99ddd
--- /dev/null
@@ -0,0 +1,27 @@
+# 
+#  localsettings template for Platforma
+#
+#  Duplicate this file as localsettings.py and change it to your liking.
+#  Settings defined in localsettings.py will override settings from 
+#  settings.py file. localsettings.py should never be commited 
+#  to a version control system. Please make changes to settings.py 
+#  or localsettings.sample instead.
+#
+
+# THIS IS REQUIRED
+from redakcja.settings import *
+
+# Path to repository with managed documents
+WIKI_REPOSITORY_PATH = '/home/lrekucki/projekty/fundacja/books'
+
+LOGGING_CONFIG_FILE = "/home/lrekucki/projekty/fundacja/redakcja/logging.cfg.dev"
+
+STATIC_ROOT = '/home/lrekucki/projekty/fundacja/redakcja/redakcja/static/'
+MEDIA_ROOT = '/home/lrekucki/projekty/fundacja/media/'
+
+# Subdirectory of STATIC_ROOT containing images
+IMAGE_DIR = 'images'
+
+CAS_SERVER_URL = 'http://logowanie.wolnelektury.pl/cas/'
+DEBUG = True
+COMPRESS = False
\ No newline at end of file
index 1fc25dd..28b571d 100755 (executable)
@@ -1,18 +1,25 @@
 #!/usr/bin/env python
 from django.core.management import execute_manager
+
+import logging
+import sys
+import os
+
+logging.basicConfig(level=logging.DEBUG, stream=sys.stderr)
+
+PROJECT_ROOT = os.path.realpath(os.path.dirname(__file__))
+sys.path += [os.path.realpath(os.path.join(*x)) for x in (
+        (PROJECT_ROOT, '..'),
+        (PROJECT_ROOT, '..', 'apps'),
+        (PROJECT_ROOT, '..', 'lib')
+)]
+
 try:
-    import settings  # Assumed to be in the same directory.
+    import localsettings  # Assumed to be in the same directory.
 except ImportError:
+    logging.exception("Failed to import settings")
     import sys
-    sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
     sys.exit(1)
 
 if __name__ == "__main__":
-    # Append lib and apps directories to PYTHONPATH
-    from os import path
-    import sys
-
-    PROJECT_ROOT = path.realpath(path.dirname(__file__))
-    sys.path += [PROJECT_ROOT + '/../apps', PROJECT_ROOT + '/../lib']
-
-    execute_manager(settings)
+    execute_manager(localsettings)
diff --git a/redakcja/settings.py b/redakcja/settings.py
deleted file mode 100644 (file)
index fb26205..0000000
+++ /dev/null
@@ -1,186 +0,0 @@
-# -*- coding: utf-8 -*-
-import os.path
-
-PROJECT_ROOT = os.path.realpath(os.path.dirname(__file__))
-
-DEBUG = False
-TEMPLATE_DEBUG = DEBUG
-
-MAINTENANCE_MODE = False
-
-ADMINS = (
-    # (u'Marek Stępniowski', 'marek@stepniowski.com'),
-    (u'Łukasz Rekucki', 'lrekucki@gmail.com'),
-)
-
-MANAGERS = ADMINS
-
-DATABASE_ENGINE = 'sqlite3'           # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
-DATABASE_NAME = PROJECT_ROOT + '/dev.sqlite'             # Or path to database file if using sqlite3.
-DATABASE_USER = ''             # Not used with sqlite3.
-DATABASE_PASSWORD = ''         # Not used with sqlite3.
-DATABASE_HOST = ''             # Set to empty string for localhost. Not used with sqlite3.
-DATABASE_PORT = ''             # Set to empty string for default. Not used with sqlite3.
-
-# Local time zone for this installation. Choices can be found here:
-# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
-# although not all choices may be available on all operating systems.
-# If running in a Windows environment this must be set to the same as your
-# system time zone.
-TIME_ZONE = 'Europe/Warsaw'
-
-# Language code for this installation. All choices can be found here:
-# http://www.i18nguy.com/unicode/language-identifiers.html
-LANGUAGE_CODE = 'pl'
-
-#import locale
-#locale.setlocale(locale.LC_ALL, '')
-
-SITE_ID = 1
-
-# If you set this to False, Django will make some optimizations so as not
-# to load the internationalization machinery.
-USE_I18N = True
-
-# Absolute path to the directory that holds media.
-# Example: "/home/media/media.lawrence.com/"
-MEDIA_ROOT = PROJECT_ROOT + '/media/dynamic'
-STATIC_ROOT = PROJECT_ROOT + '/static/'
-
-# URL that handles the media served from MEDIA_ROOT. Make sure to use a
-# trailing slash if there is a path component (optional in other cases).
-# Examples: "http://media.lawrence.com", "http://example.com/media/"
-MEDIA_URL = '/media/dynamic/'
-STATIC_URL = '/media/static/'
-
-# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
-# trailing slash.
-# Examples: "http://foo.com/media/", "/media/".
-ADMIN_MEDIA_PREFIX = '/media/admin-media/'
-
-# Make this unique, and don't share it with anybody.
-SECRET_KEY = 'ife@x^_lak+x84=lxtr!-ur$5g$+s6xt85gbbm@e_fk6q3r8=+'
-SESSION_COOKIE_NAME = "redakcja_sessionid"
-
-# List of callables that know how to import templates from various sources.
-TEMPLATE_LOADERS = (
-    'django.template.loaders.filesystem.load_template_source',
-    'django.template.loaders.app_directories.load_template_source',
-#     'django.template.loaders.eggs.load_template_source',
-)
-
-TEMPLATE_CONTEXT_PROCESSORS = (
-    "django.core.context_processors.auth",
-    "django.core.context_processors.debug",
-    "django.core.context_processors.i18n",
-    "redakcja.context_processors.settings", # this is instead of media 
-    "django.core.context_processors.request",
-)
-
-
-MIDDLEWARE_CLASSES = (
-    'django.middleware.common.CommonMiddleware',
-    'django.contrib.sessions.middleware.SessionMiddleware',
-
-    'django.contrib.auth.middleware.AuthenticationMiddleware',
-    'django_cas.middleware.CASMiddleware',
-
-    'django.middleware.doc.XViewMiddleware',
-    'maintenancemode.middleware.MaintenanceModeMiddleware',
-)
-
-AUTHENTICATION_BACKENDS = (
-    'django.contrib.auth.backends.ModelBackend',
-    'django_cas.backends.CASBackend',
-)
-
-ROOT_URLCONF = 'redakcja.urls'
-
-TEMPLATE_DIRS = (
-    PROJECT_ROOT + '/templates',
-)
-
-FIREPYTHON_LOGGER_NAME = "fnp"
-
-#
-# Central Auth System
-#
-## Set this to where the CAS server lives
-# CAS_SERVER_URL = "http://cas.fnp.pl/
-CAS_LOGOUT_COMPLETELY = True
-
-from compress_settings import *
-
-INSTALLED_APPS = (
-    'django.contrib.auth',
-    'django.contrib.contenttypes',
-    'django.contrib.sessions',
-    'django.contrib.sites',
-    'django.contrib.admin',
-    'django.contrib.admindocs',
-
-    'django_cas',
-    'compress',
-    'south',
-    'sorl.thumbnail',
-    'filebrowser',
-
-    'wiki',
-    'toolbar',
-)
-
-
-#
-# Nose tests
-#
-
-TEST_RUNNER = 'django_nose.run_tests'
-TEST_MODULES = ('wiki', 'toolbar', 'vstorage')
-NOSE_ARGS = (
-    '--tests=' + ','.join(TEST_MODULES),
-    '--cover-package=' + ','.join(TEST_MODULES),
-    '-d',
-    '--with-coverage',
-    '--with-doctest',
-)
-
-
-FILEBROWSER_URL_FILEBROWSER_MEDIA = STATIC_URL + 'filebrowser/'
-FILEBROWSER_DIRECTORY = 'images/'
-FILEBROWSER_ADMIN_VERSIONS = []
-FILEBROWSER_VERSIONS_BASEDIR = 'thumbnails/'
-FILEBROWSER_DEFAULT_ORDER = "path_relative"
-
-# REPOSITORY_PATH = '/Users/zuber/Projekty/platforma/files/books'
-IMAGE_DIR = 'images'
-
-
-WL_API_CONFIG = {
-    "URL": "http://localhost:7000/api/",
-    "AUTH_REALM": "WL API",
-    "AUTH_USER": "platforma",
-    "AUTH_PASSWD": "platforma",
-}
-
-# Import localsettings file, which may override settings defined here
-try:
-    from localsettings import *
-except ImportError:
-    pass
-
-try:
-    LOGGING_CONFIG_FILE
-except NameError:
-    LOGGING_CONFIG_FILE = os.path.join(PROJECT_ROOT, 'config',
-                                ('logging.cfg' if not DEBUG else 'logging.cfg.dev'))
-try:
-    import logging
-
-    if os.path.isfile(LOGGING_CONFIG_FILE):
-        import logging.config
-        logging.config.fileConfig(LOGGING_CONFIG_FILE)
-    else:
-        import sys
-        logging.basicConfig(stream=sys.stderr)
-except ImportError as exc:
-    raise
diff --git a/redakcja/settings/__init__.py b/redakcja/settings/__init__.py
new file mode 100644 (file)
index 0000000..6f1c094
--- /dev/null
@@ -0,0 +1,27 @@
+from __future__ import absolute_import
+from redakcja.settings.common import *
+
+DATABASE_ENGINE = 'sqlite3'    # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
+DATABASE_NAME = PROJECT_ROOT + '/dev.sqlite'             # Or path to database file if using sqlite3.
+DATABASE_USER = ''             # Not used with sqlite3.
+DATABASE_PASSWORD = ''         # Not used with sqlite3.
+DATABASE_HOST = ''             # Set to empty string for localhost. Not used with sqlite3.
+DATABASE_PORT = ''             # Set to empty string for default. Not used with sqlite3.
+
+try:
+    LOGGING_CONFIG_FILE
+except NameError:
+    LOGGING_CONFIG_FILE = os.path.join(PROJECT_ROOT, 'config',
+                                ('logging.cfg' if not DEBUG else 'logging.cfg.dev'))
+try:
+    import logging
+
+    if os.path.isfile(LOGGING_CONFIG_FILE):
+        import logging.config
+        logging.config.fileConfig(LOGGING_CONFIG_FILE)
+    else:
+        import sys
+        logging.basicConfig(stream=sys.stderr)
+except (ImportError,), exc:
+    raise
+
diff --git a/redakcja/settings/common.py b/redakcja/settings/common.py
new file mode 100644 (file)
index 0000000..7b32ba6
--- /dev/null
@@ -0,0 +1,146 @@
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import
+import os.path
+
+PROJECT_ROOT = os.path.realpath(os.path.dirname(os.path.dirname(__file__)))
+
+DEBUG = False
+TEMPLATE_DEBUG = DEBUG
+
+MAINTENANCE_MODE = False
+
+ADMINS = (
+    # (u'Marek Stępniowski', 'marek@stepniowski.com'),
+    (u'Łukasz Rekucki', 'lrekucki@gmail.com'),
+)
+
+MANAGERS = ADMINS
+
+# Local time zone for this installation. Choices can be found here:
+# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
+# although not all choices may be available on all operating systems.
+# If running in a Windows environment this must be set to the same as your
+# system time zone.
+TIME_ZONE = 'Europe/Warsaw'
+
+# Language code for this installation. All choices can be found here:
+# http://www.i18nguy.com/unicode/language-identifiers.html
+LANGUAGE_CODE = 'pl'
+
+#import locale
+#locale.setlocale(locale.LC_ALL, '')
+
+SITE_ID = 1
+
+# If you set this to False, Django will make some optimizations so as not
+# to load the internationalization machinery.
+USE_I18N = True
+
+# Absolute path to the directory that holds media.
+# Example: "/home/media/media.lawrence.com/"
+MEDIA_ROOT = PROJECT_ROOT + '/media/dynamic'
+STATIC_ROOT = PROJECT_ROOT + '/static/'
+
+# URL that handles the media served from MEDIA_ROOT. Make sure to use a
+# trailing slash if there is a path component (optional in other cases).
+# Examples: "http://media.lawrence.com", "http://example.com/media/"
+MEDIA_URL = '/media/dynamic/'
+STATIC_URL = '/media/static/'
+
+# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
+# trailing slash.
+# Examples: "http://foo.com/media/", "/media/".
+ADMIN_MEDIA_PREFIX = '/media/admin-media/'
+
+# Make this unique, and don't share it with anybody.
+SECRET_KEY = 'ife@x^_lak+x84=lxtr!-ur$5g$+s6xt85gbbm@e_fk6q3r8=+'
+SESSION_COOKIE_NAME = "redakcja_sessionid"
+
+# List of callables that know how to import templates from various sources.
+TEMPLATE_LOADERS = (
+    'django.template.loaders.filesystem.load_template_source',
+    'django.template.loaders.app_directories.load_template_source',
+#     'django.template.loaders.eggs.load_template_source',
+)
+
+TEMPLATE_CONTEXT_PROCESSORS = (
+    "django.core.context_processors.auth",
+    "django.core.context_processors.debug",
+    "django.core.context_processors.i18n",
+    "redakcja.context_processors.settings", # this is instead of media
+    "django.core.context_processors.request",
+)
+
+
+MIDDLEWARE_CLASSES = (
+    'django.middleware.common.CommonMiddleware',
+    'django.contrib.sessions.middleware.SessionMiddleware',
+
+    'django.contrib.auth.middleware.AuthenticationMiddleware',
+    'django_cas.middleware.CASMiddleware',
+
+    'django.middleware.doc.XViewMiddleware',
+    'maintenancemode.middleware.MaintenanceModeMiddleware',
+)
+
+AUTHENTICATION_BACKENDS = (
+    'django.contrib.auth.backends.ModelBackend',
+    'django_cas.backends.CASBackend',
+)
+
+ROOT_URLCONF = 'redakcja.urls'
+
+TEMPLATE_DIRS = (
+    PROJECT_ROOT + '/templates',
+)
+
+FIREPYTHON_LOGGER_NAME = "fnp"
+
+#
+# Central Auth System
+#
+## Set this to where the CAS server lives
+# CAS_SERVER_URL = "http://cas.fnp.pl/
+CAS_LOGOUT_COMPLETELY = True
+
+INSTALLED_APPS = (
+    'django.contrib.auth',
+    'django.contrib.contenttypes',
+    'django.contrib.sessions',
+    'django.contrib.sites',
+    'django.contrib.admin',
+    'django.contrib.admindocs',
+
+    'django_cas',
+    'compress',
+    'south',
+    'sorl.thumbnail',
+    'filebrowser',
+
+    'wiki',
+    'toolbar',
+)
+
+FILEBROWSER_URL_FILEBROWSER_MEDIA = STATIC_URL + 'filebrowser/'
+FILEBROWSER_DIRECTORY = 'images/'
+FILEBROWSER_ADMIN_VERSIONS = []
+FILEBROWSER_VERSIONS_BASEDIR = 'thumbnails/'
+FILEBROWSER_DEFAULT_ORDER = "path_relative"
+
+# REPOSITORY_PATH = '/Users/zuber/Projekty/platforma/files/books'
+IMAGE_DIR = 'images'
+
+
+WL_API_CONFIG = {
+    "URL": "http://localhost:7000/api/",
+    "AUTH_REALM": "WL API",
+    "AUTH_USER": "platforma",
+    "AUTH_PASSWD": "platforma",
+}
+
+SHOW_APP_VERSION = False
+
+try:
+    from redakcja.settings.compress import *
+except ImportError:
+    pass
diff --git a/redakcja/settings/compress.py b/redakcja/settings/compress.py
new file mode 100644 (file)
index 0000000..5e8d721
--- /dev/null
@@ -0,0 +1,73 @@
+# CSS and JS files to compress
+COMPRESS_CSS = {
+    'detail': {
+         'source_filenames': (
+            'css/master.css',
+            'css/toolbar.css',
+            'css/gallery.css',
+            'css/history.css',
+            'css/summary.css',
+            'css/html.css',
+            'css/jquery.autocomplete.css',
+            'css/dialogs.css',
+        ),
+        'output_filename': 'compressed/detail_styles_?.css',
+    },
+    'listing': {
+        'source_filenames': (
+            'css/filelist.css',
+        ),
+        'output_filename': 'compressed/listing_styles_?.css',
+     }
+}
+
+COMPRESS_JS = {
+    # everything except codemirror
+    'detail': {
+        'source_filenames': (
+                # libraries
+                'js/lib/jquery-1.4.2.min.js',
+                'js/lib/jquery/jquery.autocomplete.js',
+                'js/lib/jquery/jquery.blockui.js',
+                'js/lib/jquery/jquery.elastic.js',
+                'js/button_scripts.js',
+                'js/slugify.js',
+
+                # wiki scripts
+                'js/wiki/wikiapi.js',
+                'js/wiki/xslt.js',
+
+                # base UI
+                'js/wiki/base.js',
+                'js/wiki/toolbar.js',
+
+                # dialogs
+                'js/wiki/dialog_save.js',
+                'js/wiki/dialog_addtag.js',
+
+                # views
+                'js/wiki/view_history.js',
+                'js/wiki/view_summary.js',
+                'js/wiki/view_editor_source.js',
+                'js/wiki/view_editor_wysiwyg.js',
+                'js/wiki/view_gallery.js',
+                'js/wiki/view_search.js',
+                'js/wiki/view_column_diff.js',
+        ),
+        'output_filename': 'compressed/detail_scripts_?.js',
+     },
+    'listing': {
+        'source_filenames': (
+                'js/lib/jquery-1.4.2.min.js',
+                'js/slugify.js',
+        ),
+        'output_filename': 'compressed/listing_scripts_?.js',
+     }
+}
+
+COMPRESS = True
+COMPRESS_CSS_FILTERS = None
+COMPRESS_JS_FILTERS = None
+COMPRESS_AUTO = True
+COMPRESS_VERSION = True
+COMPRESS_VERSIONING = 'compress.versioning.hash.MD5Versioning'
diff --git a/redakcja/settings/test.py b/redakcja/settings/test.py
new file mode 100644 (file)
index 0000000..118c7ff
--- /dev/null
@@ -0,0 +1,28 @@
+#
+# Nose tests
+#
+
+from redakcja.settings.common import *
+
+# ROOT_URLCONF = 'yourapp.settings.test.urls'
+
+DATABASE_ENGINE = 'sqlite3'
+DATABASE_NAME = ':memory:'
+
+import tempfile
+
+WIKI_REPOSITORY_PATH = tempfile.mkdtemp(prefix='wikirepo')
+
+INSTALLED_APPS += ('django_nose',)
+
+TEST_RUNNER = 'django_nose.run_tests'
+TEST_MODULES = ('wiki', 'toolbar', 'vstorage')
+NOSE_ARGS = (
+    '--tests=' + ','.join(TEST_MODULES),
+    '--cover-package=' + ','.join(TEST_MODULES),
+    '-d',
+    '--with-coverage',
+    '--with-doctest',
+    '--with-xunit',
+    '--with-xcoverage',
+)
index 1c22868..871d723 100644 (file)
@@ -8,13 +8,13 @@
 
 .dialog .help_text {
        font-size: 11px;
-       color: #2e3536;  
+       color: #2e3536;
 }
 
 .dialog .action_area {
        padding: 1em 0.5em 0.5em;
        border-top: 1px solid black;
-       margin-top: 0.5em;      
+       margin-top: 0.5em;
 }
 
 .dialog p {
index a0b4995..c398c45 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
     Document   : filelist
     Created on : 2009-09-04, 20:44:44
     Author     : lreqc
@@ -15,7 +15,7 @@ body {
     border: 1px solid black;
     padding: 0.5em 2em;
     margin: 1em;
-       overflow: hidden;    
+       overflow: hidden;
 }
 
 #content h1 img {
@@ -34,8 +34,8 @@ body {
        float: left;
        max-width: 50%;
        padding-right: 2%;
-       border-right: 1px dashed black; 
-       
+       border-right: 1px dashed black;
+
 }
 
 #last-edited-list {
@@ -46,7 +46,7 @@ body {
 
 #last-edited-list ul {
        margin: 0px;
-}      
+}
 
 #last-edited-list li {
        margin-bottom: 1em;
@@ -59,7 +59,7 @@ body {
 
 a, a:visited, a:active {
        color: blue;
-       text-decoration: none;  
+       text-decoration: none;
 }
 
 a:hover {
index 379abcc..9c6e3a5 100644 (file)
@@ -1,19 +1,28 @@
-/* =========== */
-/* = Gallery = */
-/* =========== */
-
-#side-gallery {
+#sidebar {
+    display:none;
     position: absolute;
-    /* overflow: hidden; */
     top: 0px;
     right: 0px;
     bottom: 0px;
     width: 480px;
-    display: none;
     background-color: #FFF;
 }
 
-#side-gallery .error_message 
+#side-search {
+    height: 100%;
+    display: none;
+    background-color: #C1C1C1;
+}
+
+#side-search p {
+    padding: .5em;
+}
+
+/* =========== */
+/* = Gallery = */
+/* =========== */
+
+#side-gallery .error_message
 {
        background-color: white;
        color: black;
     -khtml-user-select: none;
     -moz-user-select: none;
     cursor: pointer;
-       
+
        background-color: white;
        min-height: 100px;
        min-width: 100px;
 }
 
 .gallery-image img[src=''] {
-       background-color: red;  
+       background-color: red;
 }
index bd710a8..3072d9b 100644 (file)
  font-size: 8px;
  line-height: 8px;
  margin-bottom: 4px;
+
  padding: 3px 4px;
  vertical-align: super;
  background-color:#add8e6;
  margin-left: -80px;
  width: 70px;
  text-align: center;
+
  -webkit-border-radius: 4px;
  }
  */
@@ -210,18 +210,18 @@ not(.strofa) > *[x-verse]::after {
 .htmlview .motto_container {
        display: inline-block;
        margin: 1.5em 0 0;
-       clear: right;   
+       clear: right;
 }
 
 .htmlview .motto {
     text-align: justify;
-    font-style: italic;    
+    font-style: italic;
 }
 
 .htmlview p.motto_podpis {
        position: relative;
        right: -3em;
-       text-align: right;      
+       text-align: right;
 }
 
 .htmlview div.fragment {
@@ -333,14 +333,19 @@ div[x-node] > .uwaga {
     left: auto;
     clear: right;
     width: 10em;
+
+    font-style: normal;
     font-weight: normal;
-    font-size: 13px;
-    line-height: 18px;
     font-variant: normal;
+    letter-spacing: 0;
+    text-transform: none;
     text-decoration: none;
+
+    font-size: 13px;
+    line-height: 18px;
     background-color: #fff;
     /*    border: 1px solid gray;
-     
+
      border-right: none;
      */
     z-index: 1;
@@ -351,6 +356,10 @@ div[x-node] > .uwaga {
     text-align: left;
 }
 
+.htmlview .noncanon {
+    color: #d00;
+}
+
 .htmlview .motyw[x-editable] {
     border-left: 4px solid #DDD;
     padding: 0.2em 0.2em 0.2em 0.5em;
@@ -361,6 +370,10 @@ div[x-node] > .uwaga {
  * Przypisy
  */
 /* Znaczniki w tekście */
+.annotation {
+    font-style: normal;
+}
+
 .htmlview .annotation:before {
     content: "[" counter(main) "]";
     counter-increment: main;
@@ -370,7 +383,10 @@ div[x-node] > .uwaga {
 }
 
 .htmlview .annotation:hover {
-    background-color: #96e0e4;
+    background-color: #ffcccc;
+}
+.htmlview .pe .annotation:hover {
+    background-color: #96e0e4;*/
 }
 *.htmlview *.annotation-inline-box {
     position: static;
@@ -467,8 +483,8 @@ div[x-node] > .uwaga {
     left: 70px;
 }
 
-.edit-button:hover, .edit-button:active, 
-.delete-button:hover, .delete-button:active, 
+.edit-button:hover, .edit-button:active,
+.delete-button:hover, .delete-button:active,
 .accept-button:hover, .accept-button:active {
     /*    color: #FFF;*/
     background-color: #999;
@@ -566,4 +582,4 @@ div[x-node] > .uwaga {
     margin: -0.25em;
     padding: 0.25em;
     border: 1px solid orange;
-}
\ No newline at end of file
+}
index 38cb596..63a2d43 100644 (file)
@@ -3,7 +3,7 @@
     font-size: 16px;
     font: Georgia, "Times New Roman", serif;
     line-height: 1.5em;
-    padding: 3em;    
+    padding: 3em;
 }
 
 .htmlview div {
     color: #777;
     padding: 0 0.5em;
     width: 7.5em;
+
+
     font-style: normal;
     font-weight: normal;
+    font-variant: normal;
+    letter-spacing: 0;
+    text-transform: none;
+    text-decoration: none;
+
     font-size: 16px;
     float: right;
     margin-right: -9.5em;
index 91b6228..416cde1 100644 (file)
        padding: 2px 5px;
        cursor: default;
        display: block;
-       /* 
-       if width will be 100% horizontal scrollbar will apear 
+       /*
+       if width will be 100% horizontal scrollbar will apear
        when scroll mode will be used
        */
        /*width: 100%;*/
        font: menu;
        font-size: 12px;
-       /* 
-       it is very important, if line-height not setted or setted 
+       /*
+       it is very important, if line-height not setted or setted
        in relative units scroll will be broken in firefox
        */
        line-height: 16px;
index ae74266..cbfe66a 100644 (file)
@@ -1,6 +1,6 @@
 a, a:visited, a:active {
        color: blue;
-       text-decoration: none;  
+       text-decoration: none;
 }
 
 a:hover {
@@ -23,10 +23,10 @@ body {
     bottom: 0;
     right: 0;
     width: 26px;
-    background: #C1C1C1 url(../img/gallery.png) no-repeat scroll center center;        
+    background: #C1C1C1 url(../img/gallery.png) no-repeat scroll center center;
     border-left: 2px solid #999;
     border-right: 2px solid #999;
-    cursor: pointer;   
+    cursor: pointer;
 }
 
 .vsplitbar:hover {
@@ -73,20 +73,34 @@ body {
        right: 0px;
        left: 0px;
        height: 30px;
-       border-bottom: 1px solid #999; 
-       
+       border-bottom: 1px solid #999;
+
     margin: 0;
     padding: 0;
     background-color: #C1C1C1;
     background-image: -webkit-gradient(linear, left top, left bottom, from(#C1C1C1), color-stop(0.9, #A2A2A2));
-       
+
        /* Firefox 3.6 */
        background-image: -moz-linear-gradient(top left, #C1C1C1, #A2A2A2, 90%);
-       
+
     font: 11px Helvetica, Verdana, sans-serif;
     font-weight: bold;
 }
 
+#header.saving {
+       background-color: #E1C1C1;
+}
+#header.saving #save-button {
+    display: none;
+}
+#save-attempt-info {
+    color: #801000;
+    display: none;
+}
+.saving #save-attempt-info {
+    display: inline;
+}
+
 #header h1, #header h1 a {
     margin: 0;
     padding: 0;
@@ -103,48 +117,54 @@ body {
     color: #222;
 }
 
-#tabs {
+.tabs {
        overflow: hidden;
     margin: 0;
        padding: 0;
        height: 31px;
-       border: 0px;    
-       padding-left: 1em;      
+       border: 0px;
+       padding-left: 1em;
+    float: left;
 }
 
-#tabs li {
+#tabs-right {
+    float: right;
+    padding-right: 1em;
+}
+
+.tabs li {
        height: 18px;
        margin-top: 6px;
-       margin-bottom: 0px;     
-       
-    -webkit-user-select: none; 
+       margin-bottom: 0px;
+
+    -webkit-user-select: none;
     cursor: pointer;
     display: block;
     float: left;
-       
+
        padding-left: 12px;
        padding-right: 12px;
        padding-top: 5px;
-       
+
     font-weight: bold;
     color: #222;
-    margin-left: 4px;    
-       
+    margin-left: 4px;
+
     background-color: #A2A2A2;
-       
+
        -moz-box-shadow: 1px -1px 2px rgba(127, 127, 127, 0.25);
     -webkit-box-shadow: 1px -1px 2px rgba(127, 127, 127, 0.25);
 
     border: 1px solid #999;
-       border-bottom-width: 0px;       
+       border-bottom-width: 0px;
        -moz-border-radius: 4px 4px 0px 0px;
        -webkit-border-radius: 4px;
     -webkit-border-bottom-left-radius: 0px;
     -webkit-border-bottom-right-radius: 0px;
 }
 
-#tabs li.active {
-    background-color: #C1C1C1;    
+.tabs li.active {
+    background-color: #C1C1C1;
 }
 
 #tools {
@@ -153,73 +173,15 @@ body {
        overflow: hidden;
     margin: 0;
        padding: 0;
-       height: 30px;  
+       height: 30px;
        margin-right: 5px;
        line-height: 30px;
        font-size: 10px;
        vertical-align: middle;
 }
 
-
-/*
- * Toolbars
- */
-
-.toolbar {
-    width: 100%;
-    border-bottom: 1px solid #777;
-    background-color: #C1C1C1;
-    margin: 0;
-    padding: 2px;
-    z-index: 100;
-    height: 28px;
-}
-
-.toolbar button {
-    display: block;
-    float: left;
-    margin: 4px 0 2px 0;
-    padding: 2px 5px;
-    border: none;
-    background: none;
-}
-
-.toolbar button img {
-       margin: 0;
-       padding: 0;     
-       margin-bottom: -3px;
-}
-
-
-.toolbar select {
-    float: left;
-    margin: 1px 5px 1px 0;
-    background: none;
-    border: 1px solid #999;
-    padding: 1px;
-}
-
-.toolbar input {
-    float: left;
-    font-size: 11px;
-    padding: 0;
-    margin: 4px 5px 0px 5px;
-       vertical-align:baseline;
-}
-
-.toolbar-end {
-    clear: both;
-}
-
-.toolbar button:hover, .toolbar button:active {
-    background: #777;
-    color: #FFF;
-    -webkit-border-radius: 10px;
-    -moz-border-radius: 10px;
-}
-
 /* Remove extra padding in Firefox */
-button::-moz-focus-inner { 
+button::-moz-focus-inner {
     border: 0;
     padding: 0;
 }
@@ -265,12 +227,12 @@ p { margin: 0;}
 }
 
 /*
- * CodeMirror 
+ * CodeMirror
  */
 
 .CodeMirror-line-numbers {
        padding: 0px;
-       padding-top: 5px;               
+       padding-top: 5px;
        text-align: right;
        overflow: hidden;
        width: 40px;
@@ -279,7 +241,7 @@ p { margin: 0;}
 }
 
 .CodeMirror-line-numbers div {
-       display: block;  
+       display: block;
        font-family:"Lucida Console", monospace;
     font-size: 13px;
     line-height: 18px;
@@ -289,16 +251,15 @@ p { margin: 0;}
 img.tabclose {
        padding-left: 8px;
        width: 16px;
-       height: 16px;   
+       height: 16px;
        vertical-align: middle;
        vertical-align: text-bottom;
 }
 
-
 /*
  * HTML Editor view
- */ 
+ */
+
 .htmlview {
        z-index: 1;
        overflow: hidden;
@@ -306,7 +267,7 @@ img.tabclose {
 
 .htmlview *[x-editable] {
     background-color: white;
-       
+
 }
 .htmlview .active[x-editable] {
     background-color: #FAFAFA;
@@ -318,3 +279,12 @@ img.tabclose {
        background-color: black;
        opacity: 0.4;
 }
+
+.poezja_cyt {
+    margin:1.5em 2em 0;
+    font-size:0.875em
+}
+
+.wers_akap {
+       padding-left: 1em;
+}
index 8fac6e1..6c05e0b 100644 (file)
@@ -3,29 +3,29 @@
 }
 
 #summary-view {
-       padding: 1em;                   
+       padding: 1em;
 }
 
 #summary-view .book-cover {
        float: left;
        margin: 1em;
        margin-right: 2em;
-       
+
        height: 300px;
        width: 212px;
-       
-       
+
+
        border: 1px dashed black;
 }
 
 #summary-view p {
-       margin: 0.5em; 
+       margin: 0.5em;
 }
 
 #summary-view label {
-       font-weight: bold; 
-}  
+       font-weight: bold;
+}
 
 #summary-view .book-cover {
-       
+
 }
diff --git a/redakcja/static/css/toolbar.css b/redakcja/static/css/toolbar.css
new file mode 100644 (file)
index 0000000..7b96820
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Toolbars
+ */
+
+.toolbar {
+    border-bottom: 1px solid #777;
+    background-color: #C1C1C1;
+    margin: 0px;
+    padding: 0px;
+    z-index: 100;
+    height: 28px;
+    position: relative;
+}
+
+.toolbar > .group_selector {
+       position: absolute;
+
+    margin: 1px 5px 1px 0;
+    border: 1px solid #999;
+    padding: 1px;
+
+    top: 0px;
+    left: 0px;
+    bottom: 0px;
+    width: 180px;
+}
+
+.toolbar > .group_selector + button {
+       position: absolute;
+       width: 20px;
+       top: 0px;
+    left: 180px;
+    bottom: 0px;
+}
+
+.toolbar > .button_group_container {
+       position: absolute;
+       top: 0px;
+       left: 200px;
+       right: 20px;
+       bottom: 0px;
+
+       overflow: hidden;
+}
+
+.toolbar > .button_group_container + button {
+       position: absolute;
+       width: 20px;
+       top: 0px;
+    right: 0px;
+    bottom: 0px;
+}
+
+.toolbar ul.button_group {
+       margin: 0;
+       padding: 0;
+       width: 10000%;
+}
+
+.toolbar ul.button_group li {
+       display: inline-block;
+       margin: 0;
+       padding: 0;
+}
+
+
+.toolbar .button_group button {
+    display: block;
+    margin: 4px 0 2px 0;
+    padding: 2px 5px;
+    border: none;
+    background: none;
+    color: #424242;
+}
+
+.toolbar .button_group button img {
+       margin: 0;
+       padding: 0;
+       margin-bottom: -3px;
+}
+
+.toolbar .button_group button:hover,
+.toolbar .button_group button:active {
+    background: #777;
+    color: #FFF;
+    -webkit-border-radius: 10px;
+    -moz-border-radius: 10px;
+}
\ No newline at end of file
index 099f94a..17277f8 100644 (file)
@@ -1,11 +1,11 @@
-.editbox {  
+.editbox {
   margin: .4em;
   margin-top: 5px;
   margin-left: 5px;
   padding: 0;
   font-family:"Lucida Console", monospace;
   font-size: 13px;
-  line-height: 18px;  
+  line-height: 18px;
   color: black;
 }
 
@@ -14,9 +14,9 @@
 }
 
 .editbox span {
-       display: inline;  
+       display: inline;
        font-size: 13px;
-    line-height: 18px; 
+    line-height: 18px;
 }
 
 span.xml-tagname {
index ec5902d..2173d9e 100644 (file)
@@ -1,10 +1,10 @@
-body {\r
-       font: 12px/16px Arial, Helvetica, sans-serif;\r
-}\r
-#fileQueue {\r
-       width: 400px;\r
-       height: 300px;\r
-       overflow: auto;\r
-       border: 1px solid #E5E5E5;\r
-       margin-bottom: 10px;\r
+body {
+       font: 12px/16px Arial, Helvetica, sans-serif;
+}
+#fileQueue {
+       width: 400px;
+       height: 300px;
+       overflow: auto;
+       border: 1px solid #E5E5E5;
+       margin-bottom: 10px;
 }
\ No newline at end of file
index 0cf8c0e..754de06 100644 (file)
@@ -1,53 +1,53 @@
-/*\r
-Uploadify v2.1.0\r
-Release Date: August 24, 2009\r
-\r
-Copyright (c) 2009 Ronnie Garcia, Travis Nickels\r
-\r
-Permission is hereby granted, free of charge, to any person obtaining a copy\r
-of this software and associated documentation files (the "Software"), to deal\r
-in the Software without restriction, including without limitation the rights\r
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
-copies of the Software, and to permit persons to whom the Software is\r
-furnished to do so, subject to the following conditions:\r
-\r
-The above copyright notice and this permission notice shall be included in\r
-all copies or substantial portions of the Software.\r
-\r
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r
-THE SOFTWARE.\r
-*/\r
-.uploadifyQueueItem {\r
-       font: 11px Verdana, Geneva, sans-serif;\r
-       border: 2px solid #E5E5E5;\r
-       background-color: #F5F5F5;\r
-       margin-top: 5px;\r
-       padding: 10px;\r
-       width: 350px;\r
-}\r
-.uploadifyError {\r
-       border: 2px solid #FBCBBC !important;\r
-       background-color: #FDE5DD !important;\r
-}\r
-.uploadifyQueueItem .cancel {\r
-       float: right;\r
-}\r
-.uploadifyProgress {\r
-       background-color: #FFFFFF;\r
-       border-top: 1px solid #808080;\r
-       border-left: 1px solid #808080;\r
-       border-right: 1px solid #C5C5C5;\r
-       border-bottom: 1px solid #C5C5C5;\r
-       margin-top: 10px;\r
-       width: 100%;\r
-}\r
-.uploadifyProgressBar {\r
-       background-color: #0099FF;\r
-       width: 1px;\r
-       height: 3px;\r
+/*
+Uploadify v2.1.0
+Release Date: August 24, 2009
+
+Copyright (c) 2009 Ronnie Garcia, Travis Nickels
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+.uploadifyQueueItem {
+       font: 11px Verdana, Geneva, sans-serif;
+       border: 2px solid #E5E5E5;
+       background-color: #F5F5F5;
+       margin-top: 5px;
+       padding: 10px;
+       width: 350px;
+}
+.uploadifyError {
+       border: 2px solid #FBCBBC !important;
+       background-color: #FDE5DD !important;
+}
+.uploadifyQueueItem .cancel {
+       float: right;
+}
+.uploadifyProgress {
+       background-color: #FFFFFF;
+       border-top: 1px solid #808080;
+       border-left: 1px solid #808080;
+       border-right: 1px solid #C5C5C5;
+       border-bottom: 1px solid #C5C5C5;
+       margin-top: 10px;
+       width: 100%;
+}
+.uploadifyProgressBar {
+       background-color: #0099FF;
+       width: 1px;
+       height: 3px;
 }
\ No newline at end of file
index 0cf8c0e..754de06 100644 (file)
@@ -1,53 +1,53 @@
-/*\r
-Uploadify v2.1.0\r
-Release Date: August 24, 2009\r
-\r
-Copyright (c) 2009 Ronnie Garcia, Travis Nickels\r
-\r
-Permission is hereby granted, free of charge, to any person obtaining a copy\r
-of this software and associated documentation files (the "Software"), to deal\r
-in the Software without restriction, including without limitation the rights\r
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
-copies of the Software, and to permit persons to whom the Software is\r
-furnished to do so, subject to the following conditions:\r
-\r
-The above copyright notice and this permission notice shall be included in\r
-all copies or substantial portions of the Software.\r
-\r
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r
-THE SOFTWARE.\r
-*/\r
-.uploadifyQueueItem {\r
-       font: 11px Verdana, Geneva, sans-serif;\r
-       border: 2px solid #E5E5E5;\r
-       background-color: #F5F5F5;\r
-       margin-top: 5px;\r
-       padding: 10px;\r
-       width: 350px;\r
-}\r
-.uploadifyError {\r
-       border: 2px solid #FBCBBC !important;\r
-       background-color: #FDE5DD !important;\r
-}\r
-.uploadifyQueueItem .cancel {\r
-       float: right;\r
-}\r
-.uploadifyProgress {\r
-       background-color: #FFFFFF;\r
-       border-top: 1px solid #808080;\r
-       border-left: 1px solid #808080;\r
-       border-right: 1px solid #C5C5C5;\r
-       border-bottom: 1px solid #C5C5C5;\r
-       margin-top: 10px;\r
-       width: 100%;\r
-}\r
-.uploadifyProgressBar {\r
-       background-color: #0099FF;\r
-       width: 1px;\r
-       height: 3px;\r
+/*
+Uploadify v2.1.0
+Release Date: August 24, 2009
+
+Copyright (c) 2009 Ronnie Garcia, Travis Nickels
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+.uploadifyQueueItem {
+       font: 11px Verdana, Geneva, sans-serif;
+       border: 2px solid #E5E5E5;
+       background-color: #F5F5F5;
+       margin-top: 5px;
+       padding: 10px;
+       width: 350px;
+}
+.uploadifyError {
+       border: 2px solid #FBCBBC !important;
+       background-color: #FDE5DD !important;
+}
+.uploadifyQueueItem .cancel {
+       float: right;
+}
+.uploadifyProgress {
+       background-color: #FFFFFF;
+       border-top: 1px solid #808080;
+       border-left: 1px solid #808080;
+       border-right: 1px solid #C5C5C5;
+       border-bottom: 1px solid #C5C5C5;
+       margin-top: 10px;
+       width: 100%;
+}
+.uploadifyProgressBar {
+       background-color: #0099FF;
+       width: 1px;
+       height: 3px;
 }
\ No newline at end of file
index 0d38b00..4aa0c95 100644 (file)
@@ -48,9 +48,8 @@ function ScriptletCenter()
 {
     this.scriptlets = {};
 
-    this.scriptlets['insert_tag'] = function(context, params, done)
+    this.scriptlets['insert_tag'] = function(context, params, text, move_forward, done)
     {
-        var text = this.XMLEditorSelectedText(context);
         var start_tag = '<'+params.tag;
         var move_cursor = false;
 
@@ -95,18 +94,14 @@ function ScriptletCenter()
             }
         }
 
-        this.XMLEditorReplaceSelectedText(context, output);
-
-        try {
-            if (move_cursor) {
-                this.XMLEditorMoveCursorForward(context, params.tag.length+2);
-            }
-        } catch(e) {}
+        if (move_cursor) {
+            move_forward += params.tag.length+2;
+        }
 
-               done();
+        done(output, move_forward);
     }.bind(this);
 
-    this.scriptlets['lineregexp'] = function(context, params, done) {
+    this.scriptlets['lineregexp'] = function(context, params, text, move_forward, done) {
                var self = this;
 
         var exprs = $.map(params.exprs, function(expr) {
@@ -120,8 +115,7 @@ function ScriptletCenter()
         });
 
         var partial = true;
-        var text = this.XMLEditorSelectedText(context);
-        if(!text) return done();
+        if(!text) done(text, move_forward);
 
         var changed = 0;
         var lines = text.split('\n');
@@ -138,15 +132,15 @@ function ScriptletCenter()
             if(old_line != line) changed += 1;
             return line;
         }, function(newlines) {
-                       if(changed > 0) {
-                               self.XMLEditorReplaceSelectedText(context, newlines.join('\n') );
-                       };
+            if(changed > 0) {
+                text = newlines.join('\n');
+            };
 
-                       done();
+            done(text, move_forward);
                });
     }.bind(this);
 
-    this.scriptlets['fulltextregexp'] = function(context, params, done) {
+    this.scriptlets['fulltextregexp'] = function(context, params, text, move_forward, done) {
                var self = this;
 
         var exprs = $.map(params.exprs, function(expr) {
@@ -160,47 +154,39 @@ function ScriptletCenter()
                 };
         });
 
-        var text = this.XMLEditorSelectedText(context);
-        if(!text) return done();
-        var original = text;
+        if(!text) done(text, move_forward);
+        var original = text;$
 
                nblck_each(exprs, function(expr, index) {
                        $progress.html(600 + index);
             text = text.replace(expr.rx, expr.repl);
         }, function() {
-                       if( original != text) {
-                  self.XMLEditorReplaceSelectedText(context, text);
-               }
-
-                       done();
+                       done(text, move_forward);
                });
     }.bind(this);
 
-    this.scriptlets['macro'] = function(context, params, done) {
+    this.scriptlets['macro'] = function(context, params, text, move_forward, done) {
         var self = this;
                var i = 0;
 
-               function next() {
+               function next(text, move_forward) {
                if (i < params.length) {
                                var e = params[i];
                                i = i + 1;
-                               self.scriptlets[e[0]](context, e[1], next);
+                               self.scriptlets[e[0]](context, e[1], text, move_forward, next);
                        }
                        else {
-                               done();
+                               done(text, move_forward);
                        }
         };
 
-               next();
+               next(text, move_forward);
     }.bind(this);
 
-    this.scriptlets['lowercase'] = function(context, params, done)
+    this.scriptlets['lowercase'] = function(context, params, text, move_forward, done)
     {
-        var text = this.XMLEditorSelectedText(context);
+        if(!text) done(text, move_forward);
 
-        if(!text) return;
-
-        var repl = '';
         var lcase = text.toLowerCase();
         var ucase = text.toUpperCase();
 
@@ -214,18 +200,14 @@ function ScriptletCenter()
                     return '';
                 }
             });
-            repl = words.join(' ');
+            text = words.join(' ');
         }
 
-        if(repl != text) this.XMLEditorReplaceSelectedText(context, repl);
-
-               done();
+        done(text, move_forward);
     }.bind(this);
 
 
-    this.scriptlets["insert_stanza"] = function(context, params, done) {
-        var text = this.XMLEditorSelectedText(context);
-
+    this.scriptlets["insert_stanza"] = function(context, params, text, move_forward, done) {
         if(text) {
             var verses = text.split('\n');
             text = ''; var buf = ''; var ebuf = '';
@@ -243,14 +225,12 @@ function ScriptletCenter()
                 }
             }
             text = text + buf + '\n</strofa>' + ebuf;
-            this.XMLEditorReplaceSelectedText(context, text);
         }
-
-        if (!text) {
-            this.XMLEditorMoveCursorForward(context, params.tag.length + 2);
+        else {
+            move_forward += params.tag.length + 2;
         }
 
-               done();
+        done(text, move_forward);
     }.bind(this);
 
 }
@@ -259,14 +239,29 @@ ScriptletCenter.prototype.callInteractive = function(opts) {
        $progress = $('<span>Executing script</span>');
        var self = this;
 
-       $.blockUI({
-               message: $progress,
-
-       });
-
-
-       self.scriptlets[opts.action](opts.context, opts.extra, function(){
-               $.unblockUI(); // done
+       /* This won't work, 'cause the JS below might be synchronous :( */
+       /* var timer = setTimeout(function() {
+           $.blockUI({message: $progress});
+           timer = null;
+       }, 1000); */
+
+       $.blockUI({message: $progress, showOverlay: false});
+
+    var input = self.XMLEditorSelectedText(opts.context);
+       self.scriptlets[opts.action](opts.context, opts.extra, input, 0, function(output, move_forward){
+           /*if(timer)
+               clearTimeout(timer);
+           else */
+        if (input != output) {
+            self.XMLEditorReplaceSelectedText(opts.context, output)
+        }
+        if (move_forward) {
+            try {
+                self.XMLEditorMoveCursorForward(opts.context, move_forward)
+            }
+            catch(e) {}
+        }
+           $.unblockUI(); // done
        });
 }
 
@@ -278,7 +273,7 @@ ScriptletCenter.prototype.XMLEditorSelectedText = function(editor) {
 ScriptletCenter.prototype.XMLEditorReplaceSelectedText = function(editor, replacement)
 {
        $progress.html("Replacing text");
-    editor.replaceSelection(replacement);
+       editor.replaceSelection(replacement);
 };
 
 ScriptletCenter.prototype.XMLEditorMoveCursorForward = function(panel, n) {
diff --git a/redakcja/static/js/jquery-1.4.2.min.js b/redakcja/static/js/jquery-1.4.2.min.js
deleted file mode 100644 (file)
index 7c24308..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-/*!
- * jQuery JavaScript Library v1.4.2
- * http://jquery.com/
- *
- * Copyright 2010, John Resig
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * Includes Sizzle.js
- * http://sizzlejs.com/
- * Copyright 2010, The Dojo Foundation
- * Released under the MIT, BSD, and GPL Licenses.
- *
- * Date: Sat Feb 13 22:33:48 2010 -0500
- */
-(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o<i;o++)e(a[o],b,f?d.call(a[o],o,e(a[o],b)):d,j);return a}return i?
-e(a[0],b):w}function J(){return(new Date).getTime()}function Y(){return false}function Z(){return true}function na(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function oa(a){var b,d=[],f=[],e=arguments,j,i,o,k,n,r;i=c.data(this,"events");if(!(a.liveFired===this||!i||!i.live||a.button&&a.type==="click")){a.liveFired=this;var u=i.live.slice(0);for(k=0;k<u.length;k++){i=u[k];i.origType.replace(O,"")===a.type?f.push(i.selector):u.splice(k--,1)}j=c(a.target).closest(f,a.currentTarget);n=0;for(r=
-j.length;n<r;n++)for(k=0;k<u.length;k++){i=u[k];if(j[n].selector===i.selector){o=j[n].elem;f=null;if(i.preType==="mouseenter"||i.preType==="mouseleave")f=c(a.relatedTarget).closest(i.selector)[0];if(!f||f!==o)d.push({elem:o,handleObj:i})}}n=0;for(r=d.length;n<r;n++){j=d[n];a.currentTarget=j.elem;a.data=j.handleObj.data;a.handleObj=j.handleObj;if(j.handleObj.origHandler.apply(j.elem,e)===false){b=false;break}}return b}}function pa(a,b){return"live."+(a&&a!=="*"?a+".":"")+b.replace(/\./g,"`").replace(/ /g,
-"&")}function qa(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function ra(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var f=c.data(a[d++]),e=c.data(this,f);if(f=f&&f.events){delete e.handle;e.events={};for(var j in f)for(var i in f[j])c.event.add(this,j,f[j][i],f[j][i].data)}}})}function sa(a,b,d){var f,e,j;b=b&&b[0]?b[0].ownerDocument||b[0]:s;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===s&&!ta.test(a[0])&&(c.support.checkClone||!ua.test(a[0]))){e=
-true;if(j=c.fragments[a[0]])if(j!==1)f=j}if(!f){f=b.createDocumentFragment();c.clean(a,b,f,d)}if(e)c.fragments[a[0]]=j?f:1;return{fragment:f,cacheable:e}}function K(a,b){var d={};c.each(va.concat.apply([],va.slice(0,b)),function(){d[this]=a});return d}function wa(a){return"scrollTo"in a&&a.document?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var c=function(a,b){return new c.fn.init(a,b)},Ra=A.jQuery,Sa=A.$,s=A.document,T,Ta=/^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/,
-Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&&
-(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this,
-a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b===
-"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this,
-function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b<d;b++)if((e=arguments[b])!=null)for(j in e){i=a[j];o=e[j];if(a!==o)if(f&&o&&(c.isPlainObject(o)||c.isArray(o))){i=i&&(c.isPlainObject(i)||
-c.isArray(i))?i:c.isArray(o)?[]:{};a[j]=c.extend(f,i,o)}else if(o!==w)a[j]=o}return a};c.extend({noConflict:function(a){A.$=Sa;if(a)A.jQuery=Ra;return c},isReady:false,ready:function(){if(!c.isReady){if(!s.body)return setTimeout(c.ready,13);c.isReady=true;if(Q){for(var a,b=0;a=Q[b++];)a.call(s,c);Q=null}c.fn.triggerHandler&&c(s).triggerHandler("ready")}},bindReady:function(){if(!xa){xa=true;if(s.readyState==="complete")return c.ready();if(s.addEventListener){s.addEventListener("DOMContentLoaded",
-L,false);A.addEventListener("load",c.ready,false)}else if(s.attachEvent){s.attachEvent("onreadystatechange",L);A.attachEvent("onload",c.ready);var a=false;try{a=A.frameElement==null}catch(b){}s.documentElement.doScroll&&a&&ma()}}},isFunction:function(a){return $.call(a)==="[object Function]"},isArray:function(a){return $.call(a)==="[object Array]"},isPlainObject:function(a){if(!a||$.call(a)!=="[object Object]"||a.nodeType||a.setInterval)return false;if(a.constructor&&!aa.call(a,"constructor")&&!aa.call(a.constructor.prototype,
-"isPrototypeOf"))return false;var b;for(b in a);return b===w||aa.call(a,b)},isEmptyObject:function(a){for(var b in a)return false;return true},error:function(a){throw a;},parseJSON:function(a){if(typeof a!=="string"||!a)return null;a=c.trim(a);if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return A.JSON&&A.JSON.parse?A.JSON.parse(a):(new Function("return "+
-a))();else c.error("Invalid JSON: "+a)},noop:function(){},globalEval:function(a){if(a&&Va.test(a)){var b=s.getElementsByTagName("head")[0]||s.documentElement,d=s.createElement("script");d.type="text/javascript";if(c.support.scriptEval)d.appendChild(s.createTextNode(a));else d.text=a;b.insertBefore(d,b.firstChild);b.removeChild(d)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,b,d){var f,e=0,j=a.length,i=j===w||c.isFunction(a);if(d)if(i)for(f in a){if(b.apply(a[f],
-d)===false)break}else for(;e<j;){if(b.apply(a[e++],d)===false)break}else if(i)for(f in a){if(b.call(a[f],f,a[f])===false)break}else for(d=a[0];e<j&&b.call(d,e,d)!==false;d=a[++e]);return a},trim:function(a){return(a||"").replace(Wa,"")},makeArray:function(a,b){b=b||[];if(a!=null)a.length==null||typeof a==="string"||c.isFunction(a)||typeof a!=="function"&&a.setInterval?ba.call(b,a):c.merge(b,a);return b},inArray:function(a,b){if(b.indexOf)return b.indexOf(a);for(var d=0,f=b.length;d<f;d++)if(b[d]===
-a)return d;return-1},merge:function(a,b){var d=a.length,f=0;if(typeof b.length==="number")for(var e=b.length;f<e;f++)a[d++]=b[f];else for(;b[f]!==w;)a[d++]=b[f++];a.length=d;return a},grep:function(a,b,d){for(var f=[],e=0,j=a.length;e<j;e++)!d!==!b(a[e],e)&&f.push(a[e]);return f},map:function(a,b,d){for(var f=[],e,j=0,i=a.length;j<i;j++){e=b(a[j],j,d);if(e!=null)f[f.length]=e}return f.concat.apply([],f)},guid:1,proxy:function(a,b,d){if(arguments.length===2)if(typeof b==="string"){d=a;a=d[b];b=w}else if(b&&
-!c.isFunction(b)){d=b;b=w}if(!b&&a)b=function(){return a.apply(d||this,arguments)};if(a)b.guid=a.guid=a.guid||b.guid||c.guid++;return b},uaMatch:function(a){a=a.toLowerCase();a=/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version)?[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||!/compatible/.test(a)&&/(mozilla)(?:.*? rv:([\w.]+))?/.exec(a)||[];return{browser:a[1]||"",version:a[2]||"0"}},browser:{}});P=c.uaMatch(P);if(P.browser){c.browser[P.browser]=true;c.browser.version=P.version}if(c.browser.webkit)c.browser.safari=
-true;if(ya)c.inArray=function(a,b){return ya.call(b,a)};T=c(s);if(s.addEventListener)L=function(){s.removeEventListener("DOMContentLoaded",L,false);c.ready()};else if(s.attachEvent)L=function(){if(s.readyState==="complete"){s.detachEvent("onreadystatechange",L);c.ready()}};(function(){c.support={};var a=s.documentElement,b=s.createElement("script"),d=s.createElement("div"),f="script"+J();d.style.display="none";d.innerHTML="   <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
-var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected,
-parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent=
-false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n=
-s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true,
-applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando];
-else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this,
-a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===
-w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i,
-cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1)if(e.className){for(var j=" "+e.className+" ",
-i=e.className,o=0,k=b.length;o<k;o++)if(j.indexOf(" "+b[o]+" ")<0)i+=" "+b[o];e.className=c.trim(i)}else e.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(k){var n=c(this);n.removeClass(a.call(this,k,n.attr("class")))});if(a&&typeof a==="string"||a===w)for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1&&e.className)if(a){for(var j=(" "+e.className+" ").replace(Aa," "),i=0,o=b.length;i<o;i++)j=j.replace(" "+b[i]+" ",
-" ");e.className=c.trim(j)}else e.className=""}return this},toggleClass:function(a,b){var d=typeof a,f=typeof b==="boolean";if(c.isFunction(a))return this.each(function(e){var j=c(this);j.toggleClass(a.call(this,e,j.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var e,j=0,i=c(this),o=b,k=a.split(ca);e=k[j++];){o=f?o:!i.hasClass(e);i[o?"addClass":"removeClass"](e)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this,"__className__",this.className);this.className=
-this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(Aa," ").indexOf(a)>-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j<d;j++){var i=
-e[j];if(i.selected){a=c(i).val();if(b)return a;f.push(a)}}return f}if(Ba.test(b.type)&&!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Za,"")}return w}var o=c.isFunction(a);return this.each(function(k){var n=c(this),r=a;if(this.nodeType===1){if(o)r=a.call(this,k,n.val());if(typeof r==="number")r+="";if(c.isArray(r)&&Ba.test(this.type))this.checked=c.inArray(n.val(),r)>=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected=
-c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");
-a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g,
-function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split(".");
-k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a),
-C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B<r.length;B++){u=r[B];if(d.guid===u.guid){if(i||k.test(u.namespace)){f==null&&r.splice(B--,1);n.remove&&n.remove.call(a,u)}if(f!=
-null)break}}if(r.length===0||f!=null&&r.length===1){if(!n.teardown||n.teardown.call(a,o)===false)Ca(a,e,z.handle);delete C[e]}}else for(var B=0;B<r.length;B++){u=r[B];if(i||k.test(u.namespace)){c.event.remove(a,n,u.handler,B);r.splice(B--,1)}}}if(c.isEmptyObject(C)){if(b=z.handle)b.elem=null;delete z.events;delete z.handle;c.isEmptyObject(z)&&c.removeData(a)}}}}},trigger:function(a,b,d,f){var e=a.type||a;if(!f){a=typeof a==="object"?a[G]?a:c.extend(c.Event(e),a):c.Event(e);if(e.indexOf("!")>=0){a.type=
-e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&&
-f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;
-if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e<j;e++){var i=d[e];if(b||f.test(i.namespace)){a.handler=i.handler;a.data=i.data;a.handleObj=i;i=i.handler.apply(this,arguments);if(i!==w){a.result=i;if(i===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}}return a.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
-fix:function(a){if(a[G])return a;var b=a;a=c.Event(b);for(var d=this.props.length,f;d;){f=this.props[--d];a[f]=b[f]}if(!a.target)a.target=a.srcElement||s;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=s.documentElement;d=s.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop||
-d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(!a.which&&(a.charCode||a.charCode===0?a.charCode:a.keyCode))a.which=a.charCode||a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==w)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a){c.event.add(this,a.origType,c.extend({},a,{handler:oa}))},remove:function(a){var b=true,d=a.origType.replace(O,"");c.each(c.data(this,
-"events").live||[],function(){if(d===this.origType.replace(O,""))return b=false});b&&c.event.remove(this,a.origType,oa)}},beforeunload:{setup:function(a,b,d){if(this.setInterval)this.onbeforeunload=d;return false},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};var Ca=s.removeEventListener?function(a,b,d){a.removeEventListener(b,d,false)}:function(a,b,d){a.detachEvent("on"+b,d)};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=
-a;this.type=a.type}else this.type=a;this.timeStamp=J();this[G]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=Z;var a=this.originalEvent;if(a){a.preventDefault&&a.preventDefault();a.returnValue=false}},stopPropagation:function(){this.isPropagationStopped=Z;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=Z;this.stopPropagation()},isDefaultPrevented:Y,isPropagationStopped:Y,
-isImmediatePropagationStopped:Y};var Da=function(a){var b=a.relatedTarget;try{for(;b&&b!==this;)b=b.parentNode;if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}}catch(d){}},Ea=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?Ea:Da,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?Ea:Da)}}});if(!c.support.submitBubbles)c.event.special.submit=
-{setup:function(){if(this.nodeName.toLowerCase()!=="form"){c.event.add(this,"click.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="submit"||d==="image")&&c(b).closest("form").length)return na("submit",this,arguments)});c.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="text"||d==="password")&&c(b).closest("form").length&&a.keyCode===13)return na("submit",this,arguments)})}else return false},teardown:function(){c.event.remove(this,".specialSubmit")}};
-if(!c.support.changeBubbles){var da=/textarea|input|select/i,ea,Fa=function(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",
-e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,
-"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a,
-d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j<o;j++)c.event.add(this[j],d,i,f)}return this}});c.fn.extend({unbind:function(a,b){if(typeof a==="object"&&
-!a.preventDefault)for(var d in a)this.unbind(d,a[d]);else{d=0;for(var f=this.length;d<f;d++)c.event.remove(this[d],a,b)}return this},delegate:function(a,b,d,f){return this.live(b,d,f,a)},undelegate:function(a,b,d){return arguments.length===0?this.unbind("live"):this.die(b,null,d,a)},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){a=c.Event(a);a.preventDefault();a.stopPropagation();c.event.trigger(a,b,this[0]);return a.result}},
-toggle:function(a){for(var b=arguments,d=1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(f){var e=(c.data(this,"lastToggle"+a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,e+1);f.preventDefault();return b[e].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var Ga={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};c.each(["live","die"],function(a,b){c.fn[b]=function(d,f,e,j){var i,o=0,k,n,r=j||this.selector,
-u=j?this:c(this.context);if(c.isFunction(f)){e=f;f=w}for(d=(d||"").split(" ");(i=d[o++])!=null;){j=O.exec(i);k="";if(j){k=j[0];i=i.replace(O,"")}if(i==="hover")d.push("mouseenter"+k,"mouseleave"+k);else{n=i;if(i==="focus"||i==="blur"){d.push(Ga[i]+k);i+=k}else i=(Ga[i]||i)+k;b==="live"?u.each(function(){c.event.add(this,pa(i,r),{data:f,selector:r,handler:e,origType:i,origHandler:e,preType:n})}):u.unbind(pa(i,r),e)}}return this}});c.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),
-function(a,b){c.fn[b]=function(d){return d?this.bind(b,d):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});A.attachEvent&&!A.addEventListener&&A.attachEvent("onunload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});(function(){function a(g){for(var h="",l,m=0;g[m];m++){l=g[m];if(l.nodeType===3||l.nodeType===4)h+=l.nodeValue;else if(l.nodeType!==8)h+=a(l.childNodes)}return h}function b(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];
-if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1&&!p){t.sizcache=l;t.sizset=q}if(t.nodeName.toLowerCase()===h){y=t;break}t=t[g]}m[q]=y}}}function d(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1){if(!p){t.sizcache=l;t.sizset=q}if(typeof h!=="string"){if(t===h){y=true;break}}else if(k.filter(h,[t]).length>0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
-e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift();
-t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D||
-g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h<g.length;h++)g[h]===g[h-1]&&g.splice(h--,1)}return g};k.matches=function(g,h){return k(g,null,null,h)};k.find=function(g,h,l){var m,q;if(!g)return[];
-for(var p=0,v=n.order.length;p<v;p++){var t=n.order[p];if(q=n.leftMatch[t].exec(g)){var y=q[1];q.splice(1,1);if(y.substr(y.length-1)!=="\\"){q[1]=(q[1]||"").replace(/\\/g,"");m=n.find[t](q,h,l);if(m!=null){g=g.replace(n.match[t],"");break}}}}m||(m=h.getElementsByTagName("*"));return{set:m,expr:g}};k.filter=function(g,h,l,m){for(var q=g,p=[],v=h,t,y,S=h&&h[0]&&x(h[0]);g&&h.length;){for(var H in n.filter)if((t=n.leftMatch[H].exec(g))!=null&&t[2]){var M=n.filter[H],I,D;D=t[1];y=false;t.splice(1,1);if(D.substr(D.length-
-1)!=="\\"){if(v===p)p=[];if(n.preFilter[H])if(t=n.preFilter[H](t,v,l,p,m,S)){if(t===true)continue}else y=I=true;if(t)for(var U=0;(D=v[U])!=null;U++)if(D){I=M(D,t,U,v);var Ha=m^!!I;if(l&&I!=null)if(Ha)y=true;else v[U]=false;else if(Ha){p.push(D);y=true}}if(I!==w){l||(v=p);g=g.replace(n.match[H],"");if(!y)return[];break}}}if(g===q)if(y==null)k.error(g);else break;q=g}return v};k.error=function(g){throw"Syntax error, unrecognized expression: "+g;};var n=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
-CLASS:/\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}},
-relative:{"+":function(g,h){var l=typeof h==="string",m=l&&!/\W/.test(h);l=l&&!m;if(m)h=h.toLowerCase();m=0;for(var q=g.length,p;m<q;m++)if(p=g[m]){for(;(p=p.previousSibling)&&p.nodeType!==1;);g[m]=l||p&&p.nodeName.toLowerCase()===h?p||false:p===h}l&&k.filter(h,g,true)},">":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m<q;m++){var p=g[m];if(p){l=p.parentNode;g[m]=l.nodeName.toLowerCase()===h?l:false}}}else{m=0;for(q=g.length;m<q;m++)if(p=g[m])g[m]=
-l?p.parentNode:p.parentNode===h;l&&k.filter(h,g,true)}},"":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("parentNode",h,m,g,p,l)},"~":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("previousSibling",h,m,g,p,l)}},find:{ID:function(g,h,l){if(typeof h.getElementById!=="undefined"&&!l)return(g=h.getElementById(g[1]))?[g]:[]},NAME:function(g,h){if(typeof h.getElementsByName!=="undefined"){var l=[];
-h=h.getElementsByName(g[1]);for(var m=0,q=h.length;m<q;m++)h[m].getAttribute("name")===g[1]&&l.push(h[m]);return l.length===0?null:l}},TAG:function(g,h){return h.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,h,l,m,q,p){g=" "+g[1].replace(/\\/g,"")+" ";if(p)return g;p=0;for(var v;(v=h[p])!=null;p++)if(v)if(q^(v.className&&(" "+v.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},
-CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m,
-g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},
-text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},
-setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return h<l[3]-0},gt:function(g,h,l){return h>l[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h=
-h[3];l=0;for(m=h.length;l<m;l++)if(h[l]===g)return false;return true}else k.error("Syntax error, unrecognized expression: "+q)},CHILD:function(g,h){var l=h[1],m=g;switch(l){case "only":case "first":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(l==="first")return true;m=g;case "last":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case "nth":l=h[2];var q=h[3];if(l===1&&q===0)return true;h=h[0];var p=g.parentNode;if(p&&(p.sizcache!==h||!g.nodeIndex)){var v=0;for(m=p.firstChild;m;m=
-m.nextSibling)if(m.nodeType===1)m.nodeIndex=++v;p.sizcache=h}g=g.nodeIndex-q;return l===0?g===0:g%l===0&&g/l>=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m===
-"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g,
-h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l<m;l++)h.push(g[l]);else for(l=0;g[l];l++)h.push(g[l]);return h}}var B;if(s.documentElement.compareDocumentPosition)B=function(g,h){if(!g.compareDocumentPosition||
-!h.compareDocumentPosition){if(g==h)i=true;return g.compareDocumentPosition?-1:1}g=g.compareDocumentPosition(h)&4?-1:g===h?0:1;if(g===0)i=true;return g};else if("sourceIndex"in s.documentElement)B=function(g,h){if(!g.sourceIndex||!h.sourceIndex){if(g==h)i=true;return g.sourceIndex?-1:1}g=g.sourceIndex-h.sourceIndex;if(g===0)i=true;return g};else if(s.createRange)B=function(g,h){if(!g.ownerDocument||!h.ownerDocument){if(g==h)i=true;return g.ownerDocument?-1:1}var l=g.ownerDocument.createRange(),m=
-h.ownerDocument.createRange();l.setStart(g,0);l.setEnd(g,0);m.setStart(h,0);m.setEnd(h,0);g=l.compareBoundaryPoints(Range.START_TO_END,m);if(g===0)i=true;return g};(function(){var g=s.createElement("div"),h="script"+(new Date).getTime();g.innerHTML="<a name='"+h+"'/>";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&&
-q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML="<a href='#'></a>";
-if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="<p class='TEST'></p>";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}();
-(function(){var g=s.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}:
-function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q<p;q++)k(g,h[q],l);return k.filter(m,l)};c.find=k;c.expr=k.selectors;c.expr[":"]=c.expr.filters;c.unique=k.uniqueSort;c.text=a;c.isXMLDoc=x;c.contains=E})();var eb=/Until$/,fb=/^(?:parents|prevUntil|prevAll)/,
-gb=/,/;R=Array.prototype.slice;var Ia=function(a,b,d){if(c.isFunction(b))return c.grep(a,function(e,j){return!!b.call(e,j,e)===d});else if(b.nodeType)return c.grep(a,function(e){return e===b===d});else if(typeof b==="string"){var f=c.grep(a,function(e){return e.nodeType===1});if(Ua.test(b))return c.filter(b,f,!d);else b=c.filter(b,f)}return c.grep(a,function(e){return c.inArray(e,b)>=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f<e;f++){d=b.length;
-c.find(a,this[f],b);if(f>0)for(var j=d;j<b.length;j++)for(var i=0;i<d;i++)if(b[i]===b[j]){b.splice(j--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,f=b.length;d<f;d++)if(c.contains(this,b[d]))return true})},not:function(a){return this.pushStack(Ia(this,a,false),"not",a)},filter:function(a){return this.pushStack(Ia(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j=
-{},i;if(f&&a.length){e=0;for(var o=a.length;e<o;e++){i=a[e];j[i]||(j[i]=c.expr.match.POS.test(i)?c(i,b||this.context):i)}for(;f&&f.ownerDocument&&f!==b;){for(i in j){e=j[i];if(e.jquery?e.index(f)>-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a===
-"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",
-d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?
-a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType===
-1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/<tbody/i,jb=/<|&#?\w+;/,ta=/<script|<object|<embed|<option|<style/i,ua=/checked\s*(?:[^=]|=\s*.checked.)/i,Ma=function(a,b,d){return hb.test(d)?
-a:b+"></"+d+">"},F={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=
-c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},
-wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},
-prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,
-this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild);
-return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja,
-""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(f){this.empty().append(a)}}else c.isFunction(a)?this.each(function(e){var j=c(this),i=j.html();j.empty().append(function(){return a.call(this,e,i)})}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&
-this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d=c(this),f=d.html();d.replaceWith(a.call(this,b,f))});if(typeof a!=="string")a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){function f(u){return c.nodeName(u,"table")?u.getElementsByTagName("tbody")[0]||
-u.appendChild(u.ownerDocument.createElement("tbody")):u}var e,j,i=a[0],o=[],k;if(!c.support.checkClone&&arguments.length===3&&typeof i==="string"&&ua.test(i))return this.each(function(){c(this).domManip(a,b,d,true)});if(c.isFunction(i))return this.each(function(u){var z=c(this);a[0]=i.call(this,u,b?z.html():w);z.domManip(a,b,d)});if(this[0]){e=i&&i.parentNode;e=c.support.parentNode&&e&&e.nodeType===11&&e.childNodes.length===this.length?{fragment:e}:sa(a,this,o);k=e.fragment;if(j=k.childNodes.length===
-1?(k=k.firstChild):k.firstChild){b=b&&c.nodeName(j,"tr");for(var n=0,r=this.length;n<r;n++)d.call(b?f(this[n],j):this[n],n>0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]);
-return this}else{e=0;for(var j=d.length;e<j;e++){var i=(e>0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["",
-""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]==="<table>"&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e=
-c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]?
-c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja=
-function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter=
-Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a,
-"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f=
-a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=
-a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=/<script(.|\s)*?\/script>/gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!==
-"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("<div />").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this},
-serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),
-function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,
-global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&&
-e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)?
-"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache===
-false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B=
-false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since",
-c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E||
-d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x);
-g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===
-1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b===
-"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional;
-if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");
-this[a].style.display=d||"";if(c.css(this[a],"display")==="none"){d=this[a].nodeName;var f;if(la[d])f=la[d];else{var e=c("<"+d+" />").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a<b;a++)this[a].style.display=c.data(this[a],"olddisplay")||"";return this}},hide:function(a,b){if(a||a===0)return this.animate(K("hide",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");!d&&d!=="none"&&c.data(this[a],
-"olddisplay",c.css(this[a],"display"))}a=0;for(b=this.length;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b){var d=typeof a==="boolean";if(c.isFunction(a)&&c.isFunction(b))this._toggle.apply(this,arguments);else a==null||d?this.each(function(){var f=d?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(K("toggle",3),a,b);return this},fadeTo:function(a,b,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d)},
-animate:function(a,b,d,f){var e=c.speed(b,d,f);if(c.isEmptyObject(a))return this.each(e.complete);return this[e.queue===false?"each":"queue"](function(){var j=c.extend({},e),i,o=this.nodeType===1&&c(this).is(":hidden"),k=this;for(i in a){var n=i.replace(ia,ja);if(i!==n){a[n]=a[i];delete a[i];i=n}if(a[i]==="hide"&&o||a[i]==="show"&&!o)return j.complete.call(this);if((i==="height"||i==="width")&&this.style){j.display=c.css(this,"display");j.overflow=this.style.overflow}if(c.isArray(a[i])){(j.specialEasing=
-j.specialEasing||{})[i]=a[i][1];a[i]=a[i][0]}}if(j.overflow!=null)this.style.overflow="hidden";j.curAnim=c.extend({},a);c.each(a,function(r,u){var z=new c.fx(k,j,r);if(Ab.test(u))z[u==="toggle"?o?"show":"hide":u](a);else{var C=Bb.exec(u),B=z.cur(true)||0;if(C){u=parseFloat(C[2]);var E=C[3]||"px";if(E!=="px"){k.style[r]=(u||1)+E;B=(u||1)/z.cur(true)*B;k.style[r]=B+E}if(C[1])u=(C[1]==="-="?-1:1)*u+B;z.custom(B,u,E)}else z.custom(B,u,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);
-this.each(function(){for(var f=d.length-1;f>=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration===
-"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||
-c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;
-this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=
-this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem,
-e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||
-c.fx.stop()},stop:function(){clearInterval(W);W=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===b.elem}).length};c.fn.offset="getBoundingClientRect"in s.documentElement?
-function(a){var b=this[0];if(a)return this.each(function(e){c.offset.setOffset(this,a,e)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);var d=b.getBoundingClientRect(),f=b.ownerDocument;b=f.body;f=f.documentElement;return{top:d.top+(self.pageYOffset||c.support.boxModel&&f.scrollTop||b.scrollTop)-(f.clientTop||b.clientTop||0),left:d.left+(self.pageXOffset||c.support.boxModel&&f.scrollLeft||b.scrollLeft)-(f.clientLeft||b.clientLeft||0)}}:function(a){var b=
-this[0];if(a)return this.each(function(r){c.offset.setOffset(this,a,r)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d=b.offsetParent,f=b,e=b.ownerDocument,j,i=e.documentElement,o=e.body;f=(e=e.defaultView)?e.getComputedStyle(b,null):b.currentStyle;for(var k=b.offsetTop,n=b.offsetLeft;(b=b.parentNode)&&b!==o&&b!==i;){if(c.offset.supportsFixedPosition&&f.position==="fixed")break;j=e?e.getComputedStyle(b,null):b.currentStyle;
-k-=b.scrollTop;n-=b.scrollLeft;if(b===d){k+=b.offsetTop;n+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(b.nodeName))){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=d;d=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&j.overflow!=="visible"){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=j}if(f.position==="relative"||f.position==="static"){k+=o.offsetTop;n+=o.offsetLeft}if(c.offset.supportsFixedPosition&&
-f.position==="fixed"){k+=Math.max(i.scrollTop,o.scrollTop);n+=Math.max(i.scrollLeft,o.scrollLeft)}return{top:k,left:n}};c.offset={initialize:function(){var a=s.body,b=s.createElement("div"),d,f,e,j=parseFloat(c.curCSS(a,"marginTop",true))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";
-a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b);
-c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a,
-d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top-
-f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset":
-"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in
-e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window);
diff --git a/redakcja/static/js/jquery.autocomplete.js b/redakcja/static/js/jquery.autocomplete.js
deleted file mode 100644 (file)
index 0d25ba6..0000000
+++ /dev/null
@@ -1,808 +0,0 @@
-/*
- * jQuery Autocomplete plugin 1.1
- *
- * Copyright (c) 2009 Jörn Zaefferer
- *
- * Dual licensed under the MIT and GPL licenses:
- *   http://www.opensource.org/licenses/mit-license.php
- *   http://www.gnu.org/licenses/gpl.html
- *
- * Revision: $Id: jquery.autocomplete.js 15 2009-08-22 10:30:27Z joern.zaefferer $
- */
-
-;(function($) {
-
-$.fn.extend({
-       autocomplete: function(urlOrData, options) {
-               var isUrl = typeof urlOrData == "string";
-               options = $.extend({}, $.Autocompleter.defaults, {
-                       url: isUrl ? urlOrData : null,
-                       data: isUrl ? null : urlOrData,
-                       delay: isUrl ? $.Autocompleter.defaults.delay : 10,
-                       max: options && !options.scroll ? 10 : 150
-               }, options);
-
-               // if highlight is set to false, replace it with a do-nothing function
-               options.highlight = options.highlight || function(value) { return value; };
-
-               // if the formatMatch option is not specified, then use formatItem for backwards compatibility
-               options.formatMatch = options.formatMatch || options.formatItem;
-
-               return this.each(function() {
-                       new $.Autocompleter(this, options);
-               });
-       },
-       result: function(handler) {
-               return this.bind("result", handler);
-       },
-       search: function(handler) {
-               return this.trigger("search", [handler]);
-       },
-       flushCache: function() {
-               return this.trigger("flushCache");
-       },
-       setOptions: function(options){
-               return this.trigger("setOptions", [options]);
-       },
-       unautocomplete: function() {
-               return this.trigger("unautocomplete");
-       }
-});
-
-$.Autocompleter = function(input, options) {
-
-       var KEY = {
-               UP: 38,
-               DOWN: 40,
-               DEL: 46,
-               TAB: 9,
-               RETURN: 13,
-               ESC: 27,
-               COMMA: 188,
-               PAGEUP: 33,
-               PAGEDOWN: 34,
-               BACKSPACE: 8
-       };
-
-       // Create $ object for input element
-       var $input = $(input).attr("autocomplete", "off").addClass(options.inputClass);
-
-       var timeout;
-       var previousValue = "";
-       var cache = $.Autocompleter.Cache(options);
-       var hasFocus = 0;
-       var lastKeyPressCode;
-       var config = {
-               mouseDownOnSelect: false
-       };
-       var select = $.Autocompleter.Select(options, input, selectCurrent, config);
-
-       var blockSubmit;
-
-       // prevent form submit in opera when selecting with return key
-       $.browser.opera && $(input.form).bind("submit.autocomplete", function() {
-               if (blockSubmit) {
-                       blockSubmit = false;
-                       return false;
-               }
-       });
-
-       // only opera doesn't trigger keydown multiple times while pressed, others don't work with keypress at all
-       $input.bind(($.browser.opera ? "keypress" : "keydown") + ".autocomplete", function(event) {
-               // a keypress means the input has focus
-               // avoids issue where input had focus before the autocomplete was applied
-               hasFocus = 1;
-               // track last key pressed
-               lastKeyPressCode = event.keyCode;
-               switch(event.keyCode) {
-
-                       case KEY.UP:
-                               event.preventDefault();
-                               if ( select.visible() ) {
-                                       select.prev();
-                               } else {
-                                       onChange(0, true);
-                               }
-                               break;
-
-                       case KEY.DOWN:
-                               event.preventDefault();
-                               if ( select.visible() ) {
-                                       select.next();
-                               } else {
-                                       onChange(0, true);
-                               }
-                               break;
-
-                       case KEY.PAGEUP:
-                               event.preventDefault();
-                               if ( select.visible() ) {
-                                       select.pageUp();
-                               } else {
-                                       onChange(0, true);
-                               }
-                               break;
-
-                       case KEY.PAGEDOWN:
-                               event.preventDefault();
-                               if ( select.visible() ) {
-                                       select.pageDown();
-                               } else {
-                                       onChange(0, true);
-                               }
-                               break;
-
-                       // matches also semicolon
-                       case options.multiple && $.trim(options.multipleSeparator) == "," && KEY.COMMA:
-                       case KEY.TAB:
-                       case KEY.RETURN:
-                               if( selectCurrent() ) {
-                                       // stop default to prevent a form submit, Opera needs special handling
-                                       event.preventDefault();
-                                       blockSubmit = true;
-                                       return false;
-                               }
-                               break;
-
-                       case KEY.ESC:
-                               select.hide();
-                               break;
-
-                       default:
-                               clearTimeout(timeout);
-                               timeout = setTimeout(onChange, options.delay);
-                               break;
-               }
-       }).focus(function(){
-               // track whether the field has focus, we shouldn't process any
-               // results if the field no longer has focus
-               hasFocus++;
-       }).blur(function() {
-               hasFocus = 0;
-               if (!config.mouseDownOnSelect) {
-                       hideResults();
-               }
-       }).click(function() {
-               // show select when clicking in a focused field
-               if ( hasFocus++ > 1 && !select.visible() ) {
-                       onChange(0, true);
-               }
-       }).bind("search", function() {
-               // TODO why not just specifying both arguments?
-               var fn = (arguments.length > 1) ? arguments[1] : null;
-               function findValueCallback(q, data) {
-                       var result;
-                       if( data && data.length ) {
-                               for (var i=0; i < data.length; i++) {
-                                       if( data[i].result.toLowerCase() == q.toLowerCase() ) {
-                                               result = data[i];
-                                               break;
-                                       }
-                               }
-                       }
-                       if( typeof fn == "function" ) fn(result);
-                       else $input.trigger("result", result && [result.data, result.value]);
-               }
-               $.each(trimWords($input.val()), function(i, value) {
-                       request(value, findValueCallback, findValueCallback);
-               });
-       }).bind("flushCache", function() {
-               cache.flush();
-       }).bind("setOptions", function() {
-               $.extend(options, arguments[1]);
-               // if we've updated the data, repopulate
-               if ( "data" in arguments[1] )
-                       cache.populate();
-       }).bind("unautocomplete", function() {
-               select.unbind();
-               $input.unbind();
-               $(input.form).unbind(".autocomplete");
-       });
-
-
-       function selectCurrent() {
-               var selected = select.selected();
-               if( !selected )
-                       return false;
-
-               var v = selected.result;
-               previousValue = v;
-
-               if ( options.multiple ) {
-                       var words = trimWords($input.val());
-                       if ( words.length > 1 ) {
-                               var seperator = options.multipleSeparator.length;
-                               var cursorAt = $(input).selection().start;
-                               var wordAt, progress = 0;
-                               $.each(words, function(i, word) {
-                                       progress += word.length;
-                                       if (cursorAt <= progress) {
-                                               wordAt = i;
-                                               return false;
-                                       }
-                                       progress += seperator;
-                               });
-                               words[wordAt] = v;
-                               // TODO this should set the cursor to the right position, but it gets overriden somewhere
-                               //$.Autocompleter.Selection(input, progress + seperator, progress + seperator);
-                               v = words.join( options.multipleSeparator );
-                       }
-                       v += options.multipleSeparator;
-               }
-
-               $input.val(v);
-               hideResultsNow();
-               $input.trigger("result", [selected.data, selected.value]);
-               return true;
-       }
-
-       function onChange(crap, skipPrevCheck) {
-               if( lastKeyPressCode == KEY.DEL ) {
-                       select.hide();
-                       return;
-               }
-
-               var currentValue = $input.val();
-
-               if ( !skipPrevCheck && currentValue == previousValue )
-                       return;
-
-               previousValue = currentValue;
-
-               currentValue = lastWord(currentValue);
-               if ( currentValue.length >= options.minChars) {
-                       $input.addClass(options.loadingClass);
-                       if (!options.matchCase)
-                               currentValue = currentValue.toLowerCase();
-                       request(currentValue, receiveData, hideResultsNow);
-               } else {
-                       stopLoading();
-                       select.hide();
-               }
-       };
-
-       function trimWords(value) {
-               if (!value)
-                       return [""];
-               if (!options.multiple)
-                       return [$.trim(value)];
-               return $.map(value.split(options.multipleSeparator), function(word) {
-                       return $.trim(value).length ? $.trim(word) : null;
-               });
-       }
-
-       function lastWord(value) {
-               if ( !options.multiple )
-                       return value;
-               var words = trimWords(value);
-               if (words.length == 1)
-                       return words[0];
-               var cursorAt = $(input).selection().start;
-               if (cursorAt == value.length) {
-                       words = trimWords(value)
-               } else {
-                       words = trimWords(value.replace(value.substring(cursorAt), ""));
-               }
-               return words[words.length - 1];
-       }
-
-       // fills in the input box w/the first match (assumed to be the best match)
-       // q: the term entered
-       // sValue: the first matching result
-       function autoFill(q, sValue){
-               // autofill in the complete box w/the first match as long as the user hasn't entered in more data
-               // if the last user key pressed was backspace, don't autofill
-               if( options.autoFill && (lastWord($input.val()).toLowerCase() == q.toLowerCase()) && lastKeyPressCode != KEY.BACKSPACE ) {
-                       // fill in the value (keep the case the user has typed)
-                       $input.val($input.val() + sValue.substring(lastWord(previousValue).length));
-                       // select the portion of the value not typed by the user (so the next character will erase)
-                       $(input).selection(previousValue.length, previousValue.length + sValue.length);
-               }
-       };
-
-       function hideResults() {
-               clearTimeout(timeout);
-               timeout = setTimeout(hideResultsNow, 200);
-       };
-
-       function hideResultsNow() {
-               var wasVisible = select.visible();
-               select.hide();
-               clearTimeout(timeout);
-               stopLoading();
-               if (options.mustMatch) {
-                       // call search and run callback
-                       $input.search(
-                               function (result){
-                                       // if no value found, clear the input box
-                                       if( !result ) {
-                                               if (options.multiple) {
-                                                       var words = trimWords($input.val()).slice(0, -1);
-                                                       $input.val( words.join(options.multipleSeparator) + (words.length ? options.multipleSeparator : "") );
-                                               }
-                                               else {
-                                                       $input.val( "" );
-                                                       $input.trigger("result", null);
-                                               }
-                                       }
-                               }
-                       );
-               }
-       };
-
-       function receiveData(q, data) {
-               if ( data && data.length && hasFocus ) {
-                       stopLoading();
-                       select.display(data, q);
-                       autoFill(q, data[0].value);
-                       select.show();
-               } else {
-                       hideResultsNow();
-               }
-       };
-
-       function request(term, success, failure) {
-               if (!options.matchCase)
-                       term = term.toLowerCase();
-               var data = cache.load(term);
-               // recieve the cached data
-               if (data && data.length) {
-                       success(term, data);
-               // if an AJAX url has been supplied, try loading the data now
-               } else if( (typeof options.url == "string") && (options.url.length > 0) ){
-
-                       var extraParams = {
-                               timestamp: +new Date()
-                       };
-                       $.each(options.extraParams, function(key, param) {
-                               extraParams[key] = typeof param == "function" ? param() : param;
-                       });
-
-                       $.ajax({
-                               // try to leverage ajaxQueue plugin to abort previous requests
-                               mode: "abort",
-                               // limit abortion to this input
-                               port: "autocomplete" + input.name,
-                               dataType: options.dataType,
-                               url: options.url,
-                               data: $.extend({
-                                       q: lastWord(term),
-                                       limit: options.max
-                               }, extraParams),
-                               success: function(data) {
-                                       var parsed = options.parse && options.parse(data) || parse(data);
-                                       cache.add(term, parsed);
-                                       success(term, parsed);
-                               }
-                       });
-               } else {
-                       // if we have a failure, we need to empty the list -- this prevents the the [TAB] key from selecting the last successful match
-                       select.emptyList();
-                       failure(term);
-               }
-       };
-
-       function parse(data) {
-               var parsed = [];
-               var rows = data.split("\n");
-               for (var i=0; i < rows.length; i++) {
-                       var row = $.trim(rows[i]);
-                       if (row) {
-                               row = row.split("|");
-                               parsed[parsed.length] = {
-                                       data: row,
-                                       value: row[0],
-                                       result: options.formatResult && options.formatResult(row, row[0]) || row[0]
-                               };
-                       }
-               }
-               return parsed;
-       };
-
-       function stopLoading() {
-               $input.removeClass(options.loadingClass);
-       };
-
-};
-
-$.Autocompleter.defaults = {
-       inputClass: "ac_input",
-       resultsClass: "ac_results",
-       loadingClass: "ac_loading",
-       minChars: 1,
-       delay: 400,
-       matchCase: false,
-       matchSubset: true,
-       matchContains: false,
-       cacheLength: 10,
-       max: 100,
-       mustMatch: false,
-       extraParams: {},
-       selectFirst: true,
-       formatItem: function(row) { return row[0]; },
-       formatMatch: null,
-       autoFill: false,
-       width: 0,
-       multiple: false,
-       multipleSeparator: ", ",
-       highlight: function(value, term) {
-               return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
-       },
-    scroll: true,
-    scrollHeight: 180
-};
-
-$.Autocompleter.Cache = function(options) {
-
-       var data = {};
-       var length = 0;
-
-       function matchSubset(s, sub) {
-               if (!options.matchCase)
-                       s = s.toLowerCase();
-               var i = s.indexOf(sub);
-               if (options.matchContains == "word"){
-                       i = s.toLowerCase().search("\\b" + sub.toLowerCase());
-               }
-               if (i == -1) return false;
-               return i == 0 || options.matchContains;
-       };
-
-       function add(q, value) {
-               if (length > options.cacheLength){
-                       flush();
-               }
-               if (!data[q]){
-                       length++;
-               }
-               data[q] = value;
-       }
-
-       function populate(){
-               if( !options.data ) return false;
-               // track the matches
-               var stMatchSets = {},
-                       nullData = 0;
-
-               // no url was specified, we need to adjust the cache length to make sure it fits the local data store
-               if( !options.url ) options.cacheLength = 1;
-
-               // track all options for minChars = 0
-               stMatchSets[""] = [];
-
-               // loop through the array and create a lookup structure
-               for ( var i = 0, ol = options.data.length; i < ol; i++ ) {
-                       var rawValue = options.data[i];
-                       // if rawValue is a string, make an array otherwise just reference the array
-                       rawValue = (typeof rawValue == "string") ? [rawValue] : rawValue;
-
-                       var value = options.formatMatch(rawValue, i+1, options.data.length);
-                       if ( value === false )
-                               continue;
-
-                       var firstChar = value.charAt(0).toLowerCase();
-                       // if no lookup array for this character exists, look it up now
-                       if( !stMatchSets[firstChar] )
-                               stMatchSets[firstChar] = [];
-
-                       // if the match is a string
-                       var row = {
-                               value: value,
-                               data: rawValue,
-                               result: options.formatResult && options.formatResult(rawValue) || value
-                       };
-
-                       // push the current match into the set list
-                       stMatchSets[firstChar].push(row);
-
-                       // keep track of minChars zero items
-                       if ( nullData++ < options.max ) {
-                               stMatchSets[""].push(row);
-                       }
-               };
-
-               // add the data items to the cache
-               $.each(stMatchSets, function(i, value) {
-                       // increase the cache size
-                       options.cacheLength++;
-                       // add to the cache
-                       add(i, value);
-               });
-       }
-
-       // populate any existing data
-       setTimeout(populate, 25);
-
-       function flush(){
-               data = {};
-               length = 0;
-       }
-
-       return {
-               flush: flush,
-               add: add,
-               populate: populate,
-               load: function(q) {
-                       if (!options.cacheLength || !length)
-                               return null;
-                       /*
-                        * if dealing w/local data and matchContains than we must make sure
-                        * to loop through all the data collections looking for matches
-                        */
-                       if( !options.url && options.matchContains ){
-                               // track all matches
-                               var csub = [];
-                               // loop through all the data grids for matches
-                               for( var k in data ){
-                                       // don't search through the stMatchSets[""] (minChars: 0) cache
-                                       // this prevents duplicates
-                                       if( k.length > 0 ){
-                                               var c = data[k];
-                                               $.each(c, function(i, x) {
-                                                       // if we've got a match, add it to the array
-                                                       if (matchSubset(x.value, q)) {
-                                                               csub.push(x);
-                                                       }
-                                               });
-                                       }
-                               }
-                               return csub;
-                       } else
-                       // if the exact item exists, use it
-                       if (data[q]){
-                               return data[q];
-                       } else
-                       if (options.matchSubset) {
-                               for (var i = q.length - 1; i >= options.minChars; i--) {
-                                       var c = data[q.substr(0, i)];
-                                       if (c) {
-                                               var csub = [];
-                                               $.each(c, function(i, x) {
-                                                       if (matchSubset(x.value, q)) {
-                                                               csub[csub.length] = x;
-                                                       }
-                                               });
-                                               return csub;
-                                       }
-                               }
-                       }
-                       return null;
-               }
-       };
-};
-
-$.Autocompleter.Select = function (options, input, select, config) {
-       var CLASSES = {
-               ACTIVE: "ac_over"
-       };
-
-       var listItems,
-               active = -1,
-               data,
-               term = "",
-               needsInit = true,
-               element,
-               list;
-
-       // Create results
-       function init() {
-               if (!needsInit)
-                       return;
-               element = $("<div/>")
-               .hide()
-               .addClass(options.resultsClass)
-               .css("position", "absolute")
-               .appendTo(document.body);
-
-               list = $("<ul/>").appendTo(element).mouseover( function(event) {
-                       if(target(event).nodeName && target(event).nodeName.toUpperCase() == 'LI') {
-                   active = $("li", list).removeClass(CLASSES.ACTIVE).index(target(event));
-                           $(target(event)).addClass(CLASSES.ACTIVE);
-               }
-               }).click(function(event) {
-                       $(target(event)).addClass(CLASSES.ACTIVE);
-                       select();
-                       // TODO provide option to avoid setting focus again after selection? useful for cleanup-on-focus
-                       input.focus();
-                       return false;
-               }).mousedown(function() {
-                       config.mouseDownOnSelect = true;
-               }).mouseup(function() {
-                       config.mouseDownOnSelect = false;
-               });
-
-               if( options.width > 0 )
-                       element.css("width", options.width);
-
-               needsInit = false;
-       }
-
-       function target(event) {
-               var element = event.target;
-               while(element && element.tagName != "LI")
-                       element = element.parentNode;
-               // more fun with IE, sometimes event.target is empty, just ignore it then
-               if(!element)
-                       return [];
-               return element;
-       }
-
-       function moveSelect(step) {
-               listItems.slice(active, active + 1).removeClass(CLASSES.ACTIVE);
-               movePosition(step);
-        var activeItem = listItems.slice(active, active + 1).addClass(CLASSES.ACTIVE);
-        if(options.scroll) {
-            var offset = 0;
-            listItems.slice(0, active).each(function() {
-                               offset += this.offsetHeight;
-                       });
-            if((offset + activeItem[0].offsetHeight - list.scrollTop()) > list[0].clientHeight) {
-                list.scrollTop(offset + activeItem[0].offsetHeight - list.innerHeight());
-            } else if(offset < list.scrollTop()) {
-                list.scrollTop(offset);
-            }
-        }
-       };
-
-       function movePosition(step) {
-               active += step;
-               if (active < 0) {
-                       active = listItems.size() - 1;
-               } else if (active >= listItems.size()) {
-                       active = 0;
-               }
-       }
-
-       function limitNumberOfItems(available) {
-               return options.max && options.max < available
-                       ? options.max
-                       : available;
-       }
-
-       function fillList() {
-               list.empty();
-               var max = limitNumberOfItems(data.length);
-               for (var i=0; i < max; i++) {
-                       if (!data[i])
-                               continue;
-                       var formatted = options.formatItem(data[i].data, i+1, max, data[i].value, term);
-                       if ( formatted === false )
-                               continue;
-                       var li = $("<li/>").html( options.highlight(formatted, term) ).addClass(i%2 == 0 ? "ac_even" : "ac_odd").appendTo(list)[0];
-                       $.data(li, "ac_data", data[i]);
-               }
-               listItems = list.find("li");
-               if ( options.selectFirst ) {
-                       listItems.slice(0, 1).addClass(CLASSES.ACTIVE);
-                       active = 0;
-               }
-               // apply bgiframe if available
-               if ( $.fn.bgiframe )
-                       list.bgiframe();
-       }
-
-       return {
-               display: function(d, q) {
-                       init();
-                       data = d;
-                       term = q;
-                       fillList();
-               },
-               next: function() {
-                       moveSelect(1);
-               },
-               prev: function() {
-                       moveSelect(-1);
-               },
-               pageUp: function() {
-                       if (active != 0 && active - 8 < 0) {
-                               moveSelect( -active );
-                       } else {
-                               moveSelect(-8);
-                       }
-               },
-               pageDown: function() {
-                       if (active != listItems.size() - 1 && active + 8 > listItems.size()) {
-                               moveSelect( listItems.size() - 1 - active );
-                       } else {
-                               moveSelect(8);
-                       }
-               },
-               hide: function() {
-                       element && element.hide();
-                       listItems && listItems.removeClass(CLASSES.ACTIVE);
-                       active = -1;
-               },
-               visible : function() {
-                       return element && element.is(":visible");
-               },
-               current: function() {
-                       return this.visible() && (listItems.filter("." + CLASSES.ACTIVE)[0] || options.selectFirst && listItems[0]);
-               },
-               show: function() {
-                       var offset = $(input).offset();
-                       element.css({
-                               width: typeof options.width == "string" || options.width > 0 ? options.width : $(input).width(),
-                               top: offset.top + input.offsetHeight,
-                               left: offset.left
-                       }).show();
-            if(options.scroll) {
-                list.scrollTop(0);
-                list.css({
-                                       maxHeight: options.scrollHeight,
-                                       overflow: 'auto'
-                               });
-
-                if($.browser.msie && typeof document.body.style.maxHeight === "undefined") {
-                                       var listHeight = 0;
-                                       listItems.each(function() {
-                                               listHeight += this.offsetHeight;
-                                       });
-                                       var scrollbarsVisible = listHeight > options.scrollHeight;
-                    list.css('height', scrollbarsVisible ? options.scrollHeight : listHeight );
-                                       if (!scrollbarsVisible) {
-                                               // IE doesn't recalculate width when scrollbar disappears
-                                               listItems.width( list.width() - parseInt(listItems.css("padding-left")) - parseInt(listItems.css("padding-right")) );
-                                       }
-                }
-
-            }
-               },
-               selected: function() {
-                       var selected = listItems && listItems.filter("." + CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE);
-                       return selected && selected.length && $.data(selected[0], "ac_data");
-               },
-               emptyList: function (){
-                       list && list.empty();
-               },
-               unbind: function() {
-                       element && element.remove();
-               }
-       };
-};
-
-$.fn.selection = function(start, end) {
-       if (start !== undefined) {
-               return this.each(function() {
-                       if( this.createTextRange ){
-                               var selRange = this.createTextRange();
-                               if (end === undefined || start == end) {
-                                       selRange.move("character", start);
-                                       selRange.select();
-                               } else {
-                                       selRange.collapse(true);
-                                       selRange.moveStart("character", start);
-                                       selRange.moveEnd("character", end);
-                                       selRange.select();
-                               }
-                       } else if( this.setSelectionRange ){
-                               this.setSelectionRange(start, end);
-                       } else if( this.selectionStart ){
-                               this.selectionStart = start;
-                               this.selectionEnd = end;
-                       }
-               });
-       }
-       var field = this[0];
-       if ( field.createTextRange ) {
-               var range = document.selection.createRange(),
-                       orig = field.value,
-                       teststring = "<->",
-                       textLength = range.text.length;
-               range.text = teststring;
-               var caretAt = field.value.indexOf(teststring);
-               field.value = orig;
-               this.selection(caretAt, caretAt + textLength);
-               return {
-                       start: caretAt,
-                       end: caretAt + textLength
-               }
-       } else if( field.selectionStart !== undefined ){
-               return {
-                       start: field.selectionStart,
-                       end: field.selectionEnd
-               }
-       }
-};
-
-})(jQuery);
\ No newline at end of file
diff --git a/redakcja/static/js/jquery.blockui.js b/redakcja/static/js/jquery.blockui.js
deleted file mode 100644 (file)
index 5491667..0000000
+++ /dev/null
@@ -1,477 +0,0 @@
-/*!
- * jQuery blockUI plugin
- * Version 2.31 (06-JAN-2010)
- * @requires jQuery v1.2.3 or later
- *
- * Examples at: http://malsup.com/jquery/block/
- * Copyright (c) 2007-2008 M. Alsup
- * Dual licensed under the MIT and GPL licenses:
- * http://www.opensource.org/licenses/mit-license.php
- * http://www.gnu.org/licenses/gpl.html
- *
- * Thanks to Amir-Hossein Sobhi for some excellent contributions!
- */
-
-;(function($) {
-
-if (/1\.(0|1|2)\.(0|1|2)/.test($.fn.jquery) || /^1.1/.test($.fn.jquery)) {
-       alert('blockUI requires jQuery v1.2.3 or later!  You are using v' + $.fn.jquery);
-       return;
-}
-
-$.fn._fadeIn = $.fn.fadeIn;
-
-var noOp = function() {};
-
-// this bit is to ensure we don't call setExpression when we shouldn't (with extra muscle to handle
-// retarded userAgent strings on Vista)
-var mode = document.documentMode || 0;
-var setExpr = $.browser.msie && (($.browser.version < 8 && !mode) || mode < 8);
-var ie6 = $.browser.msie && /MSIE 6.0/.test(navigator.userAgent) && !mode;
-
-// global $ methods for blocking/unblocking the entire page
-$.blockUI   = function(opts) { install(window, opts); };
-$.unblockUI = function(opts) { remove(window, opts); };
-
-// convenience method for quick growl-like notifications  (http://www.google.com/search?q=growl)
-$.growlUI = function(title, message, timeout, onClose) {
-       var $m = $('<div class="growlUI"></div>');
-       if (title) $m.append('<h1>'+title+'</h1>');
-       if (message) $m.append('<h2>'+message+'</h2>');
-       if (timeout == undefined) timeout = 3000;
-       $.blockUI({
-               message: $m, fadeIn: 700, fadeOut: 1000, centerY: false,
-               timeout: timeout, showOverlay: false,
-               onUnblock: onClose,
-               css: $.blockUI.defaults.growlCSS
-       });
-};
-
-// plugin method for blocking element content
-$.fn.block = function(opts) {
-       return this.unblock({ fadeOut: 0 }).each(function() {
-               if ($.css(this,'position') == 'static')
-                       this.style.position = 'relative';
-               if ($.browser.msie)
-                       this.style.zoom = 1; // force 'hasLayout'
-               install(this, opts);
-       });
-};
-
-// plugin method for unblocking element content
-$.fn.unblock = function(opts) {
-       return this.each(function() {
-               remove(this, opts);
-       });
-};
-
-$.blockUI.version = 2.31; // 2nd generation blocking at no extra cost!
-
-// override these in your code to change the default behavior and style
-$.blockUI.defaults = {
-       // message displayed when blocking (use null for no message)
-       message:  '<h1>Please wait...</h1>',
-
-       title: null,      // title string; only used when theme == true
-       draggable: true,  // only used when theme == true (requires jquery-ui.js to be loaded)
-
-       theme: false, // set to true to use with jQuery UI themes
-
-       // styles for the message when blocking; if you wish to disable
-       // these and use an external stylesheet then do this in your code:
-       // $.blockUI.defaults.css = {};
-       css: {
-               padding:        0,
-               margin:         0,
-               width:          '30%',
-               top:            '40%',
-               left:           '35%',
-               textAlign:      'center',
-               color:          '#000',
-               border:         '3px solid #aaa',
-               backgroundColor:'#fff',
-               cursor:         'wait'
-       },
-
-       // minimal style set used when themes are used
-       themedCSS: {
-               width:  '30%',
-               top:    '40%',
-               left:   '35%'
-       },
-
-       // styles for the overlay
-       overlayCSS:  {
-               backgroundColor: '#000',
-               opacity:                 0.6,
-               cursor:                  'wait'
-       },
-
-       // styles applied when using $.growlUI
-       growlCSS: {
-               width:          '350px',
-               top:            '10px',
-               left:           '',
-               right:          '10px',
-               border:         'none',
-               padding:        '5px',
-               opacity:        0.6,
-               cursor:         'default',
-               color:          '#fff',
-               backgroundColor: '#000',
-               '-webkit-border-radius': '10px',
-               '-moz-border-radius':    '10px'
-       },
-
-       // IE issues: 'about:blank' fails on HTTPS and javascript:false is s-l-o-w
-       // (hat tip to Jorge H. N. de Vasconcelos)
-       iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank',
-
-       // force usage of iframe in non-IE browsers (handy for blocking applets)
-       forceIframe: false,
-
-       // z-index for the blocking overlay
-       baseZ: 1000,
-
-       // set these to true to have the message automatically centered
-       centerX: true, // <-- only effects element blocking (page block controlled via css above)
-       centerY: true,
-
-       // allow body element to be stetched in ie6; this makes blocking look better
-       // on "short" pages.  disable if you wish to prevent changes to the body height
-       allowBodyStretch: true,
-
-       // enable if you want key and mouse events to be disabled for content that is blocked
-       bindEvents: true,
-
-       // be default blockUI will supress tab navigation from leaving blocking content
-       // (if bindEvents is true)
-       constrainTabKey: true,
-
-       // fadeIn time in millis; set to 0 to disable fadeIn on block
-       fadeIn:  200,
-
-       // fadeOut time in millis; set to 0 to disable fadeOut on unblock
-       fadeOut:  400,
-
-       // time in millis to wait before auto-unblocking; set to 0 to disable auto-unblock
-       timeout: 0,
-
-       // disable if you don't want to show the overlay
-       showOverlay: true,
-
-       // if true, focus will be placed in the first available input field when
-       // page blocking
-       focusInput: true,
-
-       // suppresses the use of overlay styles on FF/Linux (due to performance issues with opacity)
-       applyPlatformOpacityRules: true,
-
-       // callback method invoked when fadeIn has completed and blocking message is visible
-       onBlock: null,
-
-       // callback method invoked when unblocking has completed; the callback is
-       // passed the element that has been unblocked (which is the window object for page
-       // blocks) and the options that were passed to the unblock call:
-       //       onUnblock(element, options)
-       onUnblock: null,
-
-       // don't ask; if you really must know: http://groups.google.com/group/jquery-en/browse_thread/thread/36640a8730503595/2f6a79a77a78e493#2f6a79a77a78e493
-       quirksmodeOffsetHack: 4
-};
-
-// private data and functions follow...
-
-var pageBlock = null;
-var pageBlockEls = [];
-
-function install(el, opts) {
-       var full = (el == window);
-       var msg = opts && opts.message !== undefined ? opts.message : undefined;
-       opts = $.extend({}, $.blockUI.defaults, opts || {});
-       opts.overlayCSS = $.extend({}, $.blockUI.defaults.overlayCSS, opts.overlayCSS || {});
-       var css = $.extend({}, $.blockUI.defaults.css, opts.css || {});
-       var themedCSS = $.extend({}, $.blockUI.defaults.themedCSS, opts.themedCSS || {});
-       msg = msg === undefined ? opts.message : msg;
-
-       // remove the current block (if there is one)
-       if (full && pageBlock)
-               remove(window, {fadeOut:0});
-
-       // if an existing element is being used as the blocking content then we capture
-       // its current place in the DOM (and current display style) so we can restore
-       // it when we unblock
-       if (msg && typeof msg != 'string' && (msg.parentNode || msg.jquery)) {
-               var node = msg.jquery ? msg[0] : msg;
-               var data = {};
-               $(el).data('blockUI.history', data);
-               data.el = node;
-               data.parent = node.parentNode;
-               data.display = node.style.display;
-               data.position = node.style.position;
-               if (data.parent)
-                       data.parent.removeChild(node);
-       }
-
-       var z = opts.baseZ;
-
-       // blockUI uses 3 layers for blocking, for simplicity they are all used on every platform;
-       // layer1 is the iframe layer which is used to supress bleed through of underlying content
-       // layer2 is the overlay layer which has opacity and a wait cursor (by default)
-       // layer3 is the message content that is displayed while blocking
-
-       var lyr1 = ($.browser.msie || opts.forceIframe)
-               ? $('<iframe class="blockUI" style="z-index:'+ (z++) +';display:none;border:none;margin:0;padding:0;position:absolute;width:100%;height:100%;top:0;left:0" src="'+opts.iframeSrc+'"></iframe>')
-               : $('<div class="blockUI" style="display:none"></div>');
-       var lyr2 = $('<div class="blockUI blockOverlay" style="z-index:'+ (z++) +';display:none;border:none;margin:0;padding:0;width:100%;height:100%;top:0;left:0"></div>');
-
-       var lyr3;
-       if (opts.theme && full) {
-               var s = '<div class="blockUI blockMsg blockPage ui-dialog ui-widget ui-corner-all" style="z-index:'+z+';display:none;position:fixed">' +
-                                       '<div class="ui-widget-header ui-dialog-titlebar blockTitle">'+(opts.title || '&nbsp;')+'</div>' +
-                                       '<div class="ui-widget-content ui-dialog-content"></div>' +
-                               '</div>';
-               lyr3 = $(s);
-       }
-       else {
-               lyr3 = full ? $('<div class="blockUI blockMsg blockPage" style="z-index:'+z+';display:none;position:fixed"></div>')
-                                       : $('<div class="blockUI blockMsg blockElement" style="z-index:'+z+';display:none;position:absolute"></div>');
-       }
-
-       // if we have a message, style it
-       if (msg) {
-               if (opts.theme) {
-                       lyr3.css(themedCSS);
-                       lyr3.addClass('ui-widget-content');
-               }
-               else
-                       lyr3.css(css);
-       }
-
-       // style the overlay
-       if (!opts.applyPlatformOpacityRules || !($.browser.mozilla && /Linux/.test(navigator.platform)))
-               lyr2.css(opts.overlayCSS);
-       lyr2.css('position', full ? 'fixed' : 'absolute');
-
-       // make iframe layer transparent in IE
-       if ($.browser.msie || opts.forceIframe)
-               lyr1.css('opacity',0.0);
-
-       //$([lyr1[0],lyr2[0],lyr3[0]]).appendTo(full ? 'body' : el);
-       var layers = [lyr1,lyr2,lyr3], $par = full ? $('body') : $(el);
-       $.each(layers, function() {
-               this.appendTo($par);
-       });
-
-       if (opts.theme && opts.draggable && $.fn.draggable) {
-               lyr3.draggable({
-                       handle: '.ui-dialog-titlebar',
-                       cancel: 'li'
-               });
-       }
-
-       // ie7 must use absolute positioning in quirks mode and to account for activex issues (when scrolling)
-       var expr = setExpr && (!$.boxModel || $('object,embed', full ? null : el).length > 0);
-       if (ie6 || expr) {
-               // give body 100% height
-               if (full && opts.allowBodyStretch && $.boxModel)
-                       $('html,body').css('height','100%');
-
-               // fix ie6 issue when blocked element has a border width
-               if ((ie6 || !$.boxModel) && !full) {
-                       var t = sz(el,'borderTopWidth'), l = sz(el,'borderLeftWidth');
-                       var fixT = t ? '(0 - '+t+')' : 0;
-                       var fixL = l ? '(0 - '+l+')' : 0;
-               }
-
-               // simulate fixed position
-               $.each([lyr1,lyr2,lyr3], function(i,o) {
-                       var s = o[0].style;
-                       s.position = 'absolute';
-                       if (i < 2) {
-                               full ? s.setExpression('height','Math.max(document.body.scrollHeight, document.body.offsetHeight) - (jQuery.boxModel?0:'+opts.quirksmodeOffsetHack+') + "px"')
-                                        : s.setExpression('height','this.parentNode.offsetHeight + "px"');
-                               full ? s.setExpression('width','jQuery.boxModel && document.documentElement.clientWidth || document.body.clientWidth + "px"')
-                                        : s.setExpression('width','this.parentNode.offsetWidth + "px"');
-                               if (fixL) s.setExpression('left', fixL);
-                               if (fixT) s.setExpression('top', fixT);
-                       }
-                       else if (opts.centerY) {
-                               if (full) s.setExpression('top','(document.documentElement.clientHeight || document.body.clientHeight) / 2 - (this.offsetHeight / 2) + (blah = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + "px"');
-                               s.marginTop = 0;
-                       }
-                       else if (!opts.centerY && full) {
-                               var top = (opts.css && opts.css.top) ? parseInt(opts.css.top) : 0;
-                               var expression = '((document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + '+top+') + "px"';
-                               s.setExpression('top',expression);
-                       }
-               });
-       }
-
-       // show the message
-       if (msg) {
-               if (opts.theme)
-                       lyr3.find('.ui-widget-content').append(msg);
-               else
-                       lyr3.append(msg);
-               if (msg.jquery || msg.nodeType)
-                       $(msg).show();
-       }
-
-       if (($.browser.msie || opts.forceIframe) && opts.showOverlay)
-               lyr1.show(); // opacity is zero
-       if (opts.fadeIn) {
-               var cb = opts.onBlock ? opts.onBlock : noOp;
-               var cb1 = (opts.showOverlay && !msg) ? cb : noOp;
-               var cb2 = msg ? cb : noOp;
-               if (opts.showOverlay)
-                       lyr2._fadeIn(opts.fadeIn, cb1);
-               if (msg)
-                       lyr3._fadeIn(opts.fadeIn, cb2);
-       }
-       else {
-               if (opts.showOverlay)
-                       lyr2.show();
-               if (msg)
-                       lyr3.show();
-               if (opts.onBlock)
-                       opts.onBlock();
-       }
-
-       // bind key and mouse events
-       bind(1, el, opts);
-
-       if (full) {
-               pageBlock = lyr3[0];
-               pageBlockEls = $(':input:enabled:visible',pageBlock);
-               if (opts.focusInput)
-                       setTimeout(focus, 20);
-       }
-       else
-               center(lyr3[0], opts.centerX, opts.centerY);
-
-       if (opts.timeout) {
-               // auto-unblock
-               var to = setTimeout(function() {
-                       full ? $.unblockUI(opts) : $(el).unblock(opts);
-               }, opts.timeout);
-               $(el).data('blockUI.timeout', to);
-       }
-};
-
-// remove the block
-function remove(el, opts) {
-       var full = (el == window);
-       var $el = $(el);
-       var data = $el.data('blockUI.history');
-       var to = $el.data('blockUI.timeout');
-       if (to) {
-               clearTimeout(to);
-               $el.removeData('blockUI.timeout');
-       }
-       opts = $.extend({}, $.blockUI.defaults, opts || {});
-       bind(0, el, opts); // unbind events
-
-       var els;
-       if (full) // crazy selector to handle odd field errors in ie6/7
-               els = $('body').children().filter('.blockUI').add('body > .blockUI');
-       else
-               els = $('.blockUI', el);
-
-       if (full)
-               pageBlock = pageBlockEls = null;
-
-       if (opts.fadeOut) {
-               els.fadeOut(opts.fadeOut);
-               setTimeout(function() { reset(els,data,opts,el); }, opts.fadeOut);
-       }
-       else
-               reset(els, data, opts, el);
-};
-
-// move blocking element back into the DOM where it started
-function reset(els,data,opts,el) {
-       els.each(function(i,o) {
-               // remove via DOM calls so we don't lose event handlers
-               if (this.parentNode)
-                       this.parentNode.removeChild(this);
-       });
-
-       if (data && data.el) {
-               data.el.style.display = data.display;
-               data.el.style.position = data.position;
-               if (data.parent)
-                       data.parent.appendChild(data.el);
-               $(el).removeData('blockUI.history');
-       }
-
-       if (typeof opts.onUnblock == 'function')
-               opts.onUnblock(el,opts);
-};
-
-// bind/unbind the handler
-function bind(b, el, opts) {
-       var full = el == window, $el = $(el);
-
-       // don't bother unbinding if there is nothing to unbind
-       if (!b && (full && !pageBlock || !full && !$el.data('blockUI.isBlocked')))
-               return;
-       if (!full)
-               $el.data('blockUI.isBlocked', b);
-
-       // don't bind events when overlay is not in use or if bindEvents is false
-       if (!opts.bindEvents || (b && !opts.showOverlay))
-               return;
-
-       // bind anchors and inputs for mouse and key events
-       var events = 'mousedown mouseup keydown keypress';
-       b ? $(document).bind(events, opts, handler) : $(document).unbind(events, handler);
-
-// former impl...
-//        var $e = $('a,:input');
-//        b ? $e.bind(events, opts, handler) : $e.unbind(events, handler);
-};
-
-// event handler to suppress keyboard/mouse events when blocking
-function handler(e) {
-       // allow tab navigation (conditionally)
-       if (e.keyCode && e.keyCode == 9) {
-               if (pageBlock && e.data.constrainTabKey) {
-                       var els = pageBlockEls;
-                       var fwd = !e.shiftKey && e.target == els[els.length-1];
-                       var back = e.shiftKey && e.target == els[0];
-                       if (fwd || back) {
-                               setTimeout(function(){focus(back)},10);
-                               return false;
-                       }
-               }
-       }
-       // allow events within the message content
-       if ($(e.target).parents('div.blockMsg').length > 0)
-               return true;
-
-       // allow events for content that is not being blocked
-       return $(e.target).parents().children().filter('div.blockUI').length == 0;
-};
-
-function focus(back) {
-       if (!pageBlockEls)
-               return;
-       var e = pageBlockEls[back===true ? pageBlockEls.length-1 : 0];
-       if (e)
-               e.focus();
-};
-
-function center(el, x, y) {
-       var p = el.parentNode, s = el.style;
-       var l = ((p.offsetWidth - el.offsetWidth)/2) - sz(p,'borderLeftWidth');
-       var t = ((p.offsetHeight - el.offsetHeight)/2) - sz(p,'borderTopWidth');
-       if (x) s.left = l > 0 ? (l+'px') : '0';
-       if (y) s.top  = t > 0 ? (t+'px') : '0';
-};
-
-function sz(el, p) {
-       return parseInt($.css(el,p))||0;
-};
-
-})(jQuery);
\ No newline at end of file
diff --git a/redakcja/static/js/jquery.elastic.js b/redakcja/static/js/jquery.elastic.js
deleted file mode 100644 (file)
index 24e16f4..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-(function(jQuery){jQuery.fn.extend({elastic:function(){var mimics=['paddingTop','paddingRight','paddingBottom','paddingLeft','fontSize','lineHeight','fontFamily','width','fontWeight'];return this.each(function(){if(this.type!='textarea'){return false;}
-var $textarea=jQuery(this),$twin=jQuery('<div />').css({'position':'absolute','display':'none','word-wrap':'break-word'}),lineHeight=parseInt($textarea.css('line-height'),10)||parseInt($textarea.css('font-size'),'10'),minheight=parseInt($textarea.css('height'),10)||lineHeight*3,maxheight=parseInt($textarea.css('max-height'),10)||Number.MAX_VALUE,goalheight=0,i=0;if(maxheight<0){maxheight=Number.MAX_VALUE;}
-$twin.appendTo($textarea.parent());var i=mimics.length;while(i--){$twin.css(mimics[i].toString(),$textarea.css(mimics[i].toString()));}
-function setHeightAndOverflow(height,overflow){curratedHeight=Math.floor(parseInt(height,10));if($textarea.height()!=curratedHeight){$textarea.css({'height':curratedHeight+'px','overflow':overflow});}}
-function update(){var textareaContent=$textarea.val().replace(/&/g,'&amp;').replace(/  /g,'&nbsp;').replace(/<|>/g,'&gt;').replace(/\n/g,'<br />');var twinContent=$twin.html();if(textareaContent+'&nbsp;'!=twinContent){$twin.html(textareaContent+'&nbsp;');if(Math.abs($twin.height()+lineHeight-$textarea.height())>3){var goalheight=$twin.height()+lineHeight;if(goalheight>=maxheight){setHeightAndOverflow(maxheight,'auto');}else if(goalheight<=minheight){setHeightAndOverflow(minheight,'hidden');}else{setHeightAndOverflow(goalheight,'hidden');}}}}
-$textarea.css({'overflow':'hidden'});$textarea.keyup(function(){update();});$textarea.live('input paste',function(e){setTimeout(update,250);});update();});}});})(jQuery);
\ No newline at end of file
index 8c62dab..8475989 100644 (file)
@@ -177,8 +177,8 @@ var CodeMirror = (function(){
     replaceChars: function(text, start, end) {
       this.editor.replaceChars(text, start, end);
     },
-    getSearchCursor: function(string, fromCursor) {
-      return this.editor.getSearchCursor(string, fromCursor);
+    getSearchCursor: function(string, fromCursor, regexp, case_sensitive) {
+      return this.editor.getSearchCursor(string, fromCursor, regexp, case_sensitive);
     },
 
     undo: function() {this.editor.history.undo();},
index f5fe841..4eb6d09 100644 (file)
@@ -223,7 +223,29 @@ var Editor = (function(){
   // indicating whether anything was found, and can be called again to
   // skip to the next find. Use the select and replace methods to
   // actually do something with the found locations.
-  function SearchCursor(editor, string, fromCursor) {
+  function SearchCursor(editor, string, fromCursor, regexp, case_sensitive) {
+
+    function casedIndexOf(hay, needle, case_sensitive) {
+        if (case_sensitive)
+            return hay.indexOf(needle);
+        else
+            return hay.toLowerCase().indexOf(needle.toLowerCase())
+    }
+
+    function casedLastIndexOf(hay, needle, case_sensitive) {
+        if (case_sensitive)
+            return hay.lastIndexOf(needle);
+        else
+            return hay.toLowerCase().lastIndexOf(needle.toLowerCase());
+    }
+
+    function casedEqual(a, b, case_sensitive) {
+        if (case_sensitive)
+            return a == b;
+        else
+            return a.toLowerCase() == b.toLowerCase();
+    }
+
     this.editor = editor;
     this.history = editor.history;
     this.history.commit();
@@ -252,7 +274,8 @@ var Editor = (function(){
       // For one-line strings, searching can be done simply by calling
       // indexOf on the current line.
       function() {
-        var match = cleanText(self.history.textAfter(self.line).slice(self.offset)).indexOf(string);
+        var match = casedIndexOf(cleanText(self.history.textAfter(self.line).slice(self.offset)),
+                string, case_sensitive);
         if (match > -1)
           return {from: {node: self.line, offset: self.offset + match},
                   to: {node: self.line, offset: self.offset + match + string.length}};
@@ -262,19 +285,19 @@ var Editor = (function(){
       // end of the line and the last match starts at the start.
       function() {
         var firstLine = cleanText(self.history.textAfter(self.line).slice(self.offset));
-        var match = firstLine.lastIndexOf(target[0]);
+        var match = casedLastIndexOf(firstLine, target[0], case_sensitive);
         if (match == -1 || match != firstLine.length - target[0].length)
           return false;
         var startOffset = self.offset + match;
 
         var line = self.history.nodeAfter(self.line);
         for (var i = 1; i < target.length - 1; i++) {
-          if (cleanText(self.history.textAfter(line)) != target[i])
+          if (!casedEqual(cleanText(self.history.textAfter(line)), target[i], case_sensitive))
             return false;
           line = self.history.nodeAfter(line);
         }
 
-        if (cleanText(self.history.textAfter(line)).indexOf(target[target.length - 1]) != 0)
+        if (casedIndexOf(cleanText(self.history.textAfter(line)), target[target.length - 1], case_sensitive) != 0)
           return false;
 
         return {from: {node: self.line, offset: startOffset},
@@ -619,8 +642,8 @@ var Editor = (function(){
               offset: lastLine.length};
     },
 
-    getSearchCursor: function(string, fromCursor) {
-      return new SearchCursor(this, string, fromCursor);
+    getSearchCursor: function(string, fromCursor, regexp, case_sensitive) {
+      return new SearchCursor(this, string, fromCursor, regexp, case_sensitive);
     },
 
     // Re-indent the whole buffer
diff --git a/redakcja/static/js/lib/jquery-1.4.2.min.js b/redakcja/static/js/lib/jquery-1.4.2.min.js
new file mode 100644 (file)
index 0000000..7c24308
--- /dev/null
@@ -0,0 +1,154 @@
+/*!
+ * jQuery JavaScript Library v1.4.2
+ * http://jquery.com/
+ *
+ * Copyright 2010, John Resig
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ * Copyright 2010, The Dojo Foundation
+ * Released under the MIT, BSD, and GPL Licenses.
+ *
+ * Date: Sat Feb 13 22:33:48 2010 -0500
+ */
+(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o<i;o++)e(a[o],b,f?d.call(a[o],o,e(a[o],b)):d,j);return a}return i?
+e(a[0],b):w}function J(){return(new Date).getTime()}function Y(){return false}function Z(){return true}function na(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function oa(a){var b,d=[],f=[],e=arguments,j,i,o,k,n,r;i=c.data(this,"events");if(!(a.liveFired===this||!i||!i.live||a.button&&a.type==="click")){a.liveFired=this;var u=i.live.slice(0);for(k=0;k<u.length;k++){i=u[k];i.origType.replace(O,"")===a.type?f.push(i.selector):u.splice(k--,1)}j=c(a.target).closest(f,a.currentTarget);n=0;for(r=
+j.length;n<r;n++)for(k=0;k<u.length;k++){i=u[k];if(j[n].selector===i.selector){o=j[n].elem;f=null;if(i.preType==="mouseenter"||i.preType==="mouseleave")f=c(a.relatedTarget).closest(i.selector)[0];if(!f||f!==o)d.push({elem:o,handleObj:i})}}n=0;for(r=d.length;n<r;n++){j=d[n];a.currentTarget=j.elem;a.data=j.handleObj.data;a.handleObj=j.handleObj;if(j.handleObj.origHandler.apply(j.elem,e)===false){b=false;break}}return b}}function pa(a,b){return"live."+(a&&a!=="*"?a+".":"")+b.replace(/\./g,"`").replace(/ /g,
+"&")}function qa(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function ra(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var f=c.data(a[d++]),e=c.data(this,f);if(f=f&&f.events){delete e.handle;e.events={};for(var j in f)for(var i in f[j])c.event.add(this,j,f[j][i],f[j][i].data)}}})}function sa(a,b,d){var f,e,j;b=b&&b[0]?b[0].ownerDocument||b[0]:s;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===s&&!ta.test(a[0])&&(c.support.checkClone||!ua.test(a[0]))){e=
+true;if(j=c.fragments[a[0]])if(j!==1)f=j}if(!f){f=b.createDocumentFragment();c.clean(a,b,f,d)}if(e)c.fragments[a[0]]=j?f:1;return{fragment:f,cacheable:e}}function K(a,b){var d={};c.each(va.concat.apply([],va.slice(0,b)),function(){d[this]=a});return d}function wa(a){return"scrollTo"in a&&a.document?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var c=function(a,b){return new c.fn.init(a,b)},Ra=A.jQuery,Sa=A.$,s=A.document,T,Ta=/^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/,
+Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&&
+(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this,
+a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b===
+"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this,
+function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b<d;b++)if((e=arguments[b])!=null)for(j in e){i=a[j];o=e[j];if(a!==o)if(f&&o&&(c.isPlainObject(o)||c.isArray(o))){i=i&&(c.isPlainObject(i)||
+c.isArray(i))?i:c.isArray(o)?[]:{};a[j]=c.extend(f,i,o)}else if(o!==w)a[j]=o}return a};c.extend({noConflict:function(a){A.$=Sa;if(a)A.jQuery=Ra;return c},isReady:false,ready:function(){if(!c.isReady){if(!s.body)return setTimeout(c.ready,13);c.isReady=true;if(Q){for(var a,b=0;a=Q[b++];)a.call(s,c);Q=null}c.fn.triggerHandler&&c(s).triggerHandler("ready")}},bindReady:function(){if(!xa){xa=true;if(s.readyState==="complete")return c.ready();if(s.addEventListener){s.addEventListener("DOMContentLoaded",
+L,false);A.addEventListener("load",c.ready,false)}else if(s.attachEvent){s.attachEvent("onreadystatechange",L);A.attachEvent("onload",c.ready);var a=false;try{a=A.frameElement==null}catch(b){}s.documentElement.doScroll&&a&&ma()}}},isFunction:function(a){return $.call(a)==="[object Function]"},isArray:function(a){return $.call(a)==="[object Array]"},isPlainObject:function(a){if(!a||$.call(a)!=="[object Object]"||a.nodeType||a.setInterval)return false;if(a.constructor&&!aa.call(a,"constructor")&&!aa.call(a.constructor.prototype,
+"isPrototypeOf"))return false;var b;for(b in a);return b===w||aa.call(a,b)},isEmptyObject:function(a){for(var b in a)return false;return true},error:function(a){throw a;},parseJSON:function(a){if(typeof a!=="string"||!a)return null;a=c.trim(a);if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return A.JSON&&A.JSON.parse?A.JSON.parse(a):(new Function("return "+
+a))();else c.error("Invalid JSON: "+a)},noop:function(){},globalEval:function(a){if(a&&Va.test(a)){var b=s.getElementsByTagName("head")[0]||s.documentElement,d=s.createElement("script");d.type="text/javascript";if(c.support.scriptEval)d.appendChild(s.createTextNode(a));else d.text=a;b.insertBefore(d,b.firstChild);b.removeChild(d)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,b,d){var f,e=0,j=a.length,i=j===w||c.isFunction(a);if(d)if(i)for(f in a){if(b.apply(a[f],
+d)===false)break}else for(;e<j;){if(b.apply(a[e++],d)===false)break}else if(i)for(f in a){if(b.call(a[f],f,a[f])===false)break}else for(d=a[0];e<j&&b.call(d,e,d)!==false;d=a[++e]);return a},trim:function(a){return(a||"").replace(Wa,"")},makeArray:function(a,b){b=b||[];if(a!=null)a.length==null||typeof a==="string"||c.isFunction(a)||typeof a!=="function"&&a.setInterval?ba.call(b,a):c.merge(b,a);return b},inArray:function(a,b){if(b.indexOf)return b.indexOf(a);for(var d=0,f=b.length;d<f;d++)if(b[d]===
+a)return d;return-1},merge:function(a,b){var d=a.length,f=0;if(typeof b.length==="number")for(var e=b.length;f<e;f++)a[d++]=b[f];else for(;b[f]!==w;)a[d++]=b[f++];a.length=d;return a},grep:function(a,b,d){for(var f=[],e=0,j=a.length;e<j;e++)!d!==!b(a[e],e)&&f.push(a[e]);return f},map:function(a,b,d){for(var f=[],e,j=0,i=a.length;j<i;j++){e=b(a[j],j,d);if(e!=null)f[f.length]=e}return f.concat.apply([],f)},guid:1,proxy:function(a,b,d){if(arguments.length===2)if(typeof b==="string"){d=a;a=d[b];b=w}else if(b&&
+!c.isFunction(b)){d=b;b=w}if(!b&&a)b=function(){return a.apply(d||this,arguments)};if(a)b.guid=a.guid=a.guid||b.guid||c.guid++;return b},uaMatch:function(a){a=a.toLowerCase();a=/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version)?[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||!/compatible/.test(a)&&/(mozilla)(?:.*? rv:([\w.]+))?/.exec(a)||[];return{browser:a[1]||"",version:a[2]||"0"}},browser:{}});P=c.uaMatch(P);if(P.browser){c.browser[P.browser]=true;c.browser.version=P.version}if(c.browser.webkit)c.browser.safari=
+true;if(ya)c.inArray=function(a,b){return ya.call(b,a)};T=c(s);if(s.addEventListener)L=function(){s.removeEventListener("DOMContentLoaded",L,false);c.ready()};else if(s.attachEvent)L=function(){if(s.readyState==="complete"){s.detachEvent("onreadystatechange",L);c.ready()}};(function(){c.support={};var a=s.documentElement,b=s.createElement("script"),d=s.createElement("div"),f="script"+J();d.style.display="none";d.innerHTML="   <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
+var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected,
+parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent=
+false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n=
+s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true,
+applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando];
+else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this,
+a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===
+w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i,
+cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1)if(e.className){for(var j=" "+e.className+" ",
+i=e.className,o=0,k=b.length;o<k;o++)if(j.indexOf(" "+b[o]+" ")<0)i+=" "+b[o];e.className=c.trim(i)}else e.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(k){var n=c(this);n.removeClass(a.call(this,k,n.attr("class")))});if(a&&typeof a==="string"||a===w)for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1&&e.className)if(a){for(var j=(" "+e.className+" ").replace(Aa," "),i=0,o=b.length;i<o;i++)j=j.replace(" "+b[i]+" ",
+" ");e.className=c.trim(j)}else e.className=""}return this},toggleClass:function(a,b){var d=typeof a,f=typeof b==="boolean";if(c.isFunction(a))return this.each(function(e){var j=c(this);j.toggleClass(a.call(this,e,j.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var e,j=0,i=c(this),o=b,k=a.split(ca);e=k[j++];){o=f?o:!i.hasClass(e);i[o?"addClass":"removeClass"](e)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this,"__className__",this.className);this.className=
+this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(Aa," ").indexOf(a)>-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j<d;j++){var i=
+e[j];if(i.selected){a=c(i).val();if(b)return a;f.push(a)}}return f}if(Ba.test(b.type)&&!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Za,"")}return w}var o=c.isFunction(a);return this.each(function(k){var n=c(this),r=a;if(this.nodeType===1){if(o)r=a.call(this,k,n.val());if(typeof r==="number")r+="";if(c.isArray(r)&&Ba.test(this.type))this.checked=c.inArray(n.val(),r)>=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected=
+c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");
+a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g,
+function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split(".");
+k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a),
+C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B<r.length;B++){u=r[B];if(d.guid===u.guid){if(i||k.test(u.namespace)){f==null&&r.splice(B--,1);n.remove&&n.remove.call(a,u)}if(f!=
+null)break}}if(r.length===0||f!=null&&r.length===1){if(!n.teardown||n.teardown.call(a,o)===false)Ca(a,e,z.handle);delete C[e]}}else for(var B=0;B<r.length;B++){u=r[B];if(i||k.test(u.namespace)){c.event.remove(a,n,u.handler,B);r.splice(B--,1)}}}if(c.isEmptyObject(C)){if(b=z.handle)b.elem=null;delete z.events;delete z.handle;c.isEmptyObject(z)&&c.removeData(a)}}}}},trigger:function(a,b,d,f){var e=a.type||a;if(!f){a=typeof a==="object"?a[G]?a:c.extend(c.Event(e),a):c.Event(e);if(e.indexOf("!")>=0){a.type=
+e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&&
+f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;
+if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e<j;e++){var i=d[e];if(b||f.test(i.namespace)){a.handler=i.handler;a.data=i.data;a.handleObj=i;i=i.handler.apply(this,arguments);if(i!==w){a.result=i;if(i===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}}return a.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
+fix:function(a){if(a[G])return a;var b=a;a=c.Event(b);for(var d=this.props.length,f;d;){f=this.props[--d];a[f]=b[f]}if(!a.target)a.target=a.srcElement||s;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=s.documentElement;d=s.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop||
+d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(!a.which&&(a.charCode||a.charCode===0?a.charCode:a.keyCode))a.which=a.charCode||a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==w)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a){c.event.add(this,a.origType,c.extend({},a,{handler:oa}))},remove:function(a){var b=true,d=a.origType.replace(O,"");c.each(c.data(this,
+"events").live||[],function(){if(d===this.origType.replace(O,""))return b=false});b&&c.event.remove(this,a.origType,oa)}},beforeunload:{setup:function(a,b,d){if(this.setInterval)this.onbeforeunload=d;return false},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};var Ca=s.removeEventListener?function(a,b,d){a.removeEventListener(b,d,false)}:function(a,b,d){a.detachEvent("on"+b,d)};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=
+a;this.type=a.type}else this.type=a;this.timeStamp=J();this[G]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=Z;var a=this.originalEvent;if(a){a.preventDefault&&a.preventDefault();a.returnValue=false}},stopPropagation:function(){this.isPropagationStopped=Z;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=Z;this.stopPropagation()},isDefaultPrevented:Y,isPropagationStopped:Y,
+isImmediatePropagationStopped:Y};var Da=function(a){var b=a.relatedTarget;try{for(;b&&b!==this;)b=b.parentNode;if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}}catch(d){}},Ea=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?Ea:Da,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?Ea:Da)}}});if(!c.support.submitBubbles)c.event.special.submit=
+{setup:function(){if(this.nodeName.toLowerCase()!=="form"){c.event.add(this,"click.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="submit"||d==="image")&&c(b).closest("form").length)return na("submit",this,arguments)});c.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="text"||d==="password")&&c(b).closest("form").length&&a.keyCode===13)return na("submit",this,arguments)})}else return false},teardown:function(){c.event.remove(this,".specialSubmit")}};
+if(!c.support.changeBubbles){var da=/textarea|input|select/i,ea,Fa=function(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",
+e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,
+"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a,
+d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j<o;j++)c.event.add(this[j],d,i,f)}return this}});c.fn.extend({unbind:function(a,b){if(typeof a==="object"&&
+!a.preventDefault)for(var d in a)this.unbind(d,a[d]);else{d=0;for(var f=this.length;d<f;d++)c.event.remove(this[d],a,b)}return this},delegate:function(a,b,d,f){return this.live(b,d,f,a)},undelegate:function(a,b,d){return arguments.length===0?this.unbind("live"):this.die(b,null,d,a)},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){a=c.Event(a);a.preventDefault();a.stopPropagation();c.event.trigger(a,b,this[0]);return a.result}},
+toggle:function(a){for(var b=arguments,d=1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(f){var e=(c.data(this,"lastToggle"+a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,e+1);f.preventDefault();return b[e].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var Ga={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};c.each(["live","die"],function(a,b){c.fn[b]=function(d,f,e,j){var i,o=0,k,n,r=j||this.selector,
+u=j?this:c(this.context);if(c.isFunction(f)){e=f;f=w}for(d=(d||"").split(" ");(i=d[o++])!=null;){j=O.exec(i);k="";if(j){k=j[0];i=i.replace(O,"")}if(i==="hover")d.push("mouseenter"+k,"mouseleave"+k);else{n=i;if(i==="focus"||i==="blur"){d.push(Ga[i]+k);i+=k}else i=(Ga[i]||i)+k;b==="live"?u.each(function(){c.event.add(this,pa(i,r),{data:f,selector:r,handler:e,origType:i,origHandler:e,preType:n})}):u.unbind(pa(i,r),e)}}return this}});c.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),
+function(a,b){c.fn[b]=function(d){return d?this.bind(b,d):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});A.attachEvent&&!A.addEventListener&&A.attachEvent("onunload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});(function(){function a(g){for(var h="",l,m=0;g[m];m++){l=g[m];if(l.nodeType===3||l.nodeType===4)h+=l.nodeValue;else if(l.nodeType!==8)h+=a(l.childNodes)}return h}function b(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];
+if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1&&!p){t.sizcache=l;t.sizset=q}if(t.nodeName.toLowerCase()===h){y=t;break}t=t[g]}m[q]=y}}}function d(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1){if(!p){t.sizcache=l;t.sizset=q}if(typeof h!=="string"){if(t===h){y=true;break}}else if(k.filter(h,[t]).length>0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
+e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift();
+t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D||
+g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h<g.length;h++)g[h]===g[h-1]&&g.splice(h--,1)}return g};k.matches=function(g,h){return k(g,null,null,h)};k.find=function(g,h,l){var m,q;if(!g)return[];
+for(var p=0,v=n.order.length;p<v;p++){var t=n.order[p];if(q=n.leftMatch[t].exec(g)){var y=q[1];q.splice(1,1);if(y.substr(y.length-1)!=="\\"){q[1]=(q[1]||"").replace(/\\/g,"");m=n.find[t](q,h,l);if(m!=null){g=g.replace(n.match[t],"");break}}}}m||(m=h.getElementsByTagName("*"));return{set:m,expr:g}};k.filter=function(g,h,l,m){for(var q=g,p=[],v=h,t,y,S=h&&h[0]&&x(h[0]);g&&h.length;){for(var H in n.filter)if((t=n.leftMatch[H].exec(g))!=null&&t[2]){var M=n.filter[H],I,D;D=t[1];y=false;t.splice(1,1);if(D.substr(D.length-
+1)!=="\\"){if(v===p)p=[];if(n.preFilter[H])if(t=n.preFilter[H](t,v,l,p,m,S)){if(t===true)continue}else y=I=true;if(t)for(var U=0;(D=v[U])!=null;U++)if(D){I=M(D,t,U,v);var Ha=m^!!I;if(l&&I!=null)if(Ha)y=true;else v[U]=false;else if(Ha){p.push(D);y=true}}if(I!==w){l||(v=p);g=g.replace(n.match[H],"");if(!y)return[];break}}}if(g===q)if(y==null)k.error(g);else break;q=g}return v};k.error=function(g){throw"Syntax error, unrecognized expression: "+g;};var n=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
+CLASS:/\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}},
+relative:{"+":function(g,h){var l=typeof h==="string",m=l&&!/\W/.test(h);l=l&&!m;if(m)h=h.toLowerCase();m=0;for(var q=g.length,p;m<q;m++)if(p=g[m]){for(;(p=p.previousSibling)&&p.nodeType!==1;);g[m]=l||p&&p.nodeName.toLowerCase()===h?p||false:p===h}l&&k.filter(h,g,true)},">":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m<q;m++){var p=g[m];if(p){l=p.parentNode;g[m]=l.nodeName.toLowerCase()===h?l:false}}}else{m=0;for(q=g.length;m<q;m++)if(p=g[m])g[m]=
+l?p.parentNode:p.parentNode===h;l&&k.filter(h,g,true)}},"":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("parentNode",h,m,g,p,l)},"~":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("previousSibling",h,m,g,p,l)}},find:{ID:function(g,h,l){if(typeof h.getElementById!=="undefined"&&!l)return(g=h.getElementById(g[1]))?[g]:[]},NAME:function(g,h){if(typeof h.getElementsByName!=="undefined"){var l=[];
+h=h.getElementsByName(g[1]);for(var m=0,q=h.length;m<q;m++)h[m].getAttribute("name")===g[1]&&l.push(h[m]);return l.length===0?null:l}},TAG:function(g,h){return h.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,h,l,m,q,p){g=" "+g[1].replace(/\\/g,"")+" ";if(p)return g;p=0;for(var v;(v=h[p])!=null;p++)if(v)if(q^(v.className&&(" "+v.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},
+CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m,
+g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},
+text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},
+setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return h<l[3]-0},gt:function(g,h,l){return h>l[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h=
+h[3];l=0;for(m=h.length;l<m;l++)if(h[l]===g)return false;return true}else k.error("Syntax error, unrecognized expression: "+q)},CHILD:function(g,h){var l=h[1],m=g;switch(l){case "only":case "first":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(l==="first")return true;m=g;case "last":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case "nth":l=h[2];var q=h[3];if(l===1&&q===0)return true;h=h[0];var p=g.parentNode;if(p&&(p.sizcache!==h||!g.nodeIndex)){var v=0;for(m=p.firstChild;m;m=
+m.nextSibling)if(m.nodeType===1)m.nodeIndex=++v;p.sizcache=h}g=g.nodeIndex-q;return l===0?g===0:g%l===0&&g/l>=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m===
+"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g,
+h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l<m;l++)h.push(g[l]);else for(l=0;g[l];l++)h.push(g[l]);return h}}var B;if(s.documentElement.compareDocumentPosition)B=function(g,h){if(!g.compareDocumentPosition||
+!h.compareDocumentPosition){if(g==h)i=true;return g.compareDocumentPosition?-1:1}g=g.compareDocumentPosition(h)&4?-1:g===h?0:1;if(g===0)i=true;return g};else if("sourceIndex"in s.documentElement)B=function(g,h){if(!g.sourceIndex||!h.sourceIndex){if(g==h)i=true;return g.sourceIndex?-1:1}g=g.sourceIndex-h.sourceIndex;if(g===0)i=true;return g};else if(s.createRange)B=function(g,h){if(!g.ownerDocument||!h.ownerDocument){if(g==h)i=true;return g.ownerDocument?-1:1}var l=g.ownerDocument.createRange(),m=
+h.ownerDocument.createRange();l.setStart(g,0);l.setEnd(g,0);m.setStart(h,0);m.setEnd(h,0);g=l.compareBoundaryPoints(Range.START_TO_END,m);if(g===0)i=true;return g};(function(){var g=s.createElement("div"),h="script"+(new Date).getTime();g.innerHTML="<a name='"+h+"'/>";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&&
+q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML="<a href='#'></a>";
+if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="<p class='TEST'></p>";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}();
+(function(){var g=s.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}:
+function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q<p;q++)k(g,h[q],l);return k.filter(m,l)};c.find=k;c.expr=k.selectors;c.expr[":"]=c.expr.filters;c.unique=k.uniqueSort;c.text=a;c.isXMLDoc=x;c.contains=E})();var eb=/Until$/,fb=/^(?:parents|prevUntil|prevAll)/,
+gb=/,/;R=Array.prototype.slice;var Ia=function(a,b,d){if(c.isFunction(b))return c.grep(a,function(e,j){return!!b.call(e,j,e)===d});else if(b.nodeType)return c.grep(a,function(e){return e===b===d});else if(typeof b==="string"){var f=c.grep(a,function(e){return e.nodeType===1});if(Ua.test(b))return c.filter(b,f,!d);else b=c.filter(b,f)}return c.grep(a,function(e){return c.inArray(e,b)>=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f<e;f++){d=b.length;
+c.find(a,this[f],b);if(f>0)for(var j=d;j<b.length;j++)for(var i=0;i<d;i++)if(b[i]===b[j]){b.splice(j--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,f=b.length;d<f;d++)if(c.contains(this,b[d]))return true})},not:function(a){return this.pushStack(Ia(this,a,false),"not",a)},filter:function(a){return this.pushStack(Ia(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j=
+{},i;if(f&&a.length){e=0;for(var o=a.length;e<o;e++){i=a[e];j[i]||(j[i]=c.expr.match.POS.test(i)?c(i,b||this.context):i)}for(;f&&f.ownerDocument&&f!==b;){for(i in j){e=j[i];if(e.jquery?e.index(f)>-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a===
+"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",
+d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?
+a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType===
+1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/<tbody/i,jb=/<|&#?\w+;/,ta=/<script|<object|<embed|<option|<style/i,ua=/checked\s*(?:[^=]|=\s*.checked.)/i,Ma=function(a,b,d){return hb.test(d)?
+a:b+"></"+d+">"},F={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=
+c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},
+wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},
+prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,
+this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild);
+return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja,
+""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(f){this.empty().append(a)}}else c.isFunction(a)?this.each(function(e){var j=c(this),i=j.html();j.empty().append(function(){return a.call(this,e,i)})}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&
+this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d=c(this),f=d.html();d.replaceWith(a.call(this,b,f))});if(typeof a!=="string")a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){function f(u){return c.nodeName(u,"table")?u.getElementsByTagName("tbody")[0]||
+u.appendChild(u.ownerDocument.createElement("tbody")):u}var e,j,i=a[0],o=[],k;if(!c.support.checkClone&&arguments.length===3&&typeof i==="string"&&ua.test(i))return this.each(function(){c(this).domManip(a,b,d,true)});if(c.isFunction(i))return this.each(function(u){var z=c(this);a[0]=i.call(this,u,b?z.html():w);z.domManip(a,b,d)});if(this[0]){e=i&&i.parentNode;e=c.support.parentNode&&e&&e.nodeType===11&&e.childNodes.length===this.length?{fragment:e}:sa(a,this,o);k=e.fragment;if(j=k.childNodes.length===
+1?(k=k.firstChild):k.firstChild){b=b&&c.nodeName(j,"tr");for(var n=0,r=this.length;n<r;n++)d.call(b?f(this[n],j):this[n],n>0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]);
+return this}else{e=0;for(var j=d.length;e<j;e++){var i=(e>0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["",
+""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]==="<table>"&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e=
+c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]?
+c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja=
+function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter=
+Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a,
+"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f=
+a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=
+a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=/<script(.|\s)*?\/script>/gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!==
+"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("<div />").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this},
+serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),
+function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,
+global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&&
+e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)?
+"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache===
+false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B=
+false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since",
+c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E||
+d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x);
+g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===
+1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b===
+"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional;
+if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");
+this[a].style.display=d||"";if(c.css(this[a],"display")==="none"){d=this[a].nodeName;var f;if(la[d])f=la[d];else{var e=c("<"+d+" />").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a<b;a++)this[a].style.display=c.data(this[a],"olddisplay")||"";return this}},hide:function(a,b){if(a||a===0)return this.animate(K("hide",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");!d&&d!=="none"&&c.data(this[a],
+"olddisplay",c.css(this[a],"display"))}a=0;for(b=this.length;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b){var d=typeof a==="boolean";if(c.isFunction(a)&&c.isFunction(b))this._toggle.apply(this,arguments);else a==null||d?this.each(function(){var f=d?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(K("toggle",3),a,b);return this},fadeTo:function(a,b,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d)},
+animate:function(a,b,d,f){var e=c.speed(b,d,f);if(c.isEmptyObject(a))return this.each(e.complete);return this[e.queue===false?"each":"queue"](function(){var j=c.extend({},e),i,o=this.nodeType===1&&c(this).is(":hidden"),k=this;for(i in a){var n=i.replace(ia,ja);if(i!==n){a[n]=a[i];delete a[i];i=n}if(a[i]==="hide"&&o||a[i]==="show"&&!o)return j.complete.call(this);if((i==="height"||i==="width")&&this.style){j.display=c.css(this,"display");j.overflow=this.style.overflow}if(c.isArray(a[i])){(j.specialEasing=
+j.specialEasing||{})[i]=a[i][1];a[i]=a[i][0]}}if(j.overflow!=null)this.style.overflow="hidden";j.curAnim=c.extend({},a);c.each(a,function(r,u){var z=new c.fx(k,j,r);if(Ab.test(u))z[u==="toggle"?o?"show":"hide":u](a);else{var C=Bb.exec(u),B=z.cur(true)||0;if(C){u=parseFloat(C[2]);var E=C[3]||"px";if(E!=="px"){k.style[r]=(u||1)+E;B=(u||1)/z.cur(true)*B;k.style[r]=B+E}if(C[1])u=(C[1]==="-="?-1:1)*u+B;z.custom(B,u,E)}else z.custom(B,u,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);
+this.each(function(){for(var f=d.length-1;f>=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration===
+"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||
+c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;
+this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=
+this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem,
+e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||
+c.fx.stop()},stop:function(){clearInterval(W);W=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===b.elem}).length};c.fn.offset="getBoundingClientRect"in s.documentElement?
+function(a){var b=this[0];if(a)return this.each(function(e){c.offset.setOffset(this,a,e)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);var d=b.getBoundingClientRect(),f=b.ownerDocument;b=f.body;f=f.documentElement;return{top:d.top+(self.pageYOffset||c.support.boxModel&&f.scrollTop||b.scrollTop)-(f.clientTop||b.clientTop||0),left:d.left+(self.pageXOffset||c.support.boxModel&&f.scrollLeft||b.scrollLeft)-(f.clientLeft||b.clientLeft||0)}}:function(a){var b=
+this[0];if(a)return this.each(function(r){c.offset.setOffset(this,a,r)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d=b.offsetParent,f=b,e=b.ownerDocument,j,i=e.documentElement,o=e.body;f=(e=e.defaultView)?e.getComputedStyle(b,null):b.currentStyle;for(var k=b.offsetTop,n=b.offsetLeft;(b=b.parentNode)&&b!==o&&b!==i;){if(c.offset.supportsFixedPosition&&f.position==="fixed")break;j=e?e.getComputedStyle(b,null):b.currentStyle;
+k-=b.scrollTop;n-=b.scrollLeft;if(b===d){k+=b.offsetTop;n+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(b.nodeName))){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=d;d=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&j.overflow!=="visible"){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=j}if(f.position==="relative"||f.position==="static"){k+=o.offsetTop;n+=o.offsetLeft}if(c.offset.supportsFixedPosition&&
+f.position==="fixed"){k+=Math.max(i.scrollTop,o.scrollTop);n+=Math.max(i.scrollLeft,o.scrollLeft)}return{top:k,left:n}};c.offset={initialize:function(){var a=s.body,b=s.createElement("div"),d,f,e,j=parseFloat(c.curCSS(a,"marginTop",true))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";
+a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b);
+c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a,
+d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top-
+f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset":
+"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in
+e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window);
diff --git a/redakcja/static/js/lib/jquery/jquery.autocomplete.js b/redakcja/static/js/lib/jquery/jquery.autocomplete.js
new file mode 100644 (file)
index 0000000..0d25ba6
--- /dev/null
@@ -0,0 +1,808 @@
+/*
+ * jQuery Autocomplete plugin 1.1
+ *
+ * Copyright (c) 2009 Jörn Zaefferer
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ *   http://www.opensource.org/licenses/mit-license.php
+ *   http://www.gnu.org/licenses/gpl.html
+ *
+ * Revision: $Id: jquery.autocomplete.js 15 2009-08-22 10:30:27Z joern.zaefferer $
+ */
+
+;(function($) {
+
+$.fn.extend({
+       autocomplete: function(urlOrData, options) {
+               var isUrl = typeof urlOrData == "string";
+               options = $.extend({}, $.Autocompleter.defaults, {
+                       url: isUrl ? urlOrData : null,
+                       data: isUrl ? null : urlOrData,
+                       delay: isUrl ? $.Autocompleter.defaults.delay : 10,
+                       max: options && !options.scroll ? 10 : 150
+               }, options);
+
+               // if highlight is set to false, replace it with a do-nothing function
+               options.highlight = options.highlight || function(value) { return value; };
+
+               // if the formatMatch option is not specified, then use formatItem for backwards compatibility
+               options.formatMatch = options.formatMatch || options.formatItem;
+
+               return this.each(function() {
+                       new $.Autocompleter(this, options);
+               });
+       },
+       result: function(handler) {
+               return this.bind("result", handler);
+       },
+       search: function(handler) {
+               return this.trigger("search", [handler]);
+       },
+       flushCache: function() {
+               return this.trigger("flushCache");
+       },
+       setOptions: function(options){
+               return this.trigger("setOptions", [options]);
+       },
+       unautocomplete: function() {
+               return this.trigger("unautocomplete");
+       }
+});
+
+$.Autocompleter = function(input, options) {
+
+       var KEY = {
+               UP: 38,
+               DOWN: 40,
+               DEL: 46,
+               TAB: 9,
+               RETURN: 13,
+               ESC: 27,
+               COMMA: 188,
+               PAGEUP: 33,
+               PAGEDOWN: 34,
+               BACKSPACE: 8
+       };
+
+       // Create $ object for input element
+       var $input = $(input).attr("autocomplete", "off").addClass(options.inputClass);
+
+       var timeout;
+       var previousValue = "";
+       var cache = $.Autocompleter.Cache(options);
+       var hasFocus = 0;
+       var lastKeyPressCode;
+       var config = {
+               mouseDownOnSelect: false
+       };
+       var select = $.Autocompleter.Select(options, input, selectCurrent, config);
+
+       var blockSubmit;
+
+       // prevent form submit in opera when selecting with return key
+       $.browser.opera && $(input.form).bind("submit.autocomplete", function() {
+               if (blockSubmit) {
+                       blockSubmit = false;
+                       return false;
+               }
+       });
+
+       // only opera doesn't trigger keydown multiple times while pressed, others don't work with keypress at all
+       $input.bind(($.browser.opera ? "keypress" : "keydown") + ".autocomplete", function(event) {
+               // a keypress means the input has focus
+               // avoids issue where input had focus before the autocomplete was applied
+               hasFocus = 1;
+               // track last key pressed
+               lastKeyPressCode = event.keyCode;
+               switch(event.keyCode) {
+
+                       case KEY.UP:
+                               event.preventDefault();
+                               if ( select.visible() ) {
+                                       select.prev();
+                               } else {
+                                       onChange(0, true);
+                               }
+                               break;
+
+                       case KEY.DOWN:
+                               event.preventDefault();
+                               if ( select.visible() ) {
+                                       select.next();
+                               } else {
+                                       onChange(0, true);
+                               }
+                               break;
+
+                       case KEY.PAGEUP:
+                               event.preventDefault();
+                               if ( select.visible() ) {
+                                       select.pageUp();
+                               } else {
+                                       onChange(0, true);
+                               }
+                               break;
+
+                       case KEY.PAGEDOWN:
+                               event.preventDefault();
+                               if ( select.visible() ) {
+                                       select.pageDown();
+                               } else {
+                                       onChange(0, true);
+                               }
+                               break;
+
+                       // matches also semicolon
+                       case options.multiple && $.trim(options.multipleSeparator) == "," && KEY.COMMA:
+                       case KEY.TAB:
+                       case KEY.RETURN:
+                               if( selectCurrent() ) {
+                                       // stop default to prevent a form submit, Opera needs special handling
+                                       event.preventDefault();
+                                       blockSubmit = true;
+                                       return false;
+                               }
+                               break;
+
+                       case KEY.ESC:
+                               select.hide();
+                               break;
+
+                       default:
+                               clearTimeout(timeout);
+                               timeout = setTimeout(onChange, options.delay);
+                               break;
+               }
+       }).focus(function(){
+               // track whether the field has focus, we shouldn't process any
+               // results if the field no longer has focus
+               hasFocus++;
+       }).blur(function() {
+               hasFocus = 0;
+               if (!config.mouseDownOnSelect) {
+                       hideResults();
+               }
+       }).click(function() {
+               // show select when clicking in a focused field
+               if ( hasFocus++ > 1 && !select.visible() ) {
+                       onChange(0, true);
+               }
+       }).bind("search", function() {
+               // TODO why not just specifying both arguments?
+               var fn = (arguments.length > 1) ? arguments[1] : null;
+               function findValueCallback(q, data) {
+                       var result;
+                       if( data && data.length ) {
+                               for (var i=0; i < data.length; i++) {
+                                       if( data[i].result.toLowerCase() == q.toLowerCase() ) {
+                                               result = data[i];
+                                               break;
+                                       }
+                               }
+                       }
+                       if( typeof fn == "function" ) fn(result);
+                       else $input.trigger("result", result && [result.data, result.value]);
+               }
+               $.each(trimWords($input.val()), function(i, value) {
+                       request(value, findValueCallback, findValueCallback);
+               });
+       }).bind("flushCache", function() {
+               cache.flush();
+       }).bind("setOptions", function() {
+               $.extend(options, arguments[1]);
+               // if we've updated the data, repopulate
+               if ( "data" in arguments[1] )
+                       cache.populate();
+       }).bind("unautocomplete", function() {
+               select.unbind();
+               $input.unbind();
+               $(input.form).unbind(".autocomplete");
+       });
+
+
+       function selectCurrent() {
+               var selected = select.selected();
+               if( !selected )
+                       return false;
+
+               var v = selected.result;
+               previousValue = v;
+
+               if ( options.multiple ) {
+                       var words = trimWords($input.val());
+                       if ( words.length > 1 ) {
+                               var seperator = options.multipleSeparator.length;
+                               var cursorAt = $(input).selection().start;
+                               var wordAt, progress = 0;
+                               $.each(words, function(i, word) {
+                                       progress += word.length;
+                                       if (cursorAt <= progress) {
+                                               wordAt = i;
+                                               return false;
+                                       }
+                                       progress += seperator;
+                               });
+                               words[wordAt] = v;
+                               // TODO this should set the cursor to the right position, but it gets overriden somewhere
+                               //$.Autocompleter.Selection(input, progress + seperator, progress + seperator);
+                               v = words.join( options.multipleSeparator );
+                       }
+                       v += options.multipleSeparator;
+               }
+
+               $input.val(v);
+               hideResultsNow();
+               $input.trigger("result", [selected.data, selected.value]);
+               return true;
+       }
+
+       function onChange(crap, skipPrevCheck) {
+               if( lastKeyPressCode == KEY.DEL ) {
+                       select.hide();
+                       return;
+               }
+
+               var currentValue = $input.val();
+
+               if ( !skipPrevCheck && currentValue == previousValue )
+                       return;
+
+               previousValue = currentValue;
+
+               currentValue = lastWord(currentValue);
+               if ( currentValue.length >= options.minChars) {
+                       $input.addClass(options.loadingClass);
+                       if (!options.matchCase)
+                               currentValue = currentValue.toLowerCase();
+                       request(currentValue, receiveData, hideResultsNow);
+               } else {
+                       stopLoading();
+                       select.hide();
+               }
+       };
+
+       function trimWords(value) {
+               if (!value)
+                       return [""];
+               if (!options.multiple)
+                       return [$.trim(value)];
+               return $.map(value.split(options.multipleSeparator), function(word) {
+                       return $.trim(value).length ? $.trim(word) : null;
+               });
+       }
+
+       function lastWord(value) {
+               if ( !options.multiple )
+                       return value;
+               var words = trimWords(value);
+               if (words.length == 1)
+                       return words[0];
+               var cursorAt = $(input).selection().start;
+               if (cursorAt == value.length) {
+                       words = trimWords(value)
+               } else {
+                       words = trimWords(value.replace(value.substring(cursorAt), ""));
+               }
+               return words[words.length - 1];
+       }
+
+       // fills in the input box w/the first match (assumed to be the best match)
+       // q: the term entered
+       // sValue: the first matching result
+       function autoFill(q, sValue){
+               // autofill in the complete box w/the first match as long as the user hasn't entered in more data
+               // if the last user key pressed was backspace, don't autofill
+               if( options.autoFill && (lastWord($input.val()).toLowerCase() == q.toLowerCase()) && lastKeyPressCode != KEY.BACKSPACE ) {
+                       // fill in the value (keep the case the user has typed)
+                       $input.val($input.val() + sValue.substring(lastWord(previousValue).length));
+                       // select the portion of the value not typed by the user (so the next character will erase)
+                       $(input).selection(previousValue.length, previousValue.length + sValue.length);
+               }
+       };
+
+       function hideResults() {
+               clearTimeout(timeout);
+               timeout = setTimeout(hideResultsNow, 200);
+       };
+
+       function hideResultsNow() {
+               var wasVisible = select.visible();
+               select.hide();
+               clearTimeout(timeout);
+               stopLoading();
+               if (options.mustMatch) {
+                       // call search and run callback
+                       $input.search(
+                               function (result){
+                                       // if no value found, clear the input box
+                                       if( !result ) {
+                                               if (options.multiple) {
+                                                       var words = trimWords($input.val()).slice(0, -1);
+                                                       $input.val( words.join(options.multipleSeparator) + (words.length ? options.multipleSeparator : "") );
+                                               }
+                                               else {
+                                                       $input.val( "" );
+                                                       $input.trigger("result", null);
+                                               }
+                                       }
+                               }
+                       );
+               }
+       };
+
+       function receiveData(q, data) {
+               if ( data && data.length && hasFocus ) {
+                       stopLoading();
+                       select.display(data, q);
+                       autoFill(q, data[0].value);
+                       select.show();
+               } else {
+                       hideResultsNow();
+               }
+       };
+
+       function request(term, success, failure) {
+               if (!options.matchCase)
+                       term = term.toLowerCase();
+               var data = cache.load(term);
+               // recieve the cached data
+               if (data && data.length) {
+                       success(term, data);
+               // if an AJAX url has been supplied, try loading the data now
+               } else if( (typeof options.url == "string") && (options.url.length > 0) ){
+
+                       var extraParams = {
+                               timestamp: +new Date()
+                       };
+                       $.each(options.extraParams, function(key, param) {
+                               extraParams[key] = typeof param == "function" ? param() : param;
+                       });
+
+                       $.ajax({
+                               // try to leverage ajaxQueue plugin to abort previous requests
+                               mode: "abort",
+                               // limit abortion to this input
+                               port: "autocomplete" + input.name,
+                               dataType: options.dataType,
+                               url: options.url,
+                               data: $.extend({
+                                       q: lastWord(term),
+                                       limit: options.max
+                               }, extraParams),
+                               success: function(data) {
+                                       var parsed = options.parse && options.parse(data) || parse(data);
+                                       cache.add(term, parsed);
+                                       success(term, parsed);
+                               }
+                       });
+               } else {
+                       // if we have a failure, we need to empty the list -- this prevents the the [TAB] key from selecting the last successful match
+                       select.emptyList();
+                       failure(term);
+               }
+       };
+
+       function parse(data) {
+               var parsed = [];
+               var rows = data.split("\n");
+               for (var i=0; i < rows.length; i++) {
+                       var row = $.trim(rows[i]);
+                       if (row) {
+                               row = row.split("|");
+                               parsed[parsed.length] = {
+                                       data: row,
+                                       value: row[0],
+                                       result: options.formatResult && options.formatResult(row, row[0]) || row[0]
+                               };
+                       }
+               }
+               return parsed;
+       };
+
+       function stopLoading() {
+               $input.removeClass(options.loadingClass);
+       };
+
+};
+
+$.Autocompleter.defaults = {
+       inputClass: "ac_input",
+       resultsClass: "ac_results",
+       loadingClass: "ac_loading",
+       minChars: 1,
+       delay: 400,
+       matchCase: false,
+       matchSubset: true,
+       matchContains: false,
+       cacheLength: 10,
+       max: 100,
+       mustMatch: false,
+       extraParams: {},
+       selectFirst: true,
+       formatItem: function(row) { return row[0]; },
+       formatMatch: null,
+       autoFill: false,
+       width: 0,
+       multiple: false,
+       multipleSeparator: ", ",
+       highlight: function(value, term) {
+               return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
+       },
+    scroll: true,
+    scrollHeight: 180
+};
+
+$.Autocompleter.Cache = function(options) {
+
+       var data = {};
+       var length = 0;
+
+       function matchSubset(s, sub) {
+               if (!options.matchCase)
+                       s = s.toLowerCase();
+               var i = s.indexOf(sub);
+               if (options.matchContains == "word"){
+                       i = s.toLowerCase().search("\\b" + sub.toLowerCase());
+               }
+               if (i == -1) return false;
+               return i == 0 || options.matchContains;
+       };
+
+       function add(q, value) {
+               if (length > options.cacheLength){
+                       flush();
+               }
+               if (!data[q]){
+                       length++;
+               }
+               data[q] = value;
+       }
+
+       function populate(){
+               if( !options.data ) return false;
+               // track the matches
+               var stMatchSets = {},
+                       nullData = 0;
+
+               // no url was specified, we need to adjust the cache length to make sure it fits the local data store
+               if( !options.url ) options.cacheLength = 1;
+
+               // track all options for minChars = 0
+               stMatchSets[""] = [];
+
+               // loop through the array and create a lookup structure
+               for ( var i = 0, ol = options.data.length; i < ol; i++ ) {
+                       var rawValue = options.data[i];
+                       // if rawValue is a string, make an array otherwise just reference the array
+                       rawValue = (typeof rawValue == "string") ? [rawValue] : rawValue;
+
+                       var value = options.formatMatch(rawValue, i+1, options.data.length);
+                       if ( value === false )
+                               continue;
+
+                       var firstChar = value.charAt(0).toLowerCase();
+                       // if no lookup array for this character exists, look it up now
+                       if( !stMatchSets[firstChar] )
+                               stMatchSets[firstChar] = [];
+
+                       // if the match is a string
+                       var row = {
+                               value: value,
+                               data: rawValue,
+                               result: options.formatResult && options.formatResult(rawValue) || value
+                       };
+
+                       // push the current match into the set list
+                       stMatchSets[firstChar].push(row);
+
+                       // keep track of minChars zero items
+                       if ( nullData++ < options.max ) {
+                               stMatchSets[""].push(row);
+                       }
+               };
+
+               // add the data items to the cache
+               $.each(stMatchSets, function(i, value) {
+                       // increase the cache size
+                       options.cacheLength++;
+                       // add to the cache
+                       add(i, value);
+               });
+       }
+
+       // populate any existing data
+       setTimeout(populate, 25);
+
+       function flush(){
+               data = {};
+               length = 0;
+       }
+
+       return {
+               flush: flush,
+               add: add,
+               populate: populate,
+               load: function(q) {
+                       if (!options.cacheLength || !length)
+                               return null;
+                       /*
+                        * if dealing w/local data and matchContains than we must make sure
+                        * to loop through all the data collections looking for matches
+                        */
+                       if( !options.url && options.matchContains ){
+                               // track all matches
+                               var csub = [];
+                               // loop through all the data grids for matches
+                               for( var k in data ){
+                                       // don't search through the stMatchSets[""] (minChars: 0) cache
+                                       // this prevents duplicates
+                                       if( k.length > 0 ){
+                                               var c = data[k];
+                                               $.each(c, function(i, x) {
+                                                       // if we've got a match, add it to the array
+                                                       if (matchSubset(x.value, q)) {
+                                                               csub.push(x);
+                                                       }
+                                               });
+                                       }
+                               }
+                               return csub;
+                       } else
+                       // if the exact item exists, use it
+                       if (data[q]){
+                               return data[q];
+                       } else
+                       if (options.matchSubset) {
+                               for (var i = q.length - 1; i >= options.minChars; i--) {
+                                       var c = data[q.substr(0, i)];
+                                       if (c) {
+                                               var csub = [];
+                                               $.each(c, function(i, x) {
+                                                       if (matchSubset(x.value, q)) {
+                                                               csub[csub.length] = x;
+                                                       }
+                                               });
+                                               return csub;
+                                       }
+                               }
+                       }
+                       return null;
+               }
+       };
+};
+
+$.Autocompleter.Select = function (options, input, select, config) {
+       var CLASSES = {
+               ACTIVE: "ac_over"
+       };
+
+       var listItems,
+               active = -1,
+               data,
+               term = "",
+               needsInit = true,
+               element,
+               list;
+
+       // Create results
+       function init() {
+               if (!needsInit)
+                       return;
+               element = $("<div/>")
+               .hide()
+               .addClass(options.resultsClass)
+               .css("position", "absolute")
+               .appendTo(document.body);
+
+               list = $("<ul/>").appendTo(element).mouseover( function(event) {
+                       if(target(event).nodeName && target(event).nodeName.toUpperCase() == 'LI') {
+                   active = $("li", list).removeClass(CLASSES.ACTIVE).index(target(event));
+                           $(target(event)).addClass(CLASSES.ACTIVE);
+               }
+               }).click(function(event) {
+                       $(target(event)).addClass(CLASSES.ACTIVE);
+                       select();
+                       // TODO provide option to avoid setting focus again after selection? useful for cleanup-on-focus
+                       input.focus();
+                       return false;
+               }).mousedown(function() {
+                       config.mouseDownOnSelect = true;
+               }).mouseup(function() {
+                       config.mouseDownOnSelect = false;
+               });
+
+               if( options.width > 0 )
+                       element.css("width", options.width);
+
+               needsInit = false;
+       }
+
+       function target(event) {
+               var element = event.target;
+               while(element && element.tagName != "LI")
+                       element = element.parentNode;
+               // more fun with IE, sometimes event.target is empty, just ignore it then
+               if(!element)
+                       return [];
+               return element;
+       }
+
+       function moveSelect(step) {
+               listItems.slice(active, active + 1).removeClass(CLASSES.ACTIVE);
+               movePosition(step);
+        var activeItem = listItems.slice(active, active + 1).addClass(CLASSES.ACTIVE);
+        if(options.scroll) {
+            var offset = 0;
+            listItems.slice(0, active).each(function() {
+                               offset += this.offsetHeight;
+                       });
+            if((offset + activeItem[0].offsetHeight - list.scrollTop()) > list[0].clientHeight) {
+                list.scrollTop(offset + activeItem[0].offsetHeight - list.innerHeight());
+            } else if(offset < list.scrollTop()) {
+                list.scrollTop(offset);
+            }
+        }
+       };
+
+       function movePosition(step) {
+               active += step;
+               if (active < 0) {
+                       active = listItems.size() - 1;
+               } else if (active >= listItems.size()) {
+                       active = 0;
+               }
+       }
+
+       function limitNumberOfItems(available) {
+               return options.max && options.max < available
+                       ? options.max
+                       : available;
+       }
+
+       function fillList() {
+               list.empty();
+               var max = limitNumberOfItems(data.length);
+               for (var i=0; i < max; i++) {
+                       if (!data[i])
+                               continue;
+                       var formatted = options.formatItem(data[i].data, i+1, max, data[i].value, term);
+                       if ( formatted === false )
+                               continue;
+                       var li = $("<li/>").html( options.highlight(formatted, term) ).addClass(i%2 == 0 ? "ac_even" : "ac_odd").appendTo(list)[0];
+                       $.data(li, "ac_data", data[i]);
+               }
+               listItems = list.find("li");
+               if ( options.selectFirst ) {
+                       listItems.slice(0, 1).addClass(CLASSES.ACTIVE);
+                       active = 0;
+               }
+               // apply bgiframe if available
+               if ( $.fn.bgiframe )
+                       list.bgiframe();
+       }
+
+       return {
+               display: function(d, q) {
+                       init();
+                       data = d;
+                       term = q;
+                       fillList();
+               },
+               next: function() {
+                       moveSelect(1);
+               },
+               prev: function() {
+                       moveSelect(-1);
+               },
+               pageUp: function() {
+                       if (active != 0 && active - 8 < 0) {
+                               moveSelect( -active );
+                       } else {
+                               moveSelect(-8);
+                       }
+               },
+               pageDown: function() {
+                       if (active != listItems.size() - 1 && active + 8 > listItems.size()) {
+                               moveSelect( listItems.size() - 1 - active );
+                       } else {
+                               moveSelect(8);
+                       }
+               },
+               hide: function() {
+                       element && element.hide();
+                       listItems && listItems.removeClass(CLASSES.ACTIVE);
+                       active = -1;
+               },
+               visible : function() {
+                       return element && element.is(":visible");
+               },
+               current: function() {
+                       return this.visible() && (listItems.filter("." + CLASSES.ACTIVE)[0] || options.selectFirst && listItems[0]);
+               },
+               show: function() {
+                       var offset = $(input).offset();
+                       element.css({
+                               width: typeof options.width == "string" || options.width > 0 ? options.width : $(input).width(),
+                               top: offset.top + input.offsetHeight,
+                               left: offset.left
+                       }).show();
+            if(options.scroll) {
+                list.scrollTop(0);
+                list.css({
+                                       maxHeight: options.scrollHeight,
+                                       overflow: 'auto'
+                               });
+
+                if($.browser.msie && typeof document.body.style.maxHeight === "undefined") {
+                                       var listHeight = 0;
+                                       listItems.each(function() {
+                                               listHeight += this.offsetHeight;
+                                       });
+                                       var scrollbarsVisible = listHeight > options.scrollHeight;
+                    list.css('height', scrollbarsVisible ? options.scrollHeight : listHeight );
+                                       if (!scrollbarsVisible) {
+                                               // IE doesn't recalculate width when scrollbar disappears
+                                               listItems.width( list.width() - parseInt(listItems.css("padding-left")) - parseInt(listItems.css("padding-right")) );
+                                       }
+                }
+
+            }
+               },
+               selected: function() {
+                       var selected = listItems && listItems.filter("." + CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE);
+                       return selected && selected.length && $.data(selected[0], "ac_data");
+               },
+               emptyList: function (){
+                       list && list.empty();
+               },
+               unbind: function() {
+                       element && element.remove();
+               }
+       };
+};
+
+$.fn.selection = function(start, end) {
+       if (start !== undefined) {
+               return this.each(function() {
+                       if( this.createTextRange ){
+                               var selRange = this.createTextRange();
+                               if (end === undefined || start == end) {
+                                       selRange.move("character", start);
+                                       selRange.select();
+                               } else {
+                                       selRange.collapse(true);
+                                       selRange.moveStart("character", start);
+                                       selRange.moveEnd("character", end);
+                                       selRange.select();
+                               }
+                       } else if( this.setSelectionRange ){
+                               this.setSelectionRange(start, end);
+                       } else if( this.selectionStart ){
+                               this.selectionStart = start;
+                               this.selectionEnd = end;
+                       }
+               });
+       }
+       var field = this[0];
+       if ( field.createTextRange ) {
+               var range = document.selection.createRange(),
+                       orig = field.value,
+                       teststring = "<->",
+                       textLength = range.text.length;
+               range.text = teststring;
+               var caretAt = field.value.indexOf(teststring);
+               field.value = orig;
+               this.selection(caretAt, caretAt + textLength);
+               return {
+                       start: caretAt,
+                       end: caretAt + textLength
+               }
+       } else if( field.selectionStart !== undefined ){
+               return {
+                       start: field.selectionStart,
+                       end: field.selectionEnd
+               }
+       }
+};
+
+})(jQuery);
\ No newline at end of file
diff --git a/redakcja/static/js/lib/jquery/jquery.blockui.js b/redakcja/static/js/lib/jquery/jquery.blockui.js
new file mode 100644 (file)
index 0000000..5491667
--- /dev/null
@@ -0,0 +1,477 @@
+/*!
+ * jQuery blockUI plugin
+ * Version 2.31 (06-JAN-2010)
+ * @requires jQuery v1.2.3 or later
+ *
+ * Examples at: http://malsup.com/jquery/block/
+ * Copyright (c) 2007-2008 M. Alsup
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * Thanks to Amir-Hossein Sobhi for some excellent contributions!
+ */
+
+;(function($) {
+
+if (/1\.(0|1|2)\.(0|1|2)/.test($.fn.jquery) || /^1.1/.test($.fn.jquery)) {
+       alert('blockUI requires jQuery v1.2.3 or later!  You are using v' + $.fn.jquery);
+       return;
+}
+
+$.fn._fadeIn = $.fn.fadeIn;
+
+var noOp = function() {};
+
+// this bit is to ensure we don't call setExpression when we shouldn't (with extra muscle to handle
+// retarded userAgent strings on Vista)
+var mode = document.documentMode || 0;
+var setExpr = $.browser.msie && (($.browser.version < 8 && !mode) || mode < 8);
+var ie6 = $.browser.msie && /MSIE 6.0/.test(navigator.userAgent) && !mode;
+
+// global $ methods for blocking/unblocking the entire page
+$.blockUI   = function(opts) { install(window, opts); };
+$.unblockUI = function(opts) { remove(window, opts); };
+
+// convenience method for quick growl-like notifications  (http://www.google.com/search?q=growl)
+$.growlUI = function(title, message, timeout, onClose) {
+       var $m = $('<div class="growlUI"></div>');
+       if (title) $m.append('<h1>'+title+'</h1>');
+       if (message) $m.append('<h2>'+message+'</h2>');
+       if (timeout == undefined) timeout = 3000;
+       $.blockUI({
+               message: $m, fadeIn: 700, fadeOut: 1000, centerY: false,
+               timeout: timeout, showOverlay: false,
+               onUnblock: onClose,
+               css: $.blockUI.defaults.growlCSS
+       });
+};
+
+// plugin method for blocking element content
+$.fn.block = function(opts) {
+       return this.unblock({ fadeOut: 0 }).each(function() {
+               if ($.css(this,'position') == 'static')
+                       this.style.position = 'relative';
+               if ($.browser.msie)
+                       this.style.zoom = 1; // force 'hasLayout'
+               install(this, opts);
+       });
+};
+
+// plugin method for unblocking element content
+$.fn.unblock = function(opts) {
+       return this.each(function() {
+               remove(this, opts);
+       });
+};
+
+$.blockUI.version = 2.31; // 2nd generation blocking at no extra cost!
+
+// override these in your code to change the default behavior and style
+$.blockUI.defaults = {
+       // message displayed when blocking (use null for no message)
+       message:  '<h1>Please wait...</h1>',
+
+       title: null,      // title string; only used when theme == true
+       draggable: true,  // only used when theme == true (requires jquery-ui.js to be loaded)
+
+       theme: false, // set to true to use with jQuery UI themes
+
+       // styles for the message when blocking; if you wish to disable
+       // these and use an external stylesheet then do this in your code:
+       // $.blockUI.defaults.css = {};
+       css: {
+               padding:        0,
+               margin:         0,
+               width:          '30%',
+               top:            '40%',
+               left:           '35%',
+               textAlign:      'center',
+               color:          '#000',
+               border:         '3px solid #aaa',
+               backgroundColor:'#fff',
+               cursor:         'wait'
+       },
+
+       // minimal style set used when themes are used
+       themedCSS: {
+               width:  '30%',
+               top:    '40%',
+               left:   '35%'
+       },
+
+       // styles for the overlay
+       overlayCSS:  {
+               backgroundColor: '#000',
+               opacity:                 0.6,
+               cursor:                  'wait'
+       },
+
+       // styles applied when using $.growlUI
+       growlCSS: {
+               width:          '350px',
+               top:            '10px',
+               left:           '',
+               right:          '10px',
+               border:         'none',
+               padding:        '5px',
+               opacity:        0.6,
+               cursor:         'default',
+               color:          '#fff',
+               backgroundColor: '#000',
+               '-webkit-border-radius': '10px',
+               '-moz-border-radius':    '10px'
+       },
+
+       // IE issues: 'about:blank' fails on HTTPS and javascript:false is s-l-o-w
+       // (hat tip to Jorge H. N. de Vasconcelos)
+       iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank',
+
+       // force usage of iframe in non-IE browsers (handy for blocking applets)
+       forceIframe: false,
+
+       // z-index for the blocking overlay
+       baseZ: 1000,
+
+       // set these to true to have the message automatically centered
+       centerX: true, // <-- only effects element blocking (page block controlled via css above)
+       centerY: true,
+
+       // allow body element to be stetched in ie6; this makes blocking look better
+       // on "short" pages.  disable if you wish to prevent changes to the body height
+       allowBodyStretch: true,
+
+       // enable if you want key and mouse events to be disabled for content that is blocked
+       bindEvents: true,
+
+       // be default blockUI will supress tab navigation from leaving blocking content
+       // (if bindEvents is true)
+       constrainTabKey: true,
+
+       // fadeIn time in millis; set to 0 to disable fadeIn on block
+       fadeIn:  200,
+
+       // fadeOut time in millis; set to 0 to disable fadeOut on unblock
+       fadeOut:  400,
+
+       // time in millis to wait before auto-unblocking; set to 0 to disable auto-unblock
+       timeout: 0,
+
+       // disable if you don't want to show the overlay
+       showOverlay: true,
+
+       // if true, focus will be placed in the first available input field when
+       // page blocking
+       focusInput: true,
+
+       // suppresses the use of overlay styles on FF/Linux (due to performance issues with opacity)
+       applyPlatformOpacityRules: true,
+
+       // callback method invoked when fadeIn has completed and blocking message is visible
+       onBlock: null,
+
+       // callback method invoked when unblocking has completed; the callback is
+       // passed the element that has been unblocked (which is the window object for page
+       // blocks) and the options that were passed to the unblock call:
+       //       onUnblock(element, options)
+       onUnblock: null,
+
+       // don't ask; if you really must know: http://groups.google.com/group/jquery-en/browse_thread/thread/36640a8730503595/2f6a79a77a78e493#2f6a79a77a78e493
+       quirksmodeOffsetHack: 4
+};
+
+// private data and functions follow...
+
+var pageBlock = null;
+var pageBlockEls = [];
+
+function install(el, opts) {
+       var full = (el == window);
+       var msg = opts && opts.message !== undefined ? opts.message : undefined;
+       opts = $.extend({}, $.blockUI.defaults, opts || {});
+       opts.overlayCSS = $.extend({}, $.blockUI.defaults.overlayCSS, opts.overlayCSS || {});
+       var css = $.extend({}, $.blockUI.defaults.css, opts.css || {});
+       var themedCSS = $.extend({}, $.blockUI.defaults.themedCSS, opts.themedCSS || {});
+       msg = msg === undefined ? opts.message : msg;
+
+       // remove the current block (if there is one)
+       if (full && pageBlock)
+               remove(window, {fadeOut:0});
+
+       // if an existing element is being used as the blocking content then we capture
+       // its current place in the DOM (and current display style) so we can restore
+       // it when we unblock
+       if (msg && typeof msg != 'string' && (msg.parentNode || msg.jquery)) {
+               var node = msg.jquery ? msg[0] : msg;
+               var data = {};
+               $(el).data('blockUI.history', data);
+               data.el = node;
+               data.parent = node.parentNode;
+               data.display = node.style.display;
+               data.position = node.style.position;
+               if (data.parent)
+                       data.parent.removeChild(node);
+       }
+
+       var z = opts.baseZ;
+
+       // blockUI uses 3 layers for blocking, for simplicity they are all used on every platform;
+       // layer1 is the iframe layer which is used to supress bleed through of underlying content
+       // layer2 is the overlay layer which has opacity and a wait cursor (by default)
+       // layer3 is the message content that is displayed while blocking
+
+       var lyr1 = ($.browser.msie || opts.forceIframe)
+               ? $('<iframe class="blockUI" style="z-index:'+ (z++) +';display:none;border:none;margin:0;padding:0;position:absolute;width:100%;height:100%;top:0;left:0" src="'+opts.iframeSrc+'"></iframe>')
+               : $('<div class="blockUI" style="display:none"></div>');
+       var lyr2 = $('<div class="blockUI blockOverlay" style="z-index:'+ (z++) +';display:none;border:none;margin:0;padding:0;width:100%;height:100%;top:0;left:0"></div>');
+
+       var lyr3;
+       if (opts.theme && full) {
+               var s = '<div class="blockUI blockMsg blockPage ui-dialog ui-widget ui-corner-all" style="z-index:'+z+';display:none;position:fixed">' +
+                                       '<div class="ui-widget-header ui-dialog-titlebar blockTitle">'+(opts.title || '&nbsp;')+'</div>' +
+                                       '<div class="ui-widget-content ui-dialog-content"></div>' +
+                               '</div>';
+               lyr3 = $(s);
+       }
+       else {
+               lyr3 = full ? $('<div class="blockUI blockMsg blockPage" style="z-index:'+z+';display:none;position:fixed"></div>')
+                                       : $('<div class="blockUI blockMsg blockElement" style="z-index:'+z+';display:none;position:absolute"></div>');
+       }
+
+       // if we have a message, style it
+       if (msg) {
+               if (opts.theme) {
+                       lyr3.css(themedCSS);
+                       lyr3.addClass('ui-widget-content');
+               }
+               else
+                       lyr3.css(css);
+       }
+
+       // style the overlay
+       if (!opts.applyPlatformOpacityRules || !($.browser.mozilla && /Linux/.test(navigator.platform)))
+               lyr2.css(opts.overlayCSS);
+       lyr2.css('position', full ? 'fixed' : 'absolute');
+
+       // make iframe layer transparent in IE
+       if ($.browser.msie || opts.forceIframe)
+               lyr1.css('opacity',0.0);
+
+       //$([lyr1[0],lyr2[0],lyr3[0]]).appendTo(full ? 'body' : el);
+       var layers = [lyr1,lyr2,lyr3], $par = full ? $('body') : $(el);
+       $.each(layers, function() {
+               this.appendTo($par);
+       });
+
+       if (opts.theme && opts.draggable && $.fn.draggable) {
+               lyr3.draggable({
+                       handle: '.ui-dialog-titlebar',
+                       cancel: 'li'
+               });
+       }
+
+       // ie7 must use absolute positioning in quirks mode and to account for activex issues (when scrolling)
+       var expr = setExpr && (!$.boxModel || $('object,embed', full ? null : el).length > 0);
+       if (ie6 || expr) {
+               // give body 100% height
+               if (full && opts.allowBodyStretch && $.boxModel)
+                       $('html,body').css('height','100%');
+
+               // fix ie6 issue when blocked element has a border width
+               if ((ie6 || !$.boxModel) && !full) {
+                       var t = sz(el,'borderTopWidth'), l = sz(el,'borderLeftWidth');
+                       var fixT = t ? '(0 - '+t+')' : 0;
+                       var fixL = l ? '(0 - '+l+')' : 0;
+               }
+
+               // simulate fixed position
+               $.each([lyr1,lyr2,lyr3], function(i,o) {
+                       var s = o[0].style;
+                       s.position = 'absolute';
+                       if (i < 2) {
+                               full ? s.setExpression('height','Math.max(document.body.scrollHeight, document.body.offsetHeight) - (jQuery.boxModel?0:'+opts.quirksmodeOffsetHack+') + "px"')
+                                        : s.setExpression('height','this.parentNode.offsetHeight + "px"');
+                               full ? s.setExpression('width','jQuery.boxModel && document.documentElement.clientWidth || document.body.clientWidth + "px"')
+                                        : s.setExpression('width','this.parentNode.offsetWidth + "px"');
+                               if (fixL) s.setExpression('left', fixL);
+                               if (fixT) s.setExpression('top', fixT);
+                       }
+                       else if (opts.centerY) {
+                               if (full) s.setExpression('top','(document.documentElement.clientHeight || document.body.clientHeight) / 2 - (this.offsetHeight / 2) + (blah = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + "px"');
+                               s.marginTop = 0;
+                       }
+                       else if (!opts.centerY && full) {
+                               var top = (opts.css && opts.css.top) ? parseInt(opts.css.top) : 0;
+                               var expression = '((document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + '+top+') + "px"';
+                               s.setExpression('top',expression);
+                       }
+               });
+       }
+
+       // show the message
+       if (msg) {
+               if (opts.theme)
+                       lyr3.find('.ui-widget-content').append(msg);
+               else
+                       lyr3.append(msg);
+               if (msg.jquery || msg.nodeType)
+                       $(msg).show();
+       }
+
+       if (($.browser.msie || opts.forceIframe) && opts.showOverlay)
+               lyr1.show(); // opacity is zero
+       if (opts.fadeIn) {
+               var cb = opts.onBlock ? opts.onBlock : noOp;
+               var cb1 = (opts.showOverlay && !msg) ? cb : noOp;
+               var cb2 = msg ? cb : noOp;
+               if (opts.showOverlay)
+                       lyr2._fadeIn(opts.fadeIn, cb1);
+               if (msg)
+                       lyr3._fadeIn(opts.fadeIn, cb2);
+       }
+       else {
+               if (opts.showOverlay)
+                       lyr2.show();
+               if (msg)
+                       lyr3.show();
+               if (opts.onBlock)
+                       opts.onBlock();
+       }
+
+       // bind key and mouse events
+       bind(1, el, opts);
+
+       if (full) {
+               pageBlock = lyr3[0];
+               pageBlockEls = $(':input:enabled:visible',pageBlock);
+               if (opts.focusInput)
+                       setTimeout(focus, 20);
+       }
+       else
+               center(lyr3[0], opts.centerX, opts.centerY);
+
+       if (opts.timeout) {
+               // auto-unblock
+               var to = setTimeout(function() {
+                       full ? $.unblockUI(opts) : $(el).unblock(opts);
+               }, opts.timeout);
+               $(el).data('blockUI.timeout', to);
+       }
+};
+
+// remove the block
+function remove(el, opts) {
+       var full = (el == window);
+       var $el = $(el);
+       var data = $el.data('blockUI.history');
+       var to = $el.data('blockUI.timeout');
+       if (to) {
+               clearTimeout(to);
+               $el.removeData('blockUI.timeout');
+       }
+       opts = $.extend({}, $.blockUI.defaults, opts || {});
+       bind(0, el, opts); // unbind events
+
+       var els;
+       if (full) // crazy selector to handle odd field errors in ie6/7
+               els = $('body').children().filter('.blockUI').add('body > .blockUI');
+       else
+               els = $('.blockUI', el);
+
+       if (full)
+               pageBlock = pageBlockEls = null;
+
+       if (opts.fadeOut) {
+               els.fadeOut(opts.fadeOut);
+               setTimeout(function() { reset(els,data,opts,el); }, opts.fadeOut);
+       }
+       else
+               reset(els, data, opts, el);
+};
+
+// move blocking element back into the DOM where it started
+function reset(els,data,opts,el) {
+       els.each(function(i,o) {
+               // remove via DOM calls so we don't lose event handlers
+               if (this.parentNode)
+                       this.parentNode.removeChild(this);
+       });
+
+       if (data && data.el) {
+               data.el.style.display = data.display;
+               data.el.style.position = data.position;
+               if (data.parent)
+                       data.parent.appendChild(data.el);
+               $(el).removeData('blockUI.history');
+       }
+
+       if (typeof opts.onUnblock == 'function')
+               opts.onUnblock(el,opts);
+};
+
+// bind/unbind the handler
+function bind(b, el, opts) {
+       var full = el == window, $el = $(el);
+
+       // don't bother unbinding if there is nothing to unbind
+       if (!b && (full && !pageBlock || !full && !$el.data('blockUI.isBlocked')))
+               return;
+       if (!full)
+               $el.data('blockUI.isBlocked', b);
+
+       // don't bind events when overlay is not in use or if bindEvents is false
+       if (!opts.bindEvents || (b && !opts.showOverlay))
+               return;
+
+       // bind anchors and inputs for mouse and key events
+       var events = 'mousedown mouseup keydown keypress';
+       b ? $(document).bind(events, opts, handler) : $(document).unbind(events, handler);
+
+// former impl...
+//        var $e = $('a,:input');
+//        b ? $e.bind(events, opts, handler) : $e.unbind(events, handler);
+};
+
+// event handler to suppress keyboard/mouse events when blocking
+function handler(e) {
+       // allow tab navigation (conditionally)
+       if (e.keyCode && e.keyCode == 9) {
+               if (pageBlock && e.data.constrainTabKey) {
+                       var els = pageBlockEls;
+                       var fwd = !e.shiftKey && e.target == els[els.length-1];
+                       var back = e.shiftKey && e.target == els[0];
+                       if (fwd || back) {
+                               setTimeout(function(){focus(back)},10);
+                               return false;
+                       }
+               }
+       }
+       // allow events within the message content
+       if ($(e.target).parents('div.blockMsg').length > 0)
+               return true;
+
+       // allow events for content that is not being blocked
+       return $(e.target).parents().children().filter('div.blockUI').length == 0;
+};
+
+function focus(back) {
+       if (!pageBlockEls)
+               return;
+       var e = pageBlockEls[back===true ? pageBlockEls.length-1 : 0];
+       if (e)
+               e.focus();
+};
+
+function center(el, x, y) {
+       var p = el.parentNode, s = el.style;
+       var l = ((p.offsetWidth - el.offsetWidth)/2) - sz(p,'borderLeftWidth');
+       var t = ((p.offsetHeight - el.offsetHeight)/2) - sz(p,'borderTopWidth');
+       if (x) s.left = l > 0 ? (l+'px') : '0';
+       if (y) s.top  = t > 0 ? (t+'px') : '0';
+};
+
+function sz(el, p) {
+       return parseInt($.css(el,p))||0;
+};
+
+})(jQuery);
\ No newline at end of file
diff --git a/redakcja/static/js/lib/jquery/jquery.elastic.js b/redakcja/static/js/lib/jquery/jquery.elastic.js
new file mode 100644 (file)
index 0000000..24e16f4
--- /dev/null
@@ -0,0 +1,6 @@
+(function(jQuery){jQuery.fn.extend({elastic:function(){var mimics=['paddingTop','paddingRight','paddingBottom','paddingLeft','fontSize','lineHeight','fontFamily','width','fontWeight'];return this.each(function(){if(this.type!='textarea'){return false;}
+var $textarea=jQuery(this),$twin=jQuery('<div />').css({'position':'absolute','display':'none','word-wrap':'break-word'}),lineHeight=parseInt($textarea.css('line-height'),10)||parseInt($textarea.css('font-size'),'10'),minheight=parseInt($textarea.css('height'),10)||lineHeight*3,maxheight=parseInt($textarea.css('max-height'),10)||Number.MAX_VALUE,goalheight=0,i=0;if(maxheight<0){maxheight=Number.MAX_VALUE;}
+$twin.appendTo($textarea.parent());var i=mimics.length;while(i--){$twin.css(mimics[i].toString(),$textarea.css(mimics[i].toString()));}
+function setHeightAndOverflow(height,overflow){curratedHeight=Math.floor(parseInt(height,10));if($textarea.height()!=curratedHeight){$textarea.css({'height':curratedHeight+'px','overflow':overflow});}}
+function update(){var textareaContent=$textarea.val().replace(/&/g,'&amp;').replace(/  /g,'&nbsp;').replace(/<|>/g,'&gt;').replace(/\n/g,'<br />');var twinContent=$twin.html();if(textareaContent+'&nbsp;'!=twinContent){$twin.html(textareaContent+'&nbsp;');if(Math.abs($twin.height()+lineHeight-$textarea.height())>3){var goalheight=$twin.height()+lineHeight;if(goalheight>=maxheight){setHeightAndOverflow(maxheight,'auto');}else if(goalheight<=minheight){setHeightAndOverflow(minheight,'hidden');}else{setHeightAndOverflow(goalheight,'hidden');}}}}
+$textarea.css({'overflow':'hidden'});$textarea.keyup(function(){update();});$textarea.live('input paste',function(e){setTimeout(update,250);});update();});}});})(jQuery);
\ No newline at end of file
index 61a3949..de1d8e5 100644 (file)
                if($tab.length != 1)
                        $tab = $(DEFAULT_PERSPECTIVE);
 
-               var $old = $('#tabs li').filter('.active');
+               var $old = $tab.closest('.tabs').find('.active');
 
                $old.each(function(){
                        $(this).removeClass('active');
index 916f326..aa9258d 100644 (file)
                        var self = this;
 
                        self.$elem.block({
-                               message: "Zapisywanie...",
+                               message: "Zapisywanie... <br/><button id='save-hide'>ukryj</button>",
                                fadeIn: 0,
                        });
+            $.wiki.blocking = self.$elem;
 
                        try {
 
index a441402..58a12e1 100644 (file)
@@ -7,10 +7,6 @@ if (!window.console) {
 
 var DEFAULT_PERSPECTIVE = "#SummaryPerspective";
 
-THEMES = [
-       'Alkohol', 'Ambicja', 'Anioł', 'Antysemityzm', 'Arkadia', 'Artysta', 'Bezdomność', 'Bezpieczeństwo', 'Bieda', 'Bijatyka', 'Błazen', 'Błądzenie', 'Błoto', 'Bogactwo', 'Bóg', 'Brat', 'Bunt', 'Buntownik', 'Burza', 'Car', 'Carpe diem', 'Ciemność', 'Cień', 'Cisza', 'Chciwość', 'Chleb', 'Chłop', 'Choroba', 'Chrystus', 'Chrzest', 'Ciało', 'Cierpienie', 'Cmentarz', 'Cnota', 'Córka', 'Cud', 'Czarownika', 'Czary', 'Czas', 'Czyn', 'Czyściec', 'Dama', 'Danse macabre', 'Deszcz', 'Diabeł', 'Dobro', 'Dom', 'Dorosłość', 'Drzewo', 'Duch', 'Dusza', 'Duma', 'Dworek', 'Dworzanin', 'Dwór', 'Dzieciństwo', 'Dziecko', 'Dziedzictwo', 'Dziewictwo', 'Dźwięk', 'Egzorcyzm', 'Elita', 'Emigrant', 'Fałsz', 'Filozof', 'Fircyk', 'Flirt', 'Głupiec', 'Głupota', 'Głód', 'Gospodarz', 'Gospodyni', 'Gość', 'Gotycyzm', 'Góra', 'Gra', 'Grób', 'Grzech', 'Grzeczność', 'Gwiazda', 'Handel', 'Hańba', 'Historia', 'Honor', 'Idealista', 'Imię', 'Interes', 'Jabłka', 'Jedzenie', 'Jesień', 'Kaleka', 'Kara', 'Karczma', 'Klęska', 'Kłamstwo', 'Kłótnia', 'Kobieta', 'Kobieta demoniczna', 'Kobieta "upadła"', 'Kochanek', 'Kochanek romantyczny', 'Kolonializm', 'Kondycja ludzka', 'Konflikt', 'Konflikt wewnętrzny', 'Koniec świata', 'Koń', 'Korzyść', 'Kot', 'Kradzież', 'Krew', 'Król', 'Krzywda', 'Ksiądz', 'Książka', 'Księżyc', 'Kuchnia', 'Kuszenie', 'Kwiaty', 'Labirynt', 'Las', 'Lato', 'Lekarz', 'Lenistwo', 'List', 'Liberat', 'Los', 'Lud', 'Lustro', 'Łzy', 'Małżeństwo', 'Marzenie', 'Maska', 'Maszyna', 'Matka', 'Matka Boska', 'Mądrość', 'Mąż', 'Melancholia', 'Mędrzec', 'Mężczyzna', 'Miasto', 'Mieszczanin', 'Miłosierdzie', 'Miłość', 'Miłość niespełniona', 'Miłość platoniczna', 'Miłość romantyczna', 'Miłość silniejsza niż śmierć', 'Miłość spełniona', 'Miłość tragiczna', 'Mizoginia', 'Młodość', 'Moda', 'Modlitwa', 'Morderstwo', 'Morze', 'Motyl', 'Mucha', 'Muzyka', 'Narodziny', 'Naród', 'Natura', 'Nauczyciel', 'Nauczycielka', 'Nauka', 'Niebezpieczeństwo', 'Niedziela', 'Niemiec', 'Nienawiść', 'Nieśmiertelność', 'Niewola', 'Noc', 'Nuda', 'Obcy', 'Obłok', 'Obowiązek', 'Obraz świata', 'Obrzędy', 'Obyczaje', 'Obywatel', 'Odrodzenie przez grób', 'Odwaga', 'Ofiara', 'Ogień', 'Ogród', 'Ojciec', 'Ojczyzna', 'Oko', 'Okręt', 'Okrucieństwo', 'Omen', 'Opieka', 'Organizm', 'Otchłań', 'Pająk', 'Pamięć', 'Pan', 'Panna młoda', 'Państwo', 'Patriota', 'Piekło', 'Pielgrzym', 'Pieniądz', 'Pies', 'Piętno', 'Pijaństwo', 'Piwnica', 'Plotka', 'Pobożność', 'Pocałunek', 'Pochlebstwo', 'Poeta', 'Poetka', 'Poezja', 'Podróż', 'Podstęp', 'Pogrzeb', 'Pojedynek', 'Pokora', 'Pokusa', 'Polak', 'Polityka', 'Polowanie', 'Polska', 'Portret', 'Porwanie', 'Poświęcenie', 'Potwór', 'Powstanie', 'Powstaniec', 'Pozory', 'Pozycja społeczna', 'Pożar', 'Pożądanie', 'Praca', 'Praca u podstaw', 'Praca organiczna', 'Prawda', 'Prawnik', 'Prometeusz', 'Proroctwo', 'Prorok', 'Próżność', 'Przebranie', 'Przeczucie', 'Przedmurze chrześcijaństwa', 'Przekleństwo', 'Przekupstwo', 'Przemiana', 'Przemijanie', 'Przemoc', 'Przestrzeń', 'Przyjaźń', 'Przyroda nieożywiona', 'Przysięga', 'Przywódca', 'Ptak', 'Pustynia', 'Pycha', 'Raj', 'Realista', 'Religia', 'Rewolucja', 'Robak', 'Robotnik', 'Rodzina', 'Rosja', 'Rosjanin', 'Rośliny', 'Rozczarowanie', 'Rozpacz', 'Rozstanie', 'Rozum', 'Ruiny', 'Rycerz', 'Rzeka', 'Salon', 'Samobójstwo', 'Samolubstwo', 'Samotnik', 'Samotność', 'Sarmata', 'Sąsiad', 'Sąd', 'Sąd Ostateczny', 'Sen', 'Serce', 'Sędzia', 'Sielanka', 'Sierota', 'Siła', 'Siostra', 'Sława', 'Słońce', 'Słowo', 'Sługa', 'Służalczość', 'Skąpiec', 'Sobowtór', 'Społecznik', 'Spowiedź', 'Sprawiedliwość', 'Starość', 'Strach', 'Strój', 'Stworzenie', 'Sumienie', 'Swaty', 'Syberia', 'Syn', 'Syn marnotrawny', 'Syzyf', 'Szaleniec', 'Szaleństwo', 'Szantaż', 'Szatan', 'Szczęście', 'Szkoła', 'Szlachcic', 'Szpieg', 'Sztuka', 'Ślub', 'Śmiech', 'Śmierć', 'Śmierć bohaterska', 'Śpiew', 'Światło', 'Świętoszek', 'Święty', 'Świt', 'Tajemnica', 'Taniec', 'Tchórzostwo', 'Teatr', 'Testament', 'Tęsknota', 'Theatrum mundi', 'Tłum', 'Trucizna', 'Trup', 'Twórczość', 'Uczeń', 'Uczta', 'Uroda', 'Umiarkowanie', 'Upadek', 'Upiór', 'Urzędnik', 'Vanitas', 'Walka', 'Walka klas', 'Wampir', 'Warszawa', 'Wąż', 'Wdowa', 'Wdowiec', 'Wesele', 'Wiatr', 'Wierność', 'Wierzenia', 'Wieś', 'Wiedza', 'Wieża Babel', 'Więzienie', 'Więzień', 'Wina', 'Wino', 'Wiosna', 'Wizja', 'Władza', 'Własność', 'Woda', 'Wojna', 'Wojna pokoleń', 'Wolność', 'Wróg', 'Wspomnienia', 'Współpraca', 'Wygnanie', 'Wyrzuty sumienia', 'Wyspa', 'Wzrok', 'Zabawa', 'Zabobony', 'Zamek', 'Zaręczyny', 'Zaświaty', 'Zazdrość', 'Zbawienie', 'Zbrodnia', 'Zbrodniarz', 'Zdrada', 'Zdrowie', 'Zemsta', 'Zesłaniec', 'Ziarno', 'Ziemia', 'Zima', 'Zło', 'Złodziej', 'Złoty wiek', 'Zmartwychwstanie', 'Zwątpienie', 'Zwierzęta', 'Zwycięstwo', 'Żałoba', 'Żebrak', 'Żołnierz', 'Żona', 'Życie jako wędrówka', 'Życie snem', 'Żyd', 'Żywioły', 'Oświadczyny'
-];
-
 $(function()
 {
        var tabs = $('ol#tabs li');
@@ -40,7 +36,7 @@ $(function()
                /*
                 * TABS
                 */
-        $('#tabs li').live('click', function(event, callback) {
+        $('.tabs li').live('click', function(event, callback) {
                        $.wiki.switchToTab(this);
         });
 
@@ -66,19 +62,19 @@ $(function()
         $('.vsplitbar').toggle(
                        function() {
                                $.wiki.state.perspectives.ScanGalleryPerspective.show = true;
-                               $('#side-gallery').show();
-                               $('.vsplitbar').css('right', 480).addClass('.active');
+                               $('#sidebar').show();
+                               $('.vsplitbar').css('right', 480).addClass('active');
                                $('#editor .editor').css('right', 510);
                                $(window).resize();
-                               gallery.onEnter();
+                               $.wiki.perspectiveForTab('#tabs-right .active').onEnter();
                        },
                        function() {
                                $.wiki.state.perspectives.ScanGalleryPerspective.show = false;
-                               $('#side-gallery').hide();
+                               $('#sidebar').hide();
                                $('.vsplitbar').css('right', 0).removeClass('active');
                                $('#editor .editor').css('right', 30);
                                $(window).resize();
-                               gallery.onExit();
+                               $.wiki.perspectiveForTab('#tabs-right .active').onExit();
                        }
                );
 
@@ -141,6 +137,6 @@ $(function()
        /*
         * Initialize all perspectives
         */
-       initAll( $.makeArray($('ol#tabs li')), initialize);
+       initAll( $.makeArray($('.tabs li')), initialize);
        console.log(location.hash);
 });
diff --git a/redakcja/static/js/wiki/toolbar.js b/redakcja/static/js/wiki/toolbar.js
new file mode 100644 (file)
index 0000000..3eafdae
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Toolbar plugin.
+ */
+(function($) {
+
+    $.fn.toolbarize = function(options) {
+        var $toolbar = $(this);
+        var $container = $('.button_group_container', $toolbar);
+
+        $('.button_group button', $toolbar).click(function(event){
+            event.preventDefault();
+
+            var params = eval("(" + $(this).attr('data-ui-action-params') + ")");
+
+            scriptletCenter.callInteractive({
+                action: $(this).attr('data-ui-action'),
+                context: options.actionContext,
+                extra: params
+            });
+        });
+
+        $toolbar.children().filter('select').change(function(event){
+            var slug = $(this).val();
+            $container.scrollLeft(0);
+            $('*[data-group]').hide().filter('[data-group=' + slug + ']').show();
+        }).change();
+
+        $('button.next', $toolbar).click(function() {
+            var $current_group = $('.button_group:visible', $toolbar);
+            var scroll = $container.scrollLeft();
+
+            var $hidden = $("li", $current_group).filter(function() {
+                return ($(this).position().left + $(this).outerWidth()) > $container.width();
+            }).first();
+
+            if($hidden.length > 0) {
+                scroll = $hidden.position().left + scroll + $hidden.outerWidth() - $container.width() + 1;
+                $container.scrollLeft(scroll);
+            };
+        });
+
+        $('button.prev', $toolbar).click(function() {
+            var $current_group = $('.button_group:visible', $toolbar);
+            var scroll = $container.scrollLeft();
+
+            /* first not visible element is: */
+            var $hidden = $("li", $current_group).filter(function() {
+                return $(this).position().left < 0;
+            }).last();
+
+            if( $hidden.length > 0)
+            {
+                scroll = scroll + $hidden.position().left;
+                $container.scrollLeft(scroll);
+            };
+        });
+
+    };
+
+})(jQuery);
\ No newline at end of file
index a0a2e69..0597140 100644 (file)
                                                return true;
                                        });
 
-                                       $('#source-editor .toolbar button').click(function(event){
-                                               event.preventDefault();
-                                               var params = eval("(" + $(this).attr('data-ui-action-params') + ")");
-                                               scriptletCenter.callInteractive({
-                                                       action: $(this).attr('data-ui-action'),
-                                                       context: self.codemirror,
-                                                       extra: params
-                                               });
+                                       $('#source-editor .toolbar').toolbarize({
+                                           actionContext: self.codemirror
                                        });
 
-                                       $('.toolbar select').change(function(event){
-                                               var slug = $(this).val();
-
-                                               $('.toolbar-buttons-container').hide().filter('[data-group=' + slug + ']').show();
-                                               $(window).resize();
-                                       });
-
-                                       $('.toolbar-buttons-container').hide();
-                                       $('.toolbar select').change();
-
                                        console.log("Initialized CodeMirror");
 
                                        // textarea is no longer needed
                console.log('Exiting', this.doc);
                this.doc.setText(this.codemirror.getCode());
 
+        if ($('.vsplitbar').hasClass('active') && $('#SearchPerspective').hasClass('active')) {
+            $.wiki.switchToTab('#ScanGalleryPerspective');
+        }
+
                if(success) success();
        }
 
index 2ae1a8d..34618c4 100644 (file)
@@ -43,8 +43,8 @@
         return true;
     }
 
-    /* Convert HTML frament to plaintext */
-    var ANNOT_ALLOWED = ['wyroznienie', 'slowo_obce', 'osoba'];
+    /* Convert HTML fragment to plaintext */
+    var ANNOT_FORBIDDEN = ['pt', 'pa', 'pr', 'pe', 'begin', 'end', 'theme'];
 
     function html2plainText(fragment){
         var text = "";
         $(fragment.childNodes).each(function(){
             if (this.nodeType == 3) // textNode
                 text += this.nodeValue;
-            else
+            else {
                 if (this.nodeType == 1 &&
-                $.inArray($(this).attr('x-node'), ANNOT_ALLOWED) != -1) {
+                        $.inArray($(this).attr('x-node'), ANNOT_FORBIDDEN) == -1) {
                     text += html2plainText(this);
                 }
+            };
         });
 
         return text;
@@ -87,7 +88,7 @@
             return false;
         }
 
-        // BUG #273 - selected text can contain themes, which should be omited from
+        // BUG #273 - selected text can contain themes, which should be omitted from
         // defining term
         var text = html2plainText(range.cloneContents());
 
@@ -96,7 +97,7 @@
         range.insertNode(tag[0]);
 
         xml2html({
-            xml: '<pr><slowo_obce>' + text + '</slowo_obce> --- </pr>',
+            xml: '<pe><slowo_obce>' + text + '</slowo_obce> --- </pe>',
             success: function(text){
                 var t = $(text);
                 tag.replaceWith(t);
         }).appendTo($box[0].offsetParent || $box.parent()).show();
 
         if ($origin.is('.motyw')) {
-            $('textarea', $overlay).autocomplete(THEMES, {
+            $('textarea', $overlay).autocomplete('/themes', {
                 autoFill: true,
                 multiple: true,
-                selectFirst: true
+                selectFirst: true,
+                highlight: false
             });
         }
 
-        if ($origin.is('.motyw')) {
+        if ($origin.is('.motyw')){
             $('.delete-button', $overlay).click(function(){
                 if (window.confirm("Czy jesteś pewien, że chcesz usunąć ten motyw ?")) {
                     $('[theme-class=' + $origin.attr('theme-class') + ']').remove();
                     $(document).unbind('click.blur-overlay');
                     return false;
                 };
-                            });
+            });
+        }
+        else if($box.is('*[x-annotation-box]')) {
+            $('.delete-button', $overlay).click(function(){
+                if (window.confirm("Czy jesteś pewien, że chcesz usunąć ten przypis?")) {
+                    $origin.remove();
+                    $overlay.remove();
+                    $(document).unbind('click.blur-overlay');
+                    return false;
+                };
+            });
         }
         else {
             $('.delete-button', $overlay).hide();
index aa39e15..1be30bf 100644 (file)
@@ -65,7 +65,7 @@
                 event.preventDefault();
                 self.setPage($(this).val());
             });
-
+                    
             $('.previous-page', this.$element).click(function(){
                 self.setPage(parseInt(self.$numberInput.val(),10) - 1);
             });
 
     ScanGalleryPerspective.prototype.setPage = function(newPage){
         newPage = normalizeNumber(newPage, this.doc.galleryImages.length);
+        $('#imagesCount').val(this.doc.galleryImages.length);
         this.$numberInput.val(newPage);
                this.config().page = newPage;
         $('.gallery-image img', this.$element).attr('src', this.doc.galleryImages[newPage - 1]);
 
         $.wiki.Perspective.prototype.onEnter.call(this);
 
+        $('.vsplitbar').not('.active').trigger('click');
+
         this.doc.refreshGallery({
             success: function(doc, data){
                 self.$image.show();
 
     $.wiki.ScanGalleryPerspective = ScanGalleryPerspective;
 
-})(jQuery);
\ No newline at end of file
+})(jQuery);
index b4a9dd8..d35a8da 100644 (file)
                                self.showTagForm();
                        });
 
+               $('#doc-revert-button').click(function() {
+                   self.revertDocumentToVersion();
+               });
+
                        $('#open-preview-button').click(function(event) {
                                var selected = $('#changes-list .entry.selected');
 
 
                $('#changes-list .entry').live('click', function(){
                var $this = $(this);
-               if ($this.hasClass('selected'))
-                       return $this.removeClass('selected');
 
-               if ($("#changes-list .entry.selected").length < 2)
-                       return $this.addClass('selected');
+               var selected_count = $("#changes-list .entry.selected").length;
+
+               if ($this.hasClass('selected')) {
+                       $this.removeClass('selected');
+                       selected_count -= 1;
+               }
+               else {
+                   if (selected_count  < 2) {
+                       $this.addClass('selected');
+                       selected_count += 1;
+                   };
+               };
+
+               $('#history-view-editor .toolbar button').attr('disabled', 'disabled').
+                   filter('*[data-enabled-when~=' + selected_count + '], *[data-enabled-when~=*]').
+                   attr('disabled', null);
                });
 
            $('#changes-list span.tag').live('click', function(event){
                                                tag: function(value) {
                                                        return tags.filter("*[value='"+value+"']").text();
                                                }
+//                        description: function(value) {
+//                                                 return value.replace('\n', ');
+//                                             }
                                        }
                                });
             });
         });
     };
 
+    HistoryPerspective.prototype.revertDocumentToVersion = function(){
+        var selected = $('#changes-list .entry.selected');
+
+        if (selected.length != 1) {
+            window.alert("Musisz zaznaczyć dokładnie jedną wersję.");
+            return;
+        }
+
+        var version = parseInt($("*[data-stub-value='version']", selected[0]).text());
+        this.doc.revertToVersion({'revision': version});
+    };
+
     $.wiki.HistoryPerspective = HistoryPerspective;
 
 })(jQuery);
diff --git a/redakcja/static/js/wiki/view_search.js b/redakcja/static/js/wiki/view_search.js
new file mode 100644 (file)
index 0000000..34393dc
--- /dev/null
@@ -0,0 +1,113 @@
+(function($){
+
+    /*
+     * Perspective
+     */
+    function SearchPerspective(options){
+        var old_callback = options.callback || function() { };
+
+        this.noupdate_hash_onenter = true;
+
+        options.callback = function(){
+            var self = this;
+
+            this.editor = null;
+            this.$element = $("#side-search");
+            this.$searchInput = $('#search-input', this.$element);
+            this.$replaceInput = $('#replace-input', this.$element);
+            this.$searchButton = $('#search-button', this.$element);
+            this.$replaceButton = $('#replace-button', this.$element);
+
+            this.$replaceButton.attr("disabled","disabled");
+            this.options = Array();
+
+            // handlers
+            this.$searchInput.change(function(event){
+                self.searchCursor = null;
+            });
+            this.$replaceInput.change(function(event){
+                self.searchCursor = null;
+            });
+
+            $("#side-search input:checkbox").each(function() {
+                self.options[this.id] = this.checked;
+            }).change(function(){
+                self.options[this.id] = this.checked;
+                self.searchCursor = null;
+            });
+
+            this.$searchButton.click(function(){
+                if (!self.search())
+                    alert('Brak wyników.');
+            });
+
+            this.$replaceButton.click(function(){
+                self.replace();
+            });
+
+            old_callback.call(this);
+        };
+
+        $.wiki.Perspective.call(this, options);
+    };
+
+    SearchPerspective.prototype = new $.wiki.Perspective();
+
+    SearchPerspective.prototype.search = function(){
+        var self = this;
+        var query = self.$searchInput.val();
+
+        if (!self.editor)
+            self.editor = $.wiki.perspectiveForTab('#CodeMirrorPerspective').codemirror
+
+        if (!self.searchCursor) {
+            self.searchCursor = self.editor.getSearchCursor(
+                self.$searchInput.val(), 
+                self.options['search-from-cursor'], 
+                self.options['search-regexp'],
+                self.options['search-case-sensitive']
+            );
+        }
+        if (self.searchCursor.findNext()) {
+            self.searchCursor.select();
+            self.$replaceButton.removeAttr("disabled");
+            return true;
+        }
+        else {
+            self.searchCursor = null;
+            this.$replaceButton.attr("disabled","disabled");
+            return false;
+        }
+    };
+
+    SearchPerspective.prototype.replace = function(){
+        var self = this;
+        var query = self.$replaceInput.val();
+
+        if (!self.searchCursor) {
+            self.search();
+        }
+        else {}
+        self.searchCursor.select();
+        self.searchCursor.replace(query);
+        self.search();
+    };
+
+    SearchPerspective.prototype.onEnter = function(success, failure){
+        var self = this;
+
+        $.wiki.Perspective.prototype.onEnter.call(this);
+        self.$searchCursor = null;
+
+        $('.vsplitbar').not('.active').trigger('click');
+        if ($.wiki.activePerspective() != 'CodeMirrorPerspective')
+            $.wiki.switchToTab('#CodeMirrorPerspective');
+    };
+
+    SearchPerspective.prototype.onExit = function(success, failure) {
+
+    };
+
+    $.wiki.SearchPerspective = SearchPerspective;
+
+})(jQuery);
\ No newline at end of file
index 27ab97e..b6388f1 100644 (file)
@@ -7,8 +7,8 @@
                failure: noop
        };
        /*
-        * Return absolute reverse path of given named view.
-        * (at least he have it hard-coded in one place)
+        * Return absolute reverse path of given named view. (at least he have it
+        * hard-coded in one place)
         *
         * TODO: think of a way, not to hard-code it here ;)
         *
@@ -33,7 +33,7 @@
 
                if (vname == "ajax_document_gallery") {
 
-                       return base_path + "/gallery/" + arguments[1];
+                       return base_path + "/" + arguments[1] + "/gallery";
                }
 
                if (vname == "ajax_document_diff")
        /*
         * Fetch history of this document.
         *
-        * from - First revision to fetch (default = 0)
-        * upto - Last revision to fetch (default = tip)
+        * from - First revision to fetch (default = 0) upto - Last revision to
+        * fetch (default = tip)
         *
         */
        WikiDocument.prototype.fetchHistory = function(params) {
                        success: function(data) {
                                var changed = false;
 
+                $('#header').removeClass('saving');
+
                                if (data.text) {
                                        self.text = data.text;
                                        self.revision = data.revision;
                                params['success'](self, changed, ((changed && "Udało się zapisać :)") || "Twoja wersja i serwera jest identyczna"));
                        },
                        error: function(xhr) {
-                               try {
-                                       params['failure'](self, $.parseJSON(xhr.responseText));
-                               }
-                               catch (e) {
-                                       params['failure'](self, {
-                                               "__message": "<p>Nie udało się zapisać - błąd serwera.</p>"
-                                       });
-                               };
+                if ($('#header').hasClass('saving')) {
+                    $('#header').removeClass('saving');
+                    $.blockUI({
+                        message: "<p>Nie udało się zapisać zmian. <br/><button onclick='$.unblockUI()'>OK</button></p>"
+                    })
+                }
+                else {
+                    try {
+                        params['failure'](self, $.parseJSON(xhr.responseText));
+                    }
+                    catch (e) {
+                        params['failure'](self, {
+                            "__message": "<p>Nie udało się zapisać - błąd serwera.</p>"
+                        });
+                    };
+                }
 
                        }
                });
+
+        $('#save-hide').click(function(){
+            $('#header').addClass('saving');
+            $.unblockUI();
+            $.wiki.blocking.unblock();
+        });
        }; /* end of save() */
 
        WikiDocument.prototype.publish = function(params) {
index 532b452..2bab378 100644 (file)
@@ -33,32 +33,71 @@ function withStylesheets(code_block, onError)
        }
 }
 
+var canonThemes = null;
 
-function xml2html(options) {
-    withStylesheets(function() {
-        var xml = options.xml.replace(/\/\s+/g, '<br />');
-        var parser = new DOMParser();
-        var serializer = new XMLSerializer();
-        var doc = parser.parseFromString(xml, 'text/xml');
-        var error = $('parsererror', doc);
-
-        if (error.length == 0) {
-            doc = xml2htmlStylesheet.transformToFragment(doc, document);
-                       console.log(doc.firstChild);
-
-                       if(doc.firstChild === null) {
-                               options.error("Błąd w przetwarzaniu XML.");
-                               return;
-                       }
+// Wykonuje block z załadowanymi kanonicznymi motywami
+function withThemes(code_block, onError)
+{
+    if (!canonThemes) {
+        $.blockUI({message: 'Ładowanie motywów...'});
+        $.ajax({
+            url: '/themes',
+            dataType: 'text',
+            success: function(data) {
+                canonThemes = {};
+                themes = data.split('\n');
+                for (i in themes) {
+                    canonThemes[themes[i]] = 1;
+                }
+                $.unblockUI();
+                code_block();
+            },
+            error: onError
+        })
+    }
+    else {
+        code_block();
+    }
+}
 
-            error = $('parsererror', doc);
-        }
 
-        if (error.length > 0 && options.error) {
-            options.error(error.text());
-        } else {
-            options.success(doc.firstChild);
-        }
+
+function xml2html(options) {
+    withStylesheets(function() {
+        withThemes(function() {
+            var xml = options.xml.replace(/\/\s+/g, '<br />');
+            var parser = new DOMParser();
+            var serializer = new XMLSerializer();
+            var doc = parser.parseFromString(xml, 'text/xml');
+            var error = $('parsererror', doc);
+
+            if (error.length == 0) {
+                doc = xml2htmlStylesheet.transformToFragment(doc, document);
+                console.log(doc.firstChild);
+
+                if(doc.firstChild === null) {
+                    options.error("Błąd w przetwarzaniu XML.");
+                    return;
+                }
+
+                error = $('parsererror', doc);
+            }
+
+            if (error.length > 0 && options.error) {
+                options.error(error.text());
+            } else {
+                $('.theme-text-list', doc.firstChild).each(function(){
+                    var themes = $(this).html().split(',');
+                    for (i in themes) {
+                        themes[i] = $.trim(themes[i]);
+                        if (!(themes[i] in canonThemes))
+                            themes[i] = '<span x-pass-thru="true" class="noncanon">' + themes[i] + "</span>"
+                    }
+                    $(this).html(themes.join(', '));
+                });
+                options.success(doc.firstChild);
+            }
+        }, function() { options.error && options.error('Nie udało się załadować motywów'); });
     }, function() { options.error && options.error('Nie udało się załadować XSLT'); });
 }
 
index ac728d0..749fd2a 100644 (file)
@@ -1,14 +1,24 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+{% load i18n %}
 <html xmlns="http://www.w3.org/1999/xhtml">
     <head>
         <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
-        <title>{% block title %}Platforma Redakcyjna{% block subtitle %}{% endblock subtitle %}{% endblock title%}</title>
+        <title>{% block title %}{% trans "Platforma Redakcyjna" %}{% block subtitle %}{% endblock subtitle %}{% endblock title%}</title>
         {% block extrahead %}
         {% endblock %}
     </head>
     <body id="{% block bodyid %}base{% endblock %}">
+
+    <div id="loading-overlay" style="display: none;">
+       <div id="loading-message">
+               <img src="{{STATIC_URL}}img/spinner.gif" />
+               <p>{% trans "Loading" %}</p>
+       </div>
+       </div>
+
        <div id="body-wrap">
+               <!-- version: {{ APP_VERSION }} -->
         <div id="content">{% block maincontent %} {% endblock %}</div>
         </div>
        <!-- <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" type="text/javascript"></script> -->
index f8538fa..dd7f884 100644 (file)
@@ -4,6 +4,8 @@ from django.conf.urls.defaults import *
 from django.contrib import admin
 from django.conf import settings
 
+import wiki.urls
+
 admin.autodiscover()
 
 urlpatterns = patterns('',
@@ -26,4 +28,8 @@ urlpatterns = patterns('',
         {'document_root': settings.MEDIA_ROOT, 'show_indexes': True}),
     url(r'^%s(?P<path>.+)$' % settings.STATIC_URL[1:], 'django.views.static.serve',
         {'document_root': settings.STATIC_ROOT, 'show_indexes': True}),
+    (r'^documents/', include(wiki.urls)),
+    url(r'^themes$', 'wiki.views.themes', name="themes"),
+    url(r'^$', 'django.views.generic.simple.redirect_to', {'url': '/documents/'}),
+
 )
diff --git a/redmine/redmine_publications/README.rdoc b/redmine/redmine_publications/README.rdoc
deleted file mode 100644 (file)
index 2bcee99..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-= publications
-
-Description goes here
diff --git a/redmine/redmine_publications/app/controllers/publications_controller.rb b/redmine/redmine_publications/app/controllers/publications_controller.rb
deleted file mode 100644 (file)
index c7a1194..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-class PublicationsController < ApplicationController
-  unloadable
-
-  #  before_filter :authorize, :only => [:issues]
-
-  def index
-       @publications = Publication.all
-    respond_to do |format|
-      format.html
-      format.xml { render :xml => @publications }
-      format.json { render :json => @publications }
-    end
-  end
-
-  def refresh
-    regexp = Regexp.new(Setting.plugin_redmine_publications[:pattern])
-    repo = Repository.find(:first, :conditions => ['project_id = ?', Setting.plugin_redmine_publications[:project]] )
-
-    Rails.logger.info('[INFO] Importing changes from ' << repo.url)
-    Rails.logger.info('[INFO] Change list: ' << repo.changes.find(:all).inspect )
-
-    @repo_status = []
-    repo.changes.find(:all).each do |change|
-        Rails.logger.info('[INFO] Importing change ' << change.path)
-        match = change.path.match(regexp)
-        if match
-            Publication.find_or_create_by_name(:name => match[1],
-                :source_file => change.path, :repository_id => repo.id)
-              @repo_status += [{:path => change.path, :match => match[1], :matched => true}]
-        else
-              @repo_status += [{:path => change.path, :match => nil, :matched => false}]
-        end
-    end
-       
-    respond_to do |format|
-        format.html
-        format.xml { render :xml => @repo_status}
-        format.json { render :json => @repo_status }
-    end
-  end
-
-  def issues
-    @publication = Publication.find_by_name(params[:pub])
-
-    joins = "JOIN issue_publications ON (issues.id = issue_publications.issue_id)"
-    conditions = ['issue_publications.publication_id = ? ', @publication.id ]
-    @issues = Issue.all(:joins => joins, :conditions =>  conditions)
-
-    respond_to do |fmt| 
-      fmt.json { render :json => @issues, :callback => params[:callback] }
-    end
-  end
-
-  private
-
-  def find_project
-    @project = Project.find(params[:project_id])
-  end
-
-end
diff --git a/redmine/redmine_publications/app/helpers/publications_helper.rb b/redmine/redmine_publications/app/helpers/publications_helper.rb
deleted file mode 100644 (file)
index 50f110e..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-module PublicationsHelper
-end
diff --git a/redmine/redmine_publications/app/models/issue_publication.rb b/redmine/redmine_publications/app/models/issue_publication.rb
deleted file mode 100644 (file)
index ef7bf92..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-class IssuePublication < ActiveRecord::Base
-  belongs_to :publication
-  belongs_to :issue
-end    
diff --git a/redmine/redmine_publications/app/models/publication.rb b/redmine/redmine_publications/app/models/publication.rb
deleted file mode 100644 (file)
index 1544402..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-class Publication < ActiveRecord::Base
-  has_many :issues, :through => :issuepublications
-  belongs_to :repository
-end
diff --git a/redmine/redmine_publications/app/views/issues/_issue_form_pub.html.erb b/redmine/redmine_publications/app/views/issues/_issue_form_pub.html.erb
deleted file mode 100644 (file)
index ebb903c..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-<div>
-<p><label for="issue_source_files"><%= l(:field_publications) %>:</label>
-<input type='text' id='publications' name="publications" size="50"
-       value='<%= @issue.publication_names.join(', ') %>' />
-</div>
diff --git a/redmine/redmine_publications/app/views/issues/_issue_view_pub.erb b/redmine/redmine_publications/app/views/issues/_issue_view_pub.erb
deleted file mode 100644 (file)
index a22c78b..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-<tr>
-    <td><b><%= l(:field_publications) %>:</b></td>
-    <td>
-<% @issue.publication_names.each  do |pub| %>
-      <a href="<%= Setting.plugin_redmine_publications[:editorurl].sub(':pubid', pub) %>"><%= pub %></a><br />
-<% end %>
-    </td>
-</tr>
diff --git a/redmine/redmine_publications/app/views/publications/index.html.erb b/redmine/redmine_publications/app/views/publications/index.html.erb
deleted file mode 100644 (file)
index 3fa0299..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<h2>Publikacje</h2>
-<p><a href="/publications/refresh">Odśwież listę publikacji</a></p>
-<ol>
-<% @publications.each do |pub| %>
-       <li><a href="/publications/issues/<%= pub.name %>"><%= pub.name %></a></li>
-<% end %>
-</ol>
diff --git a/redmine/redmine_publications/app/views/publications/issues.html.erb b/redmine/redmine_publications/app/views/publications/issues.html.erb
deleted file mode 100644 (file)
index f36a875..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-<h2>Issues for publication: <%= @publication.name %></h2>
-<% @issues.each do |issue| %>
-<p><%= issue.subject %></p>
-<% end %>
diff --git a/redmine/redmine_publications/app/views/publications/refresh.erb b/redmine/redmine_publications/app/views/publications/refresh.erb
deleted file mode 100644 (file)
index 311ed33..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-<table>
-<tr><th>Ścieżka zasobu</th><th>Rozpoznano</th><th>ID zasobu</th></tr>
-<% @repo_status.each do |status| %>
-<tr>
-<td><%= status[:path] %></td>
-<td><%= (status[:matched] && 'Tak') || 'Nie' %></td>
-<td><%= status[:match] || '' %></td>
-</tr>
-<% end %>
-</table>
diff --git a/redmine/redmine_publications/app/views/settings/_publications_settings.html.erb b/redmine/redmine_publications/app/views/settings/_publications_settings.html.erb
deleted file mode 100644 (file)
index 255460e..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-<% @project = Project.find(:first, :conditions => ["id = ?", @settings[:project]]) %>
-<fieldset>
-<p>
-  <label for="settings[project]">Użyj w projektcie: </label>
-  <%= collection_select(:project, :id, Project.all, :id, :name, {}, {:name => "settings[project]"}) %>
-</p>
-
-<p>
-  <label for="settings[pattern]">Filtr publikacji: </label>
-  <%= text_field_tag 'settings[pattern]', @settings[:pattern] || '' %>
-</p>
-
-<p>
-  <label for="settings[editorurl]">Docelowy URL: </label>
-  <%= text_field_tag 'settings[editorurl]', @settings[:editorurl] || '' %>
-</p>
-
-</fieldset>
diff --git a/redmine/redmine_publications/db/migrate/001_create_publications.rb b/redmine/redmine_publications/db/migrate/001_create_publications.rb
deleted file mode 100644 (file)
index f9d93ef..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-class CreatePublications < ActiveRecord::Migration
-  def self.up
-    create_table :publications do |t|
-      t.column :source_file, :string, :null => false
-    end
-  end
-
-  def self.down
-    drop_table :publications
-  end
-end
diff --git a/redmine/redmine_publications/db/migrate/002_create_issue_publications.rb b/redmine/redmine_publications/db/migrate/002_create_issue_publications.rb
deleted file mode 100644 (file)
index 07b64bd..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-class CreateIssuePublications < ActiveRecord::Migration
-  def self.up
-    create_table :issue_publications do |t| 
-       t.column :publication_id, :integer, :null => false
-        t.column :issue_id, :integer, :null => false
-    end
-  end
-
-  def self.down
-    drop_table :issue_publications
-  end
-end
diff --git a/redmine/redmine_publications/db/migrate/003_publications_add_repo_id.rb b/redmine/redmine_publications/db/migrate/003_publications_add_repo_id.rb
deleted file mode 100644 (file)
index 8f232c9..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-class PublicationsAddRepoId < ActiveRecord::Migration
-  def self.up
-    add_column :publications, :repository_id, :integer, :null => false, :default => 0
-  end
-
-  def self.down 
-  end
-end
diff --git a/redmine/redmine_publications/db/migrate/004_publications_add_name.rb b/redmine/redmine_publications/db/migrate/004_publications_add_name.rb
deleted file mode 100644 (file)
index 6b5bac6..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-class PublicationsAddName < ActiveRecord::Migration
-  def self.up
-    add_column :publications, :name, :string
-  end
-
-  def self.down 
-  end
-end
diff --git a/redmine/redmine_publications/init.rb b/redmine/redmine_publications/init.rb
deleted file mode 100644 (file)
index 01afeab..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-require 'redmine'
-
-# Patches to the Redmine core.
-require 'dispatcher'
-
-Dispatcher.to_prepare :redmine_publications do
-  require_dependency 'issue'
-  
-  #Guards against including the module multiple time (like in tests)
-  # and registering multiple callbacks
-  unless Issue.included_modules.include? RedminePublications::IssuePatch
-    Issue.send(:include, RedminePublications::IssuePatch)
-  end
-
-  unless Change.included_modules.include? RedminePublications::ChangePatch
-    Change.send(:include, RedminePublications::ChangePatch)
-  end
-end
-
-require_dependency 'issue_publication_hook'
-
-Redmine::Plugin.register :redmine_publications do
-  name 'Publications managment plugin'
-  author 'Łukasz Rekucki'
-  description 'This plugn helps manage issues related to a publication.'
-  version '0.0.9'
-
-  # permission :view_issues_for_publication, :publications => :issues 
-
-  settings :partial => 'settings/publications_settings',
-      :default => { :project => '0', :pattern => '[^\$].xml', :editorurl => 'http://localhost/:pubid'}
-
-  menu :application_menu, :publications, { :controller => 'publications', :action => 'index' }, :caption => 'Publikacje'
-
-#  requires_redmine :version_or_higher => '0.8.0'       
-
-end
-
diff --git a/redmine/redmine_publications/lang/en.yml b/redmine/redmine_publications/lang/en.yml
deleted file mode 100644 (file)
index e338591..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-# English strings go here
-my_label: "My label"
diff --git a/redmine/redmine_publications/lib/issue_publication_hook.rb b/redmine/redmine_publications/lib/issue_publication_hook.rb
deleted file mode 100644 (file)
index 788a72f..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-# Provides a link to the document on the platform
-class IssuesPublicationHook < Redmine::Hook::ViewListener
-
-  def self.render_on(hook, options={})
-    define_method hook do |context|
-      if !options.include?(:if) || evaluate_if_option(options[:if], context)
-        context[:controller].send(:render_to_string, {:locals => context}.merge(options))
-      end
-    end
-  end
-
-  private
-
-  def evaluate_if_option(if_option, context)
-    case if_option
-    when Symbol
-      send(if_option, context)
-    when Method, Proc
-      if_option.call(context)
-    end
-  end
-
-  def is_pticket?(context)
-    context[:issue].project_id == Setting.plugin_redmine_publications[:project].to_i
-  end
-
-  public
-
-  render_on :view_issues_show_details_bottom, :partial => 'issue_view_pub', :if => :is_pticket?
-  render_on :view_issues_form_details_bottom, :partial => 'issue_form_pub', :if => :is_pticket?
-
-  #  names = context[:issue].publication_names {|name| "<span>" + name + "</span>"}
-  #  result << names.join(', ')
-
-  def controller_issues_edit_before_save(context)
-    if is_pticket?context
-      old_value = context[:issue].publication_names
-      new_value = context[:params][:publications].split(',').map { |n| n.strip }
-      context[:journal].details << JournalDetail.new(
-        :property => 'attr', :prop_key => "publications",
-        :old_value => old_value.join(', '),
-        :value => new_value.join(', ') ) unless new_value==old_value
-      context[:issue].publication_names = new_value
-    end
-  end
-
-
-  def controller_issues_new_after_save(context)
-    if is_pticket?context
-      value = context[:params][:publications].split(',').map { |n| n.strip }
-      context[:issue].publication_names = value
-      context[:issue].save
-    end
-  end
-end
diff --git a/redmine/redmine_publications/lib/redmine_publications/change_patch.rb b/redmine/redmine_publications/lib/redmine_publications/change_patch.rb
deleted file mode 100644 (file)
index b8e5c4b..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-module RedminePublications
-  # Patches Redmine's Issues dynamically. Adds a +after_save+ filter.
-
-  module ChangePatch
-    def self.included(base) # :nodoc:
-      base.extend(ClassMethods)
-
-      base.send(:include, InstanceMethods)
-
-      # Same as typing in the class
-      base.class_eval do
-        unloadable # Send unloadable so it will not be unloaded in development
-        after_save :update_publication
-      end
-
-    end
-
-    module ClassMethods
-    end
-
-    module InstanceMethods
-
-      def update_publication
-        if (self.action == 'A') and (self.changeset.repository.project_id == Setting.plugin_redmine_publications[:project].to_i)
-          regexp = Regexp.new(Setting.plugin_redmine_publications[:pattern])
-          match = self.path.match(regexp)
-          if match
-            Rails.logger.info('[INFO] Adding publication: "' << match[1])
-            Publication.find_or_create_by_name(:name => match[1],
-              :source_file => self.path, :repository_id => self.changeset.repository.id )
-          end
-        end      
-      end
-      
-    end
-    
-  end
-
-
-end
diff --git a/redmine/redmine_publications/lib/redmine_publications/issue_patch.rb b/redmine/redmine_publications/lib/redmine_publications/issue_patch.rb
deleted file mode 100644 (file)
index bd1f73e..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-module RedminePublications
-  # Patches Redmine's Issues dynamically. Adds a +after_save+ filter.
-
-  module IssuePatch
-    def self.included(base) # :nodoc:
-      base.extend(ClassMethods)
-      base.send(:include, InstanceMethods)
-      # Same as typing in the class
-      base.class_eval do
-        unloadable # Send unloadable so it will not be unloaded in development
-        validate :check_relations
-        after_save :update_relations
-      end
-    end
-    
-    module ClassMethods
-    end
-    
-    module InstanceMethods
-
-      def publication_names    
-        if not @pubnames
-          self.publications.map { |pub| pub.name }
-        else
-          @pubnames
-        end
-      end
-
-      def publication_names=(value)
-        @pubnames = value.sort!
-      end
-
-      def publications
-        Publication.all( 
-          :joins =>
-            "JOIN issue_publications ON (issue_publications.publication_id = publications.id)",
-          :conditions =>
-            ["issue_publications.issue_id = ? ", self.id] )
-      end
-
-      def check_relations
-        current_names = self.publication_names
-        non_existant = []
-
-        pubs =  Publication.find_all_by_name(current_names).map {|i| i.name}
-        missing = current_names.select {|name| not pubs.include?name }
-
-        if not missing.empty?
-          errors.add("publications", "Missing publication(s): " + missing.join(', '))
-        end
-      end
-
-      def update_relations
-        old = self.publications
-        current_names = self.publication_names
-        Rails.logger.info('[INFO] Updating relations: old= ' << old.inspect << ' current=' << current_names.inspect)
-
-        # delete unused relations
-        deleted = old.select { |v| not (current_names.include?(v.name)) }
-        deleted.each do |pub|
-          IssuePublication.delete_all(["issue_publications.issue_id = ? AND issue_publications.publication_id = ?", self.id, pub.id])
-        end
-
-        current_names.each do |name|
-          pub = Publication.find_by_name(name)
-          IssuePublication.find_or_create_by_publication_id_and_issue_id(pub.id, self.id)
-        end
-
-        return true
-      end
-
-    end
-  end
-end
diff --git a/redmine/redmine_publications/locales/en.yml b/redmine/redmine_publications/locales/en.yml
deleted file mode 100644 (file)
index 3932ef2..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-## YAML Template.
-en:
-  field_publications: Publications
diff --git a/redmine/redmine_publications/locales/pl.yml b/redmine/redmine_publications/locales/pl.yml
deleted file mode 100644 (file)
index 2bf0783..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-## YAML Template.
-pl:
-  field_publications: Publikacje
diff --git a/redmine/redmine_publications/routes.rb b/redmine/redmine_publications/routes.rb
deleted file mode 100644 (file)
index 8752c69..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-connect 'publications/:action',
-       :controller => 'publications',
-       :format => 'html'
-
-connect 'publications/:action.:format',
-       :controller => 'publications' 
-
-connect 'publications/:action/:pub', 
-       :controller => 'publications', :format => 'json',
-     :pub => /[^\/?]+/
diff --git a/redmine/redmine_publications/test/fixtures/publications.yml b/redmine/redmine_publications/test/fixtures/publications.yml
deleted file mode 100644 (file)
index 9d7d113..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
-one:
-  id: 1
-  source_file: One
-two:
-  id: 2
-  source_file: Two
diff --git a/redmine/redmine_publications/test/functional/publications_controller_test.rb b/redmine/redmine_publications/test/functional/publications_controller_test.rb
deleted file mode 100644 (file)
index 62b35f6..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-require File.dirname(__FILE__) + '/../test_helper'
-
-class MicrorestControllerTest < ActionController::TestCase
-  # Replace this with your real tests.
-  def test_truth
-    assert true
-  end
-end
diff --git a/redmine/redmine_publications/test/test_helper.rb b/redmine/redmine_publications/test/test_helper.rb
deleted file mode 100644 (file)
index bd1ed0c..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-# Load the normal Rails helper
-require File.expand_path(File.dirname(__FILE__) + '/../../../../test/test_helper')
-
-# Ensure that we are using the temporary fixture path
-Engines::Testing.set_fixture_path
diff --git a/redmine/redmine_publications/test/unit/publication_test.rb b/redmine/redmine_publications/test/unit/publication_test.rb
deleted file mode 100644 (file)
index ccf8aa4..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-require File.dirname(__FILE__) + '/../test_helper'
-
-class PublicationTest < Test::Unit::TestCase
-  fixtures :publications
-
-  # Replace this with your real tests.
-  def test_truth
-    assert true
-  end
-end
diff --git a/requirements-test.txt b/requirements-test.txt
new file mode 100644 (file)
index 0000000..fe7944c
--- /dev/null
@@ -0,0 +1,3 @@
+django-nose==0.0.3
+nose
+nosexcover
index d247c76..70cbcae 100644 (file)
@@ -7,14 +7,10 @@ PIL>=1.1
 ## Book conversion library
 git+git://github.com/fnp/librarian.git@master#egg=librarian
 
-## Django 
+## Django
 Django>=1.1.1,<1.2
 sorl-thumbnail>=3.2
 django-maintenancemode>=0.9
 
 # migrations
 south>=0.6
-
-## Debugging utils, uncomment this if you want tests
-# django-nose>=0.0.3
-# django-debug-toolbar>=0.8
\ No newline at end of file
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)