* End of javascript refactoring: both editors, history and gallery work as expected.
authorŁukasz Rekucki <lrekucki@gmail.com>
Sat, 10 Apr 2010 19:10:07 +0000 (21:10 +0200)
committerŁukasz Rekucki <lrekucki@gmail.com>
Sat, 10 Apr 2010 19:10:07 +0000 (21:10 +0200)
* Minor refactoring to wiki views.
* Added views and vstorage support for taging history.
* Other minor changes in vstorage.

27 files changed:
apps/wiki/forms.py
apps/wiki/models.py
apps/wiki/templates/wiki/document_details.html
apps/wiki/templates/wiki/history_view.html
apps/wiki/templates/wiki/save_dialog.html
apps/wiki/urls.py
apps/wiki/views.py
lib/test_vstorage.py
lib/vstorage.py
platforma/settings.py
platforma/static/css/dialogs.css
platforma/static/css/history.css
platforma/static/css/html.css
platforma/static/css/master.css
platforma/static/css/xmlcolors_15032010.css
platforma/static/js/slugify.js
platforma/static/js/wiki/base.js
platforma/static/js/wiki/diff_view.js
platforma/static/js/wiki/history_view.js
platforma/static/js/wiki/main.js
platforma/static/js/wiki/save_dialog.js
platforma/static/js/wiki/scan_gallery.js
platforma/static/js/wiki/source_editor.js
platforma/static/js/wiki/summary_view.js
platforma/static/js/wiki/wikiapi.js
platforma/static/js/wiki/wysiwyg_editor.js
platforma/templates/base.html

index ca21988..236c3f0 100644 (file)
@@ -35,6 +35,14 @@ class DocumentForm(forms.Form):
                 parent =self.cleaned_data['revision'] )
         
         return storage.get(self.cleaned_data['name'])
+    
+class DocumentTagForm(forms.Form):
+    TAGS = (
+        ("publish", "Do publikacji"),        
+    )
+        
+    tag = forms.ChoiceField(choices = TAGS)
+    version = forms.IntegerField(widget = forms.HiddenInput)
 
 class DocumentTextSaveForm(forms.Form):
     """ 
@@ -55,16 +63,16 @@ class DocumentTextSaveForm(forms.Form):
                 
     id = forms.CharField(widget=forms.HiddenInput)
     parent_revision = forms.IntegerField(widget=forms.HiddenInput)
+    text = forms.CharField(widget=forms.HiddenInput)
     
     author = forms.CharField(
         required = False,
         label = _(u"Autor"),
         help_text = _(u"Twoje imie i nazwisko lub email.")
-         
     )
     
     comment = forms.CharField(
-        required = False, 
+        required = True, 
         widget=forms.Textarea,
         label = _(u"Twój komentarz"),
         help_text = _(u"Opisz w miarę dokładnie swoje zmiany."), 
index 22a8119..a530916 100644 (file)
@@ -4,10 +4,16 @@
 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.  
 #
 import re
+import os
 import vstorage
 from vstorage import DocumentNotFound
 from wiki import settings
 
+from django.http import Http404
+
+import logging
+logger = logging.getLogger("fnp.wiki")
+
 class DocumentStorage(object):
     def __init__(self, path):
         self.vstorage = vstorage.VersionedStorage(path)
@@ -18,6 +24,12 @@ class DocumentStorage(object):
         else:
             text = self.vstorage.revision_text(name, revision)
         return Document(self, name = name, text = text)
+    
+    def get_or_404(self, *args, **kwargs):
+        try:
+            return self.get(*args, **kwargs)
+        except DocumentNotFound:
+            raise Http404            
 
     def put(self, document, author, comment, parent):
         self.vstorage.save_text(
@@ -52,7 +64,12 @@ class Document(object):
         try:
             return self.storage._info(self.name)[0]
         except DocumentNotFound:
-            return - 1
+            return -1
+        
+    def add_tag(self, tag):
+        """ Add document specific tag """
+        logger.debug("Adding tag %s to doc %s version %d", tag, self.name, self.revision)
+        self.storage.vstorage.add_page_tag(self.name, self.revision, tag)
 
     @property
     def plain_text(self):
@@ -70,8 +87,12 @@ class Document(object):
                 except ValueError:
                     continue                
                 
-        if 'gallery' not in result:
-            result['gallery'] = (settings.GALLERY_URL + self.name).replace(' ', '_')
+        gallery = result.get('gallery', self.name.replace(' ', '_'))
+        
+        if gallery.startswith('/'):            
+            gallery = os.path.basename(gallery)
+            
+        result['gallery'] = gallery
             
         if 'title' not in result:
             result['title'] = self.name.title()            
index d077e7d..cbed276 100644 (file)
@@ -23,7 +23,7 @@
     </div>
 </div>
 
-<div id="document-meta" 
+<div id="document-meta"
        data-document-name="{{ document.name }}" style="display:none">
        
        {% for k, v in document_meta.items %}
     <div id="tools">
         <a href="{{ REDMINE_URL }}projects/wl-publikacje/wiki/Pomoc" target="_blank">Pomoc</a>
         | {% include "registration/head_login.html" %} 
-        | Wersja: <span id="document-revision">{{ document_info.revision }}</span>
+        | Wersja: <span id="document-revision">unknown</span>
         | 
         <button style="margin-left: 6px" id="save-button">
             Zapisz
         </button>
     </div>
-    <ol id="tabs">
-       
-               <li id="SummaryPerspective-tab
-                       data-ui-related="summary-view-editor" data-ui-jsclass="SummaryPerspective">
+    <ol id="tabs">     
+               <li id="SummaryPerspective" 
+                       data-ui-related="summary-view-editor
+                       data-ui-jsclass="SummaryPerspective">
             <span>{{ document_meta.title }}</span>
         </li>          
                
-        <li id="VisualPerspective-tab" 
-                       data-ui-related="simple-editor" data-ui-jsclass="VisualPerspective">
+        <li id="VisualPerspective" 
+                       data-ui-related="simple-editor" 
+                       data-ui-jsclass="VisualPerspective">
             <span>Edytor</span>
         </li>
                
-               <li id="HistoryPerspective-tab
+               <li id="HistoryPerspective" 
                        data-ui-related="history-view-editor" 
                        data-ui-jsclass="HistoryPerspective">           
-            Historia
+            <span>Historia</span>
         </li>
                        
-               <li id="CodeMirrorPerspective-tab" 
-                       data-ui-related="source-editor" data-ui-jsclass="CodeMirrorPerspective">
-            Kod źródłowy
+               <li id="CodeMirrorPerspective" 
+                       data-ui-related="source-editor" 
+                       data-ui-jsclass="CodeMirrorPerspective">
+            <span>Kod źródłowy</span>
         </li>
     </ol>
 </div>
     </div>
 </div>
 {% include "wiki/save_dialog.html" %}
+{% include "wiki/tag_dialog.html" %}
 {% endblock %}
\ No newline at end of file
index c14cb4d..36be487 100644 (file)
@@ -1,19 +1,27 @@
 <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>
        </div> 
     <div id="history-view">
-        <p class="message-box" style="display:none;">
-        </p>
-        <div class="row-stub" style="display: none;">
-                       <span class="tag" data-stub-target="data-version-tag" data-stub-value="tag">dodaj tag</span>
-                       <span data-stub-value="version"></span>: <span data-stub-value="description"></span>
-            (<span data-stub-value="author"></span>, <span data-stub-value="date"></span>)
-        </div>
-        <div id="changes-list">
-        </div>
-        <p>            
-    
+        <p class="message-box" style="display:none;"></p>
+               
+               <table id="changes-list-container">
+        <tbody id="changes-list">              
+        </tbody>
+               <tbody style="display: none;">
+                       <tr class="entry row-stub">                     
+                       <td data-stub-value="version"></td>
+                       <td>
+                               <span data-stub-value="description"></span>
+                               <br />
+               <span data-stub-value="author"></span>, <span data-stub-value="date"></span>
+                       </td>
+                       <td data-stub-value="tag">                              
+                       </td>
+               </tr>
+               </tbody>
+               </table>                   
         <div id="diff-view">
         </div>
     </div>
index f49db3f..aba61cc 100644 (file)
@@ -1,24 +1,40 @@
-<div id="save_dialog" class="dialog">
-       <p>{{ text_save_form.comment.label }}</p>
-       <p class="help_text">{{text_save_form.comment.help_text}}</p>
-               {{ text_save_form.comment }}
+<div id="save_dialog" class="dialog" data-ui-jsclass="SaveDialog">
+       <form method="POST" action="">
+       <p>{{ forms.text_save.comment.label }}</p>
+       <p class="help_text">
+               {{ forms.text_save.comment.help_text}}
+               <span data-ui-error-for="{{ forms.text_save.comment.name }}"> </span>
+       </p>
+       {{forms.text_save.comment }}
+       
+       
        
        {% if request.user.is_anonymous %}
        <p>
-               {{ text_save_form.author.label }}: 
-               {{ text_save_form.author }}
-               <span class="help_text">{{ text_save_form.author.help_text }}</span>
+               {{ forms.text_save.author.label }}: 
+               {{ forms.text_save.author }}
+               <span class="help_text">{{ forms.text_save.author.help_text }}</span>
+               <span data-ui-error-for="{{ forms.text_save.author.name }}"> </span>
        </p>
        {% else %}
        <p>
-               {{ text_save_form.stage_completed.label }}: 
-               {{ text_save_form.stage_completed }}
-               <span class="help_text">{{ text_save_form.stage_completed.help_text }}</span>
+               {{ forms.text_save.stage_completed.label }}: 
+               {{ forms.text_save.stage_completed }}
+               <span class="help_text">{{ forms.text_save.stage_completed.help_text }}</span>
+               <span data-ui-error-for="{{ forms.text_save.stage_completed.name }}"> </span>
        </p>
        {% endif %}
        
+       
+       {% for f in forms.text_save.hidden_fields %}
+               {{ f }}
+       {% endfor %}
+       
+       <p data-ui-error-for="__all__"> </p>
+       
        <p class="action_area">
-               <button type="submit" class="ok-button">Zapisz</button>
-               <button class="cancel-button">Anuluj</button>
-       </p>            
+               <button type="submit" class"ok" data-ui-action="save">Zapisz</button>
+               <button type="button" class="cancel" data-ui-action="cancel">Anuluj</button>
+       </p>    
+       </form> 
 </div>
index 0c6393c..b319465 100644 (file)
@@ -12,7 +12,7 @@ urlpatterns = patterns('wiki.views',
         'document_text', name="wiki_text"),
     url(r'^(?P<name>[^/]+)/publish/(?P<version>\d+)$', 
         'document_publish', name="wiki_publish"),
-    url(r'^(?P<name>[^/]+)/diff/(?P<revA>\d+)/(?P<revB>\d+)$', 
+    url(r'^(?P<name>[^/]+)/diff$', 
         'document_diff', name="wiki_diff"),    
     url(r'^(?P<name>[^/]+)$', 
         'document_detail', name="wiki_details"),       
index 5bf3ce4..29039b7 100644 (file)
@@ -2,11 +2,12 @@ import os
 
 from django.conf import settings
 from django.views.generic.simple import direct_to_template
-from django.http import HttpResponse, Http404
-from django.utils import simplejson as json
+from django.views.decorators.http import require_POST
+from .helpers import JSONResponse, JSONFormInvalid, JSONServerError
+from django import http
 
-from wiki.models import Document, DocumentNotFound, getstorage
-from wiki.forms import DocumentForm, DocumentTextSaveForm
+from wiki.models import getstorage
+from wiki.forms import DocumentForm, DocumentTextSaveForm, DocumentTagForm
 from datetime import datetime
 from django.utils.encoding import smart_unicode
 import wlapi
@@ -24,12 +25,6 @@ import operator
 
 MAX_LAST_DOCS = 10
 
-class DateTimeEncoder(json.JSONEncoder):
-     def default(self, obj):
-         if isinstance(obj, datetime):
-             return datetime.ctime(obj) + " " + (datetime.tzname(obj) or 'GMT')
-         return json.JSONEncoder.default(self, obj)
-
 @never_cache
 def document_list(request, template_name = 'wiki/document_list.html'):
     # TODO: find a way to cache "Storage All"
@@ -42,10 +37,7 @@ def document_list(request, template_name = 'wiki/document_list.html'):
 @never_cache
 def document_detail(request, name, template_name = 'wiki/document_details.html'):
     
-    try:
-        document = getstorage().get(name)
-    except DocumentNotFound:        
-        raise Http404
+    document = getstorage().get_or_404(name)
     
     access_time = datetime.now()
     last_documents = request.session.get("wiki_last_docs", {})      
@@ -60,90 +52,115 @@ def document_detail(request, name, template_name = 'wiki/document_details.html')
         'document': document,
         'document_info': document.info,
         'document_meta': document.meta,
-        'text_save_form': DocumentTextSaveForm(),         
+        'forms': {"text_save": DocumentTextSaveForm(), "add_tag": DocumentTagForm() },         
     })
 
 @never_cache
-def document_text(request, name):
-    try:
-        document = getstorage().get(name)
-    except DocumentNotFound:        
-        raise Http404
+def document_text(request, name):    
+    storage = getstorage()
+    document = storage.get_or_404(name) 
     
     if request.method == 'POST':        
-        form = DocumentForm(request.POST, instance = document)
-        if form.is_valid():
-            document = form.save(document_author = request.user.username)
-            return HttpResponse(json.dumps({'text': document.plain_text, 'meta': document.meta(), 'revision': document.revision()}))
+        form = DocumentTextSaveForm(request.POST)
+        
+        if form.is_valid():            
+            revision = form.cleaned_data['parent_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 
+            )
+                        
+            return JSONResponse({
+                'text': document.plain_text if revision != document.revision() else None, 
+                'meta': document.meta(), 
+                'revision': document.revision() 
+            })
         else:
-            return HttpResponse(json.dumps({'errors': list(form.errors)}))
+            return JSONFormInvalid(form)                            
     else:
-        return HttpResponse(json.dumps({'text': document.plain_text, 'meta': document.meta(), 'revision': document.revision()}))
+        return JSONResponse({
+            'text': document.plain_text, 
+            'meta': document.meta(), 
+            'revision': document.revision()
+        })
    
 
 
 @never_cache
 def document_gallery(request, directory):
     try:
+        base_url = ''.join((
+                        smart_unicode(settings.MEDIA_URL),
+                        smart_unicode(settings.FILEBROWSER_DIRECTORY),
+                        smart_unicode(directory)))
+        
         base_dir = os.path.join(
                     smart_unicode(settings.MEDIA_ROOT), 
                     smart_unicode(settings.FILEBROWSER_DIRECTORY),
-                    smart_unicode(directory) )
+                    smart_unicode(directory))
         
-        def map_to_url(filename):           
-                         
-            return '%s%s%s/%s' % (
-                        smart_unicode(settings.MEDIA_URL),                         
-                        smart_unicode(settings.FILEBROWSER_DIRECTORY),
-                        smart_unicode(directory),
-                        smart_unicode(filename)
-            )
+        def map_to_url(filename):
+            return "%s/%s" % (base_url, smart_unicode(filename))
             
         def is_image(filename):
             return os.path.splitext(f)[1].lower() in (u'.jpg', u'.jpeg', u'.png')
             
         images = [ map_to_url(f) for f in map(smart_unicode, os.listdir(base_dir)) if is_image(f) ]
         images.sort()
-        return HttpResponse(json.dumps(images))
+        return JSONResponse(images)
     except (IndexError, OSError), exc:
         import traceback
         traceback.print_exc()
-
-        raise Http404
+        raise http.Http404
     
 @never_cache
-def document_diff(request, name, revA, revB):
-    storage = getstorage()     
-    docA = storage.get(name, int(revA))
-    docB = storage.get(name, int(revB)) 
+def document_diff(request, name):
+    storage = getstorage()    
     
+    revA = int(request.GET.get('from', 0))
+    revB = int(request.GET.get('to', 0))
     
-    return HttpResponse(nice_diff.html_diff_table(docA.plain_text.splitlines(), 
+    if revA > revB:
+        revA, revB = revB, revA
+        
+    if revB == 0:
+        revB = None   
+         
+    docA = storage.get_or_404(name, int(revA))
+    docB = storage.get_or_404(name, int(revB)) 
+        
+    return http.HttpResponse(nice_diff.html_diff_table(docA.plain_text.splitlines(), 
                                          docB.plain_text.splitlines()) )                                           
     
 @never_cache    
 def document_history(request, name):
     storage = getstorage()
+    return JSONResponse(storage.history(name)) 
+
+@require_POST
+def document_add_tag(request, name): 
+    storage = getstorage()
     
-    return HttpResponse( 
-                json.dumps(storage.history(name), cls=DateTimeEncoder), 
-                mimetype='application/json')
-    
+    form = DocumentTagForm(request.POST)
+    if form.is_valid():
+        doc = storage.get_or_404(name, form.cleaned_data['version'])
+        doc.add_tag(form.cleaned_data['tag'])
+        return JSONResponse({"message": _("Tag added")})  
+    else:
+        return JSONFormInvalid(form)
     
-@never_cache
+@require_POST
 def document_publish(request, name, version):
     storage = getstorage()
     
     # get the document
-    try:
-        document = storage.get(name, revision = int(version))
-    except DocumentNotFound:        
-        raise Http404
+    document = storage.get_or_404(name, revision = int(version))
     
     api = wlapi.WLAPI(settings.WL_API_CONFIG)    
     try:        
-        result = {"success": True, "result": api.publish_book(document)}
-    except wlapi.APICallException, e:                        
-        result = {"success": False, "reason": str(e)}
-        
-    return HttpResponse( json.dumps(result), mimetype='application/json')           
\ No newline at end of file
+        return JSONResponse({"result": api.publish_book(document)})
+    except wlapi.APICallException, e:  
+        return JSONServerError({"message": str(e)})                     
\ No newline at end of file
index 00df2f6..eaea46f 100644 (file)
@@ -44,7 +44,7 @@ class TestVersionedStorage(object):
                     comment = comment, parent=-1)
         
         saved = self.repo.open_page(title).read()
-        assert saved == text
+        assert_equal(saved, text)
 
     def test_save_text_noparent(self):
         text = u"test text"
@@ -57,7 +57,7 @@ class TestVersionedStorage(object):
                     comment = comment, parent=None)
         
         saved = self.repo.open_page(title).read()
-        assert saved == text
+        assert_equal(saved, text)
 
     def test_save_merge_no_conflict(self):
         text = u"test\ntext"
@@ -71,7 +71,7 @@ class TestVersionedStorage(object):
                     text = text, author = author, 
                     comment = comment, parent=-1)
         saved = self.repo.open_page(title).read()
-        assert saved == text
+        assert_equal(saved, text)
     
     def test_save_merge_line_conflict(self):
         text = u"test\ntest\n"
@@ -129,7 +129,86 @@ text
         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 same_repo.repo_revision() == current_repo_revision
+        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"}, # anonymous 
+            {"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"}, # anonymous 
+        {"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__':
index 527a245..319a0f1 100644 (file)
@@ -325,7 +325,7 @@ class VersionedStorage(object):
         """
         return guess_mime(self._file_path(title))
 
-    def _find_filectx(self, title):
+    def _find_filectx(self, title, rev = None):
         """Find the last revision in which the file existed."""
 
         repo_file = self._title_to_file(title)
@@ -338,14 +338,18 @@ class VersionedStorage(object):
             for parent in changectx.parents():
                 if parent != changectx:
                     stack.append(parent)
-        return changectx[repo_file]
+        
+        try:
+            fctx = changectx[repo_file]            
+            return fctx if rev is None else fctx.filectx(rev)
+        except IndexError, LookupError:
+            raise DocumentNotFound()
 
     def page_history(self, title):
         """Iterate over the page's history."""
 
         filectx_tip = self._find_filectx(title)
-        if filectx_tip is None:
-            return
+        
         maxrev = filectx_tip.filerev()
         minrev = 0
         for rev in range(maxrev, minrev - 1, -1):
@@ -354,31 +358,37 @@ class VersionedStorage(object):
             author = unicode(filectx.user(), "utf-8",
                              'replace').split('<')[0].strip()
             comment = unicode(filectx.description(), "utf-8", 'replace')
-            tags = filectx.changectx().tags()
+            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[0] if tags else None,
+                "tag": tags,
             }
 
     def page_revision(self, title, rev):
         """Get unicode contents of specified revision of the page."""
-
-        filectx_tip = self._find_filectx(title)
-        if filectx_tip is None:
-            raise DocumentNotFound()
-        try:
-            data = filectx_tip.filectx(rev).data()
-        except IndexError:
-            raise DocumentNotFound()
-        return data
+        return self._find_filectx(title, rev).data()
 
     def revision_text(self, title, rev):
         data = self.page_revision(title, rev)
         text = unicode(data, self.charset, 'replace')
         return text
+    
+    @with_working_copy_locked
+    def add_page_tag(self, title, rev, tag, user = "<wiki>", doctag = True):
+        if doctag:
+            tag = "{title}#{tag}".format(**locals())
+            
+        message = "Assigned tag {tag} to version {rev} of {title}".format(**locals())
+            
+        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."""
index 0290dd8..8814148 100644 (file)
@@ -132,13 +132,13 @@ COMPRESS_CSS = {
 }
  
 COMPRESS_JS = {
-    # everything except codemirror and jquery (which we take from google)
+    # everything except codemirror
     'detail': {
         'source_filenames': (
-                #'js/jquery-1.4.2.min.js', 
+                'js/jquery-1.4.2.min.js', 
                 'js/jquery.autocomplete.js', 
                 'js/jquery.blockui.js',
-                'js/jquery.elastic.js',
+                'js/jquery.elastic.js',                
                 'js/button_scripts.js',
                 'js/slugify.js',
                 
@@ -146,18 +146,26 @@ COMPRESS_JS = {
                 'js/wiki/wikiapi.js',
                 'js/wiki/base.js',
                 'js/wiki/xslt.js',
+                
+                # dialogs
+                'js/wiki/save_dialog.js',
+                
+                # views
                 'js/wiki/history_view.js',
                 'js/wiki/summary_view.js',
                 'js/wiki/source_editor.js',
                 'js/wiki/wysiwyg_editor.js',
                 'js/wiki/scan_gallery.js',                
+                'js/wiki/diff_view.js',
+                
+                # bootstrap
                 'js/wiki/main.js',
         ),             
         'output_filename': 'compressed/detail_scripts_?.js',
      },
     'listing': {
         'source_filenames': (
-                'js/jquery-1.4.2.min.js', 
+                'js/jquery-1.4.2.min.js', 
                 'js/slugify.js',                
         ),             
         'output_filename': 'compressed/listing_scripts_?.js',
index 026fc9d..9d03435 100644 (file)
@@ -25,3 +25,8 @@
 .dialog p {
        margin: 0.5em;
 }
+
+*[data-ui-error-for] {
+       color: red;
+       font-weight: bold;
+}
index 5028e23..b319116 100644 (file)
     bottom: 0px;
     left: 0px;
     right: 0px;
-       z-index: 1;
+    z-index: 1;
 }
 
 /*
  * File History
  */
+#changes-list-container {
+    margin: 1em auto;
+    width: 70%;
+}
+
+table#changes-list-container {
+    border-spacing: 0px 15px;
+}
+
 #changes-list {
-       margin: 0.5em 0.2em;    
+    margin: 0.5em 0.2em;
+}
+
+#changes-list td {
+    padding: 0.5em 1em;
+}
+
+#changes-list .entry {
+    position: relative;
+    padding: 0.5em;
+    padding-left: 3em;
+    margin: 0.5em;
 }
 
-#changes-list div {
-       position: relative;
-       padding: 0.5em;
-       margin: 0.5em;
+#changes-list .entry:hover {
+    background-color: #f0f0f0;
 }
 
-#changes-list div:hover {
-       background-color: #f0f0f0;
+#changes-list .entry.selected {
+    background-color: #ffec63;
 }
 
-#changes-list div.selected {
-       background-color: #ffec63;
+#changes-list .tag {
+    display: inline-block;
+    visibility: hidden;
+    width: 60px;
+    margin: 0 0.5em 0 0;
+    font-size: 11px;
+    padding: 3px 2px;
+    text-align: center;
+    color: black;
+    background: #add8e6;
+    cursor: pointer;
+    vertical-align: middle;
+    -moz-border-radius: 10px;
+    -webkit-border-radius: 10px;
+    border-radius: 10px;
 }
 
-#changes-list span.tag {
-       display: inline-block;
-       visibility: hidden;
-       width: 60px;
-       margin: 0 0.5em 0 0;    
-       font-size: 11px;
-       padding: 3px 2px;
-       text-align: center;             
-       color: black;
-       background: #add8e6;
-       cursor: pointer;
-       vertical-align: middle;
-       -moz-border-radius: 10px;
-       -webkit-border-radius: 10px;
-       border-radius: 10px;
+#changes-list .entry:hover .tag {
+    visibility: visible;
 }
 
-#changes-list div:hover span.tag {
-       visibility: visible;     
+#changes-list .tag:hover {
+    background: #bde8f6;
 }
 
-#changes-list span.tag:hover {
-       background: #bde8f6;
+#changes-list *[data-version-tag] {
+    visibility: visible;
+    border: 1px solid black;
+    color: black;
 }
 
-#changes-list span[data-version-tag] {
-       visibility: visible;
-       border: 1px solid black;        
-       
-       color: black;
+#changes-list *[data-stub-value =
+'version'] {
+    font-weight: bold;
 }
 
-#changes-list span[data-stub-value='version'] {
-       font-weight: bold;
+#changes-list td[data-stub-value =
+'version'] {
+    vertical-align: text-top;
 }
 
-#changes-list span[data-stub-value='date'], 
-#changes-list span[data-stub-value='author'] 
-{
-       font-size: 11px;
-       color: gray;
+#changes-list *[data-stub-value =
+'date'], #changes-list *[data-stub-value = 'author'] {
+    font-size: 11px;
+    color: gray;
 }
-/* 
+
+/*
  * Graphical DIFF view
- * 
+ *
  */
 #history-view .diff_table {
-       width: 90%;
+    width: 90%;
 }
 
- .diff_table { 
-       border-width: 1px;
-       border-style: solid;
-       border-color: black;
-       empty-cells: show;
-       border-spacing: 0px;            
+.editor.DiffPerspective {
+    overflow-y: scroll;
+}
+
+.diff_table {
+    border-width: 1px;
+    border-style: solid;
+    border-color: black;
+    empty-cells: show;
+    border-spacing: 0px;
 }
 
 .diff_table td {
-       border-width: 0px 1px 1px 0px;
-       border-style: dotted;
-       border-color: grey;
-       
-       font-size: 10px;
-       line-height: 20px;
-       font-family: monospace;
-       padding: 0px;
-       white-space:pre-line;
-       /*word-wrap:break-word;
-       word-break:break-all; */
+    border-width: 0px 1px 1px 0px;
+    border-style: dotted;
+    border-color: grey;
+    font-size: 10px;
+    line-height: 20px;
+    font-family: monospace;
+    padding: 0px;
+    white-space: pre-line;
+    /*word-wrap:break-word;
+     word-break:break-all; */
 }
 
 .diff_table th {
-       border-width: 0px 1px 1px 0px;
-       border-style: solid;
-       border-color: black;
-       background: #e5ffe5;            
+    border-width: 0px 1px 1px 0px;
+    border-style: solid;
+    border-color: black;
+    background: #e5ffe5;
 }
-/* .diff_table td.left, .diff_table td.right {
-       width: 50%;
-}*/
 
+/* .diff_table td.left, .diff_table td.right {
+ width: 50%;
+ }*/
 .diff_table tr.change {
-       background-color: #dcdcdc;
-       
+    background-color: #dcdcdc;
 }
 
 .diff_mark {
-       display: inline-block;
-       padding: 2px;
+    display: inline-block;
+    padding: 2px;
 }
 
 .diff_mark_removed {
-       background-color: #ff9c94;
+    background-color: #ff9c94;
 }
 
 .diff_mark_added {
-       background-color: #90ee90;
+    background-color: #90ee90;
 }
 
 .diff_mark_changed {
-       background-color: yellow;
+    background-color: yellow;
 }
\ No newline at end of file
index df8c54c..ba0f853 100644 (file)
@@ -1,5 +1,4 @@
 /* Style widoku HTML. Nie należy tu ustawiać position ani marginesów */
-
 .htmlview {
     counter-reset: main;
     font-size: 16px;
@@ -7,42 +6,43 @@
     line-height: 1.5em;
     padding: 3em;
     padding-left: 45px;
-       overflow-y: scroll;
-       overflow-x: auto;
+    overflow-y: scroll;
+    overflow-x: auto;
 }
 
 .htmlview[data-tag-names-visible] {
-       padding-left: 90px;     
-}
-
-.htmlview[data-tag-names-visible] *[x-editable]:not(*[x-common])::before {
-       display: block;
-       float: left;
-       clear: left;
-       content: attr(x-node);
-       font-weight: bold;
-       font-style: normal;
-       font-variant:normal;    
-       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;     
-}
-
-.htmlview *[x-node='RDF'] {
+    padding-left: 90px;
+}
+
+/*
+ .htmlview[data-tag-names-visible] *[x-editable]:not(*[x-common])::before {
+ display: block;
+ float: left;
+ clear: left;
+ content: attr(x-node);
+ font-weight: bold;
+ font-style: normal;
+ font-variant:normal;
+ 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;
+ }
+ */
+.htmlview *[x-node = 'RDF'] {
     display: none;
 }
 
 .htmlview * {
-    position: relative;        
+    position: relative;
 }
 
 .htmlview div {
 }
 
 .htmlview .podtytul {
-    /* */    
+    /* */
 }
 
 .htmlview .didaskalia {
 }
 
 .htmlview .strofa {
-    margin: 1.5em 0 0.5em auto;    
+    margin: 1.5em 0 0.5em auto;
 }
 
 /* wersy */
-.htmlview .strofa .wers_wciety, .htmlview .strofa .wers_wciety[data-wlf-typ='1'] {
-       margin-left: 1em;
+.htmlview .strofa .wers_wciety, .htmlview .strofa .wers_wciety[data-wlf-typ =
+'1'] {
+    margin-left: 1em;
 }
 
-.htmlview .strofa .wers_wciety[data-wlf-typ='2'] {
-       margin-left: 2em;
+.htmlview .strofa .wers_wciety[data-wlf-typ =
+'2'] {
+    margin-left: 2em;
 }
 
-.htmlview .strofa .wers_wciety[data-wlf-typ='3'] {
-       margin-left: 3em;
+.htmlview .strofa .wers_wciety[data-wlf-typ =
+'3'] {
+    margin-left: 3em;
 }
 
-.htmlview .strofa .wers_wciety[data-wlf-typ='4'] {
-       margin-left: 4em;
+.htmlview .strofa .wers_wciety[data-wlf-typ =
+'4'] {
+    margin-left: 4em;
 }
 
-.htmlview .strofa .wers_wciety[data-wlf-typ='5'] {
-       margin-left: 5em;
+.htmlview .strofa .wers_wciety[data-wlf-typ =
+'5'] {
+    margin-left: 5em;
 }
 
-.htmlview .strofa .wers_wciety[data-wlf-typ='6'] {
-       margin-left: 6em;
+.htmlview .strofa .wers_wciety[data-wlf-typ =
+'6'] {
+    margin-left: 6em;
 }
 
 /* błędne wersy */
-.htmlview *:not(.strofa) > *[x-verse]::after {
-       content: "Ten wers znajduje się poza strofą.";
-       display: inline;
-       background: red;
-       font-size: 8pt;
-       border: 1px solid black;
-       -moz-border-radius: 10px;
-       -webkit-border-radius: 10px;
-       padding: 1px 1em;
-       margin-left: 1em;
-       vertical-align: super;
+.htmlview *:
+not(.strofa) > *[x-verse]::after {
+    content: "Ten wers znajduje się poza strofą.";
+    display: inline;
+    background: red;
+    font-size: 8pt;
+    border: 1px solid black;
+    -moz-border-radius: 10px;
+    -webkit-border-radius: 10px;
+    padding: 1px 1em;
+    margin-left: 1em;
+    vertical-align: super;
 }
 
-
 .htmlview .kwestia .strofa {
     margin: 0;
 }
     padding-bottom: 1.5em;
 }
 
-.htmlview div.nota p,
-.htmlview div.dedykacja p {
+.htmlview div.nota p, .htmlview div.dedykacja p {
     text-align: right;
     font-style: italic;
 }
     font-style: italic;
 }
 
-.htmlview .mat,
-.htmlview .slowo_obce,
-.htmlview .tytul_dziela,
-.htmlview .didaskalia {
+.htmlview .mat, .htmlview .slowo_obce, .htmlview .tytul_dziela, .htmlview .didaskalia {
     font-style: italic;
 }
 
     margin: 1em;
 }
 
- .parse-warning .message {
+.parse-warning .message {
     color: purple;
     font-weight: bold;
 }
 
 /* Uwaga/Extra */
-
 .htmlview .uwaga {
-       background-color: #96e0e4;
-       border: 1px solid black;
-       -moz-border-radius: 10px;
-       -webkit-border-radius: 10px;
-       display: block;
-       font-size: 10pt;
-       line-height: 12pt;
-       padding: 2px 1em;
-       float: right;   
-       max-width: 20%;
-       max-height: 24pt;
-       margin-left: 0.5em;
-       overflow: hidden;
+    background-color: #96e0e4;
+    border: 1px solid black;
+    -moz-border-radius: 10px;
+    -webkit-border-radius: 10px;
+    display: block;
+    font-size: 10pt;
+    line-height: 12pt;
+    padding: 2px 1em;
+    float: right;
+    max-width: 20%;
+    max-height: 24pt;
+    margin-left: 0.5em;
+    overflow: hidden;
 }
 
 .utwor > .uwaga {
-       float: none;
-       padding: 0.5em 1em;
-       margin: 1em;
-       max-width: 100%;
-       max-height: 100%;
+    float: none;
+    padding: 0.5em 1em;
+    margin: 1em;
+    max-width: 100%;
+    max-height: 100%;
 }
 
 .htmlview .uwaga:hover {
-       max-height: 100%;
+    max-height: 100%;
 }
 
-
 /* Motywy */
 /* ======================== */
 /* = Footnotes and themes = */
 /* ======================== */
-
 .htmlview .begin, .htmlview .end {
     background: green;
 }
 
 .htmlview .motyw {
     /* position: absolute; */
-    
     float: right;
     left: auto;
     clear: right;
-    
     width: 10em;
-    
     font-weight: normal;
     font-size: 13px;
     line-height: 18px;
     font-variant: normal;
     text-decoration: none;
-
-
     background-color: #fff;
-    
-/*    border: 1px solid gray;
-
-    border-right: none;
-*/    
+    /*    border: 1px solid gray;
+     
+     border-right: none;
+     */
     z-index: 1;
     -moz-user-select: -moz-none;
     -webkit-user-select: none;
     margin-top: 0.2em;
 }
 
-/* 
+/*
  * Przypisy
  */
-
 /* Znaczniki w tekście */
-.htmlview .annotation {    
+.htmlview .annotation {
     vertical-align: super;
     text-decoration: none;
-/*    font-size: 10px;    */
+    /*    font-size: 10px;    */
 }
 
 .htmlview .annotation:before {
 .htmlview .annotation:hover {
     background-color: #96e0e4;
 }
-
 *.htmlview *.annotation-inline-box {
     position: static;
 }
 /*
  * Przypisy w tekście
  */
- .htmlview .annotation-inline-box > span[x-annotation-box]
- {
-     display: none;
-     position: absolute;
-
-     width: 300px;      
-     
-     font-size: 10pt;  
-     line-height: 12pt;
-     font-weight: normal;
-     font-style: normal;
-
-     background: #fffe93;
-     border-color: black;
-     border-width: 1px;
-     border-style: solid;
-        border-radius: 10px;
-        -moz-border-radius: 10px;
-        -webkit-border-radius: 10px;
-        
-     padding: 3px 5px;
-
-     text-decoration: none;
-        
-     z-index: 1000;
- }
+.htmlview .annotation-inline-box > span[x-annotation-box] {
+    display: none;
+    position: absolute;
+    width: 300px;
+    font-size: 10pt;
+    line-height: 12pt;
+    font-weight: normal;
+    font-style: normal;
+    background: #fffe93;
+    border-color: black;
+    border-width: 1px;
+    border-style: solid;
+    border-radius: 10px;
+    -moz-border-radius: 10px;
+    -webkit-border-radius: 10px;
+    padding: 3px 5px;
+    text-decoration: none;
+    z-index: 1000;
+}
 
 /*
  * Przypisy na końcu utworu (aktualnie nieuzywane)
     left: -0.4em;
     width: 2.5em;
     text-align: right;
-
 }
 
 .htmlview .annotations-block .annotation-backref:before {
 /*
  * EDITABLE ELEMENTS
  */
-
-.htmlview *[x-editable] {    
+.htmlview *[x-editable] {
     position: relative;
     padding: 2px;
     margin-left: 0;
 }
 
 /* focused editable element */
-.htmlview *[x-editable]:hover
-{
+.htmlview *[x-editable]:hover {
     z-index: 900;
-} 
+}
 
-.htmlview *[x-editable][x-open]
-{
+.htmlview *[x-editable][x-open] {
     visibility: hidden;
 }
 
     left: -1px;
     width: 72px;
     height: 21px;
-    
     display: block;
-/*    margin: 4px 0 2px 0;*/
+    /*    margin: 4px 0 2px 0;*/
     padding: 5px 5px 2px 5px;
     border: none;
     background-color: #FAFAFA;
-    
-/*    z-index: 3000;*/
-/*    color: #FFF;
-    z-index: 1500;
-*/    border: 1px solid #DDD;
+    /*    z-index: 3000;*/
+    /*    color: #FFF;
+     z-index: 1500;
+     */
+    border: 1px solid #DDD;
     border-bottom: none;
 }
 
 }
 
 .edit-button:hover, .edit-button:active, .delete-button:hover, .delete-button:active, .accept-button:hover, .accept-button:active {
-/*    color: #FFF;*/
+    /*    color: #FFF;*/
     background-color: #999;
     color: #FFF;
 }
 .htmlview *[x-editable][x-open] > .default-menu {
     visibility: hidden;
 }
+
 .htmlview *[x-editable][x-open] *[x-annotation-box] > .default-menu {
     visibility: hidden;
 }
 .htmlview *[x-editable] > .edit-menu {
     visibility: hidden;
 }
+
 .htmlview *[x-editable] *[x-annotation-box] > .edit-menu {
     visibility: hidden;
 }
 .htmlview *[x-editable][x-open] > .edit-menu {
     visibility: visible;
 }
+
 .htmlview *[x-editable][x-open] *[x-annotation-box] > .edit-menu {
     visibility: visible;
 }
     border: 0px;
     background-color: gray;
     padding: 1px;
-
     z-index: 2000;
     position: absolute;
 }
 
-.html-editarea textarea
-{
+.html-editarea textarea {
     position: absolute;
     top: 0;
-    
     margin: 0px;
     padding: 0px;
-
     width: 100%;
     height: 100%;
-
     z-index: 0;
     font-size: 10pt;
-/*    background-color: ivory;*/
+    /*    background-color: ivory;*/
 }
 
 .htmlview .out-of-flow-text {
-       display: block;
-       font-face: monospace;
+    display: block;
+    font-face: monospace;
     border: 2px solid red !important;
-    white-space: pre-line;    
+    white-space: pre-line;
 }
 
 .htmlview .out-of-flow-text::before {
-       content: "Tekst w tej ramce nie jest otagowany!";
-       background-color: #ff6c6c;
-       color: black;
-       
-       font-size: 10pt;
-       line-height: 12pt;
-       border: 1px solid black;
-       -moz-border-radius: 10px;
-       -webkit-border-radius: 10px;
-       padding: 5px 1em;
-       margin: 0em;
-       margin-left: 1em;
-       
-       text-align: justify;
-       
-       display: inline;
-       float: right;
-       max-width: 25%;
+    content: "Tekst w tej ramce nie jest otagowany!";
+    background-color: #ff6c6c;
+    color: black;
+    font-size: 10pt;
+    line-height: 12pt;
+    border: 1px solid black;
+    -moz-border-radius: 10px;
+    -webkit-border-radius: 10px;
+    padding: 5px 1em;
+    margin: 0em;
+    margin-left: 1em;
+    text-align: justify;
+    display: inline;
+    float: right;
+    max-width: 25%;
 }
 
 .unknown-tag {
index 68d8219..5f3fe96 100644 (file)
@@ -69,7 +69,7 @@ body {
        right: 0px;
        left: 0px;
        height: 30px;
-       border-bottom: 1px solid #999;
+       border-bottom: 1px solid #999; 
        
     margin: 0;
     padding: 0;
@@ -102,13 +102,16 @@ body {
 #tabs {
        overflow: hidden;
     margin: 0;
-       height: 30px;    
+       padding: 0;
+       height: 31px;
+       border: 0px;    
        padding-left: 1em;      
 }
 
 #tabs li {
-       height: 24px;
-       margin-top: 6px;        
+       height: 18px;
+       margin-top: 6px;
+       margin-bottom: 0px;     
        
     -webkit-user-select: none; 
     cursor: pointer;
@@ -128,7 +131,8 @@ body {
        -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: 1px solid #999;
+       border-bottom-width: 0px;       
        -moz-border-radius: 4px 4px 0px 0px;
        -webkit-border-radius: 4px;
     -webkit-border-bottom-left-radius: 0px;
@@ -277,6 +281,12 @@ p { margin: 0;}
        padding-right: 5px;
 }
 
+img.tabclose {
+       padding-left: 8px;
+       width: 10px;
+       height: 10px;
+}
+
 
 /*
  * HTML Editor view
index 5a2d7cc..099f94a 100644 (file)
@@ -1,13 +1,11 @@
 .editbox {  
   margin: .4em;
   margin-top: 5px;
-  margin-left: 45px;
+  margin-left: 5px;
   padding: 0;
-  
   font-family:"Lucida Console", monospace;
   font-size: 13px;
-  line-height: 18px;
-  
+  line-height: 18px;  
   color: black;
 }
 
index b000b64..8be7758 100644 (file)
         
         return s;
     }
-})()
+})();
+
+
index 535749c..429b0e6 100644 (file)
 (function($) 
-{      
-       $.wiki = {};
+{              
+       var noop = function() { };
        
-       $.wiki.Perspective = function(document, callback) {
-               // initialization
+       $.wiki = {
+               perspectives: {},
+               cls: {}         
        };
        
-       $.wiki.Perspective.toString = function() {
-               return this.perspective_id;
+       $.wiki.activePerspective = function() { 
+               return this.perspectives[$("#tabs li.active").attr('id')];
+       };
+       
+       $.wiki.exitContext = function() {
+               var ap = this.activePerspective();
+               if(ap) ap.onExit();
+               return ap;      
+       };
+       
+       $.wiki.enterContext = function(ap) {
+               if(ap) ap.onEnter();                            
+       };
+       
+       $.wiki.isDirty = function() {
+               var ap = this.activePerspective();
+               return (!!CurrentDocument && CurrentDocument.has_local_changes) || ap.dirty(); 
+       };
+       
+       $.wiki.newTab = function(doc, title, klass) {
+               var base_id = 'id' + Math.floor(Math.random()* 5000000000);
+               var id = (''+klass)+'_' + base_id;
+               var $tab = $('<li id="'+id+'" data-ui-related="'+base_id+'" data-ui-jsclass="'+klass+'" >'
+                               + title + '<img src="/static/icons/close.png" class="tabclose"></li>');
+               var $view = $('<div class="editor '+klass+'" id="'+base_id+'"> </div>');                
+               
+               this.perspectives[id] = new $.wiki[klass]({
+                       doc: doc,
+                       id: id,
+                       base_id: base_id,
+               });             
+               
+               $('#tabs').append($tab);                                        
+               $view.hide().appendTo('#editor');                       
+               return {
+                       tab: $tab[0],
+                       view: $view[0],
+               };                                                      
+       };
+       
+       $.wiki.initTab = function(options) {
+               var klass = $(options.tab).attr('data-ui-jsclass');
+               
+               return new $.wiki[klass]({
+                       doc: options.doc,
+                       id: $(options.tab).attr('id'),
+                       callback: function() {
+                               $.wiki.perspectives[this.perspective_id] = this;
+                               if(options.callback)
+                                       options.callback.call(this);                            
+                       }                       
+               });
+       };
+       
+       $.wiki.perspectiveForTab = function(tab) { // element or id
+               return this.perspectives[ $(tab).attr('id')];
        }
        
+       $.wiki.switchToTab = function(tab){
+               var self = this;
+               var $tab = $(tab);
+               
+               if($tab.length != 1) 
+                       $tab = $(DEFAULT_PERSPECTIVE);
+               
+               var $old = $('#tabs li').filter('.active');
+                               
+               $old.each(function(){
+                       $(this).removeClass('active');
+                       $('#' + $(this).attr('data-ui-related')).hide();
+                       self.perspectives[$(this).attr('id')].onExit();
+               });
+               
+               /* show new */
+               $tab.addClass('active');
+               $('#' + $tab.attr('data-ui-related')).show();
+               
+               console.log($tab);
+               console.log($.wiki.perspectives);
+               
+               $.wiki.perspectives[$tab.attr('id')].onEnter();
+       };
+       
+       /*
+        * Basic perspective.
+        */
+       $.wiki.Perspective = function(options) {
+               if(!options) return;
+               
+               this.doc = options.doc;
+               if (options.id) {
+                       this.perspective_id = options.id;
+               }
+               else {
+                       this.perspective_id = '';
+               }
+                               
+               if(options.callback)
+                       options.callback.call(this);
+       };
+       
+       $.wiki.Perspective.prototype.toString = function() {
+               return this.perspective_id;
+       };
+       
+       $.wiki.Perspective.prototype.dirty = function() {
+               return true;
+       };
+       
        $.wiki.Perspective.prototype.onEnter = function () {
                // called when perspective in initialized
                if (this.perspective_id) {
        
        $.wiki.Perspective.prototype.onExit = function () {
                // called when user switches to another perspective 
+               document.location.hash = '';
        };       
        
+       $.wiki.Perspective.prototype.destroy = function() {
+               // pass         
+       };
+       
        $.wiki.Perspective.prototype.freezeState = function () {
                // free UI state (don't store data here)
        };
                // restore UI state
        };
        
+       /*
+        * Stub rendering (used in generating history)
+        */
        $.wiki.renderStub = function($container, $stub, data) 
        {
                var $elem = $stub.clone();
                $elem.show();
                return $elem;                                           
        };
+       
+       /*
+        * Dialogs
+        */
+       function GenericDialog(element) {
+               if(!element) return;
+               
+               var self = this;
+                               
+               self.$elem = $(element);
+               
+               if(!self.$elem.attr('data-ui-initialized')) {
+                       console.log("Initializing dialog", this);
+                       self.initialize();
+                       self.$elem.attr('data-ui-initialized', true);                   
+               }
+                
+               self.show();                            
+       };
+       
+       GenericDialog.prototype = {
+       
+               /*
+               * Steps to follow when the dialog in first loaded on page.
+               */
+               initialize: function(){
+                       var self = this;
+                       
+                       /* bind buttons */
+                       $('button[data-ui-action]', self.$elem).click(function(event) {
+                               event.preventDefault();
+                               
+                               var action = $(this).attr('data-ui-action');
+                               console.log("Button pressed, action: ", action);
+                                
+                               try {
+                                       self[action + "Action"].call(self);
+                               } catch(e) {
+                                       console.log("Action failed:", e);
+                                       // always hide on cancel
+                                       if(action == 'cancel')
+                                               self.hide();                                    
+                               }                                                               
+                       });                     
+               },
+               
+               /* 
+                * Prepare dialog for user. Clear any unnessary data.
+               */
+               show: function() {
+                       $.blockUI({
+                               message: this.$elem,
+                               css: {
+                                       'top': '25%',
+                                       'left': '25%',
+                                       'width': '50%'
+                               }
+                       });
+               },
+               
+               hide: function(){
+                       $.unblockUI();
+               },
+               
+               cancelAction: function() {
+                       this.hide();                    
+               },
+               
+               doneAction: function() {
+                       this.hide();
+               },
+               
+               clearForm: function() {
+                       $("*[data-ui-error-for]", this.$elem).text('');
+               },
                
+               reportErrors: function(errors) {
+                       var global = $("*[data-ui-error-for='__all__']", this.$elem);
+                       var unassigned = [];
+                       
+                       for (var field_name in errors) 
+                       {                               
+                               var span = $("*[data-ui-error-for='"+field_name+"']", this.$elem);
+                               
+                               if(!span.length) {
+                                       unassigned.push(field_name);
+                                       continue;
+                               }
+                               
+                               span.text(errors[field_name].join(' '));        
+                       }
+                       
+                       if(unassigned.length > 0)
+                               global.text( global.text() + 'W formularzu wystąpiły błędy');
+               }       
+       };       
+       
+       $.wiki.cls.GenericDialog = GenericDialog;  
+        
+       $.wiki.showDialog = function(selector) {
+               var elem = $(selector);
+               
+               if(elem.length != 1) {
+                       console.log("Failed to show dialog:", selector, elem);
+                       return false;                   
+               }
+               
+               try {   
+                   var klass = elem.attr('data-ui-jsclass') 
+                       return new $.wiki.cls[klass](elem);                                             
+               } catch(e) {
+                       console.log("Failed to show dialog", selector, klass, e);
+                       return false;
+               }                
+       };
+       
 })(jQuery);
index 3eafd13..d6e71a6 100644 (file)
@@ -1,8 +1,11 @@
 (function($){
        
        function DiffPerspective(options) {
-               var old_callback = options.callback || function() {};        
+               var old_callback = options.callback || function() {};
+               var self = this;
+                       
         options.callback = function(){
+                       self.base_id = options.base_id;                 
                        old_callback.call(this);
                };              
                
         // must 
     };
        
+       DiffPerspective.prototype.destroy = function() {
+               $('#' + this.base_id).remove();
+               $('#' + this.perspective_id).remove();
+       };
+       
        DiffPerspective.prototype.onEnter = function(success, failure){
                $.wiki.Perspective.prototype.onEnter.call(this);
-               
                console.log("Entered diff view");
        };
        
index 0f35ca3..2ee4558 100644 (file)
@@ -1,58 +1,37 @@
 (function($){
-
-    function fetchDiff(success, failed){
-        var changelist = $('#changes-list');
-   
-               var selected = $('div.selected', changelist); 
-        
-        if (selected.length != 2) {
-            window.alert("Musisz zaznaczyć dokładnie dwie wersje do porównania.");
-            if(failed) failed();
-        }
-        
-        $.blockUI({
-            message: 'Wczytywanie porównania...'
-        });
-        
-        $.ajax({
-                       method: "GET",
-            url: document.location.href + '/diff/' + rev_a.val() + '/' + rev_b.val(),
-            dataType: 'html',
-            error: function(){
-                $.unblockUI();
-                if(failed) failed('Nie udało się wczytać porównania z serwera.');
-            },
-            success: function(data){
-                var diffview = $('#diff-view');
-                diffview.html(data);
-                diffview.show();
-                $.unblockUI();
-                if(success) success(data);
-            }
-        });
-    }
     
-    function HistoryPerspective(doc, callback) {
-               this.perspective_id = 'HistoryPerspective';
-               this.doc = doc;
-               
-        // first time page is rendered
-        $('#make-diff-button').click(fetchDiff);
-               
-               $('#changes-list div').live('click', function() {
-                       var $this = $(this);
-                       if($this.hasClass('selected')) 
-                               return $this.removeClass('selected');
-                               
-                       if($("#changes-list div.selected").length < 2)
-                               return $this.addClass('selected');
-               });
+    function HistoryPerspective(options) {
+               var old_callback = options.callback || function() {};
                
-               $('#changes-list span.tag').live('click', function(event) {                     
-                       return false;                                           
-               });
+               options.callback = function() {
+                       var self = this;
+                       
+                       // first time page is rendered
+               $('#make-diff-button').click(function() {
+                               self.makeDiff();
+                       });
+                       
+                       $('#tag-changeset-button').click(function() {
+                               self.showTagForm();                             
+                       });
+        
+               $('#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');
+               });
+               
+           $('#changes-list span.tag').live('click', function(event){
+                   return false;
+               });
+        
+               old_callback.call(this);
+               }
                
-               callback.call(this);
+               $.wiki.Perspective.call(this, options);         
     };
     
     HistoryPerspective.prototype = new $.wiki.Perspective();
         // must 
     };
     
-    HistoryPerspective.prototype.onEnter = function(success, failure) 
-       {               
-               $.wiki.Perspective.prototype.onEnter.call(this);
-               
+    HistoryPerspective.prototype.onEnter = function(success, failure){
+        $.wiki.Perspective.prototype.onEnter.call(this);
+        
         $.blockUI({
             message: 'Odświeżanie historii...'
         });
-               
-               function _finalize(s) {
-                       $.unblockUI();
-                       
-                       if(s) { if(success) success(); }
-                       else { if(failure) failure(); }
-               }
         
-        function _failure(doc, message) {
-          $('#history-view .message-box').html('Nie udało się odświeżyć historii:' + message).show();
-                 _finalize(false);    
+        function _finalize(s){
+            $.unblockUI();
+            
+            if (s) {
+                if (success) 
+                    success();
+            }
+            else {
+                if (failure) 
+                    failure();
+            }
+        }
+        
+        function _failure(doc, message){
+            $('#history-view .message-box').html('Nie udało się odświeżyć historii:' + message).show();
+            _finalize(false);
         };
-          
-               function _success(doc, data) {
-               $('#history-view .message-box').hide();
+        
+        function _success(doc, data){
+            $('#history-view .message-box').hide();
             var changes_list = $('#changes-list');
-            var $stub = $('#history-view .row-stub');                
+            var $stub = $('#history-view .row-stub');
             changes_list.html('');
-                
+            
             $.each(data, function(){
-               $.wiki.renderStub(changes_list, $stub, this);                                                           
+                $.wiki.renderStub(changes_list, $stub, this);
             });
-                       
-                       $('span[data-version-tag]', changes_list).each(function() {
-                               $(this).text($(this).attr('data-version-tag'));                         
-                       });
-                       
-                       _finalize(true);                        
+            
+            $('span[data-version-tag]', changes_list).each(function(){
+                $(this).text($(this).attr('data-version-tag'));
+            });
+            
+            _finalize(true);
         };
+        
+        return this.doc.fetchHistory({
+            success: _success,
+            failure: _failure
+        });
+    };
+       
+       HistoryPerspective.prototype.showTagForm = function(){
+               var selected = $('#changes-list .entry.selected');
+               
+               if (selected.length != 1) {
+            window.alert("Musisz dokładnie jedną wersję do oznaczenia.");            
+            return;
+        }
                
-               return this.doc.fetchHistory({success: _success, failure: _failure});
-    };    
+               var version = parseInt($("*[data-stub-value='version']", selected[0]).text());
+               var dialog = $('#add_tag_dialog');
                
-       $.wiki.HistoryPerspective = HistoryPerspective;
+               $("input[name='version']", dialog).val(version);
+               
+               console.log($('form', dialog).serialize());
+               
+               $.blockUI({
+                       message: dialog
+               });
+       };
        
+       HistoryPerspective.prototype.makeDiff = function() {
+        var changelist = $('#changes-list');        
+        var selected = $('.entry.selected', changelist);
+        
+        if (selected.length != 2) {
+            window.alert("Musisz zaznaczyć dokładnie dwie wersje do porównania.");            
+            return;
+        }
+        
+        $.blockUI({
+            message: 'Wczytywanie porównania...'
+        });
+               
+               var rev_from = $("*[data-stub-value='version']", selected[1]).text();
+               var rev_to =  $("*[data-stub-value='version']", selected[0]).text();
+        
+        return this.doc.fetchDiff({
+            from: rev_from, 
+                       to: rev_to,            
+            success: function(doc, data){
+                var result = $.wiki.newTab(doc, ''+rev_from +' -> ' + rev_to, 'DiffPerspective');
+                               
+                               $(result.view).html(data);
+                               $.wiki.switchToTab(result.tab); 
+                               $.unblockUI();
+            },
+            failure: function(doc){
+                $.unblockUI();
+            }
+        });
+    };
+    
+    $.wiki.HistoryPerspective = HistoryPerspective;
+    
 })(jQuery);
index 802926c..ef127e3 100644 (file)
@@ -1,4 +1,3 @@
-
 if (!window.console) {
     window.console = {
         log: function(){
@@ -6,74 +5,30 @@ if (!window.console) {
     }
 }
 
-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'];
+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');             
-       var perspectives = {};
        var gallery = null;
-       var wikidoc = new $.wikiapi.WikiDocument("document-meta");
+       CurrentDocument = new $.wikiapi.WikiDocument("document-meta");
                
        $.blockUI.defaults.baseZ = 10000;
-       
-       function activePerspective() {
-               return perspectives[$("#tabs " + document.location.hash + "-tab").attr('data-ui-jsclass')];             
-       };
-               
+                       
     function initialize() 
        {               
-               gallery = new $.wiki.ScanGalleryPerspective(wikidoc);
+               gallery = new $.wiki.ScanGalleryPerspective({
+                       doc: CurrentDocument
+               });
                
                /* The save button */
         $('#save-button').click(function(event){
             event.preventDefault();
-            $.blockUI({
-                message: $('#save_dialog'),
-                               css: {
-                                       'top': '25%',
-                                       'left': '25%',
-                                       'width': '50%'
-                               }                               
-            });
-        });
-        
-        $('#save_dialog .ok-button').click(function(){
-            $.blockUI({
-                message: 'Zapisywanie...'
-            });
-                       
-                       var ap = activePerspective();
-                       
-                       /* exit perspective */
-                       ap.onExit();          
-                       
-                       function finalize() {
-                               ap.onEnter();
-                               $.unblockUI();
-                       };
-                       
-                       wikidoc.save({
-                               comment: $("#komentarz").text(),
-                               success: function(doc, changed, info){
-                                       console.log(info);
-                                       $.blockUI({
-                                               message: info
-                                       });
-                                       setTimeout(finalize, 2000);
-                               },
-                               failure: function(doc, info) {
-                                       console.log(info);
-                                       $.blockUI({
-                                               message: info
-                                       });
-                                       setTimeout(finalize, 3000);
-                               }
-                       });
-        });
-        
-        $('#save_dialog .cancel-button').click(function(){
-            $.unblockUI();
+                       $.wiki.showDialog('#save_dialog');            
         }); 
                                
                $('.editor').hide();   
@@ -81,20 +36,20 @@ $(function()
                /*
                 * TABS 
                 */             
-        tabs.click(function(event, callback) {
-                       /* hide old */
-            var $old = tabs.filter('.active');
-                                               
-                       $old.each(function(){
-                               $(this).removeClass('active');
-                               $('#' + $(this).attr('data-ui-related')).hide();
-                               perspectives[$(this).attr('data-ui-jsclass')].onExit();
-                       });                     
+        $('#tabs li').live('click', function(event, callback) {
+                       $.wiki.switchToTab(this);                       
+        });
+               
+               $('#tabs li > .tabclose').live('click', function(event, callback) {
+                       var $tab = $(this).parent();
+                       
+                       if($tab.is('.active'))
+                               $.wiki.switchToTab(DEFAULT_PERSPECTIVE);
+                               
+                       var p = $.wiki.perspectiveForTab($tab);
+                       p.destroy();
                        
-                       /* show new */                                          
-            $(this).addClass('active');
-            $('#' + $(this).attr('data-ui-related')).show();                   
-            perspectives[$(this).attr('data-ui-jsclass')].onEnter();
+                       return false;                   
         });
                        
         
@@ -121,18 +76,29 @@ $(function()
                        }
                );              
         
-        $(window).bind('beforeunload', function(event){
-            if(wikidoc.has_local_changes) return "Na stronie mogą być zmiany.";
-        });
+        window.onbeforeunload = function(e) {
+            if($.wiki.isDirty()) {
+                               e.returnValue = "Na stronie mogą być nie zapisane zmiany.";
+                               return "Na stronie mogą być nie zapisane zmiany.";
+                       };
+        };
                
                console.log("Fetching document's text");
                
-               wikidoc.fetch({
+               $(document).bind('wlapi_document_changed', function(event, doc) {
+                       try {
+                               $('#document-revision').text(doc.revision);
+                       } catch(e) {
+                               console.log("Failed handler", e);
+                       }
+               });
+               
+               CurrentDocument.fetch({
                        success: function(){
                                console.log("Fetch success");
                                $('#loading-overlay').fadeOut();                                
-                               var active_tab = document.location.hash || "#SummaryPerspective";
-                               var $active = $("#tabs " + active_tab + "-tab");
+                               var active_tab = document.location.hash || DEFAULT_PERSPECTIVE;
+                               var $active = $("#tabs " + active_tab);
                                
                                $active.trigger("click");
                        },
@@ -141,28 +107,25 @@ $(function()
                                alert("FAILURE");
                        }
                });
-                                               
+                               
+               $(window).resize();             
     }; /* end of initialize() */
        
        var initAll = function(a, f) {                          
                if (a.length == 0) return f();  
-                       
-               var klass = a.pop();
-               console.log("INIT", klass);             
-               var p = new $.wiki[klass](wikidoc, function() {
-                       perspectives[this.perspective_id] = this;                        
-                       initAll(a, f); 
-               });                                             
-               
+                               
+               $.wiki.initTab({
+                       tab: a.pop(),
+                       doc: CurrentDocument,                   
+                       callback: function(){                           
+                               initAll(a, f);
+                       }
+               });                                                             
        };
        
        /*
         * Initialize all perspectives 
         */
-       initAll($.makeArray( $('ol#tabs li').map(function(){
-                       return $(this).attr('data-ui-jsclass');                                         
-       })), initialize);
-       
-       console.log(location.hash);
-       
+       initAll( $.makeArray($('ol#tabs li')), initialize);
+       console.log(location.hash);     
 });
index 827b26b..2159a57 100644 (file)
@@ -5,36 +5,50 @@
 (function($) {
        
        function SaveDialog(element) {
-               $.wiki.cls.GenericDialog.call(this, element);
                this.ctx = $.wiki.exitContext();
+               this.clearForm();
+               
+               /* fill out hidden fields */
+               this.$form = $('form', element);
+               
+               $("input[name='id']", this.$form).val(CurrentDocument.id);
+               $("input[name='parent_revision']", this.$form).val(CurrentDocument.revision);
+               
+               $.wiki.cls.GenericDialog.call(this, element);           
        };
        
-       SaveDialog.prototype = new $.wiki.cls.GenericDialog();
+       SaveDialog.prototype = new $.wiki.cls.GenericDialog(); 
        
-       SaveDialog.prototype 
+       SaveDialog.prototype.cancelAction = function() {
+               $.wiki.enterContext(this.ctx);
+               this.hide();
+       };
        
        SaveDialog.prototype.saveAction = function() {
                        var self = this;                                
                        
                        self.$elem.block({
-                               message: "Zapisywanie..."
+                               message: "Zapisywanie...",
+                               fadeIn: 0,
                        });
                        
                        try {
                                
                                CurrentDocument.save({
-                                       comment: $("#komentarz").text(),
+                                       form: self.$form,
                                        success: function(doc, changed, info){
                                                self.$elem.block({
                                                        message: info,
-                                                       timeout: 1000,
+                                                       timeout: 2000,
                                                        fadeOut: 0, 
                                                        onUnblock: function() {                                                                                                                 
                                                                self.hide();
+                                                               $.wiki.enterContext(self.ctx);
                                                        }
                                                });
                                        },
                                        failure: function(doc, info) {
+                                               console.log("Failure", info);
                                                self.reportErrors(info);
                                                self.$elem.unblock();
                                        }                                       
index 1d496f1..7f646d7 100644 (file)
@@ -1,9 +1,8 @@
 (function($){
 
-    function normalizeNumber(number, length){
+    function normalizeNumber(pageNumber, pageCount){
         // Numer strony musi być pomiędzy 1 a najwyższym numerem
-        var pageCount = length;
-        pageNumber = parseInt(pageNumber, 10);
+        var pageNumber = parseInt(pageNumber, 10);
         
         if (!pageNumber ||
         pageNumber == NaN ||
     /*
      * Perspective
      */
-    function ScanGalleryPerspective(doc, callback){
-        var self = this;
-               
-               this.perspective_id = '';
-               this.doc = doc;
-        
-        this.dimensions = {};
-        this.zoomFactor = 1;
-        this.$element = $("#side-gallery");
-        this.$numberInput = $('.page-number', this.$element);
-        
-        // ...
-        var origin = {};
-        var imageOrigin = {};
-        
-        this.$image = $('.gallery-image img', this.$element).attr('unselectable', 'on');
-        
-        // button handlers
-        this.$numberInput.change(function(event){
-            event.preventDefault();
-            self.setPage($(this).val());
-        });
-        
-        $('.previous-page', this.$element).click(function(){
-            self.setPage(self.$numberInput.val() - 1);
-        });
-        
-        $('.nexy-page', this.$element).click(function(){
-            self.setPage(self.$numberInput.val() + 1);
-        });        
-        
-        $('.zoom-in', this.$element).click(function(){
-            self.alterZoom(0.2);
-        });
-        
-        $('.zoom-out', this.$element).click(function(){
-            self.alterZoom(-0.2);
-        });
-        
-        $(window).resize(function(){
-            self.dimensions.galleryWidth = self.$image.parent().width();
-            self.dimensions.galleryHeight = self.$image.parent().height();
-        });
+    function ScanGalleryPerspective(options){
+        var old_callback = options.callback || function() { };
+        
+        options.callback = function(){
+            var self = this;
+            
+            this.dimensions = {};
+            this.zoomFactor = 1;
+            this.$element = $("#side-gallery");
+            this.$numberInput = $('.page-number', this.$element);
+            
+            // ...
+            var origin = {};
+            var imageOrigin = {};
+            
+            this.$image = $('.gallery-image img', this.$element).attr('unselectable', 'on');
+            
+            // button handlers
+            this.$numberInput.change(function(event){
+                event.preventDefault();
+                self.setPage($(this).val());
+            });
+            
+            $('.previous-page', this.$element).click(function(){
+                self.setPage(parseInt(self.$numberInput.val(),10) - 1);
+            });
+            
+            $('.next-page', this.$element).click(function(){
+                self.setPage(parseInt(self.$numberInput.val(),10) + 1);
+            });
+            
+            $('.zoom-in', this.$element).click(function(){
+                self.alterZoom(0.2);
+            });
+            
+            $('.zoom-out', this.$element).click(function(){
+                self.alterZoom((-0.2));
+            });
+            
+            $(window).resize(function(){
+                self.dimensions.galleryWidth = self.$image.parent().width();
+                self.dimensions.galleryHeight = self.$image.parent().height();
+            });
+            
+            $('.gallery-image img', this.$element).load(function(){
+                console.log("Image loaded.")
+                self._resizeImage();
+            }).bind('mousedown', function() {
+                               self.imageMoveStart.apply(self, arguments);
+                       });
+            
+                       old_callback.call(this);
+        };
         
-        $('.gallery-image img', this.$element).load(function(){
-                       console.load("Image loaded.")
-            self._resizeImage();
-        });
+        $.wiki.Perspective.call(this, options);
     };
     
     ScanGalleryPerspective.prototype = new $.wiki.Perspective();
             width: $img.width() * this.zoomFactor,
             height: $img.height() * this.zoomFactor,
             originWidth: $img.width(),
-            originHeight: $img.height(),
-            galleryWidth: $img.parent().width(),
+            originHeight: $img.height(),          
+                   galleryWidth: $img.parent().width(),
             galleryHeight: $img.parent().height()
         };
         
     };
     
     ScanGalleryPerspective.prototype.setPage = function(newPage){
-        newPage = normalizeNumber(newPage, this.$image.length);
+        newPage = normalizeNumber(newPage, this.doc.galleryImages.length);
         this.$numberInput.val(newPage);
         $('.gallery-image img', this.$element).attr('src', this.doc.galleryImages[newPage - 1]);
     };
         this.dimensions.width = this.dimensions.originWidth * this.zoomFactor;
         this.dimensions.height = this.dimensions.originHeight * this.zoomFactor;
         
-        var position = normalizePosition(this.$image.position().left, this.$image.position().top, this.dimensions.galleryWidth, this.dimensions.galleryHeight, this.dimensions.width, this.dimensions.height);
+        // var position = normalizePosition(this.$image.position().left, this.$image.position().top, this.dimensions.galleryWidth, this.dimensions.galleryHeight, this.dimensions.width, this.dimensions.height);
         
-        this.$image.css({
+               this._resizeImage();
+        /* this.$image.css({
             width: this.dimensions.width,
             height: this.dimensions.height,
             left: position.x,
             top: position.y
-        });
+        });*/
     };
+       
+       /*
+        * Movement
+        */
+       ScanGalleryPerspective.prototype.imageMoved = function(event){
+               event.preventDefault();
+               
+               // origin is where the drag started
+               // imageOrigin is where the drag started on the image
+               
+               var newX = event.clientX - this.origin.x + this.imageOrigin.left;
+               var newY = event.clientY - this.origin.y + this.imageOrigin.top;
+               
+               var position = normalizePosition(newX, newY, this.dimensions.galleryWidth, this.dimensions.galleryHeight, this.dimensions.width, this.dimensions.height);
+               
+               this.$image.css({
+                       left: position.x,
+                       top: position.y,
+               });
+               
+               return false;
+       };
+       
+       ScanGalleryPerspective.prototype.imageMoveStart = function(event){
+               event.preventDefault();
+               
+               var self = this;
+               
+               this.origin = {
+                       x: event.clientX,
+                       y: event.clientY
+               };
+               
+               this.imageOrigin = self.$image.position();
+               $(document).bind('mousemove.gallery', function(){
+                       self.imageMoved.apply(self, arguments);
+               }).bind('mouseup.gallery', function() {
+                       self.imageMoveStop.apply(self, arguments); 
+               });
+               
+               return false;
+       };
+       
+       ScanGalleryPerspective.prototype.imageMoveStop = function(event){
+               $(document).unbind('mousemove.gallery').unbind('mouseup.gallery');
+       };
     
     /*
      * Loading gallery
      */
     ScanGalleryPerspective.prototype.onEnter = function(success, failure){
-               var self = this;
-               
-        $.wiki.Perspective.prototype.onEnter.call(this);        
+        var self = this;
         
-               this.doc.refreshGallery({
-                       success: function(doc, data) {
-                               self.$image.show();
-                               $('.error_message', self.$element).hide();
-                               success();                              
-                       },
-                       failure: function(doc, message) {
-                               self.$image.hide();
-                               $('.error_message', self.$element).show().html(message);
-                               failure();                              
-                       }                        
-               });
+        $.wiki.Perspective.prototype.onEnter.call(this);
+        
+        this.doc.refreshGallery({
+            success: function(doc, data){
+                self.$image.show();
+                               self.setPage( self.$numberInput.val() );
+                               
+                $('.error_message', self.$element).hide();
+                if(success) success();
+            },
+            failure: function(doc, message){
+                self.$image.hide();
+                $('.error_message', self.$element).show().html(message);
+                if(failure) failure();
+            }
+        });
     };
     
     $.wiki.ScanGalleryPerspective = ScanGalleryPerspective;
-})(jQuery);
-
-
-/*
-
-
- function onMouseMove(event){
-
-
- var position = normalizePosition(event.clientX - origin.x + imageOrigin.left, event.clientY - origin.y + imageOrigin.top, imageDimensions.galleryWidth, imageDimensions.galleryHeight, imageDimensions.width, imageDimensions.height);
-
-
- image.css({
-
-
- position: 'absolute',
-
-
- top: position.y,
-
-
- left: position.x
-
-
- });
-
-
- return false;
-
-
- }
-
-
- function onMouseUp(event){
-
-
- $(document).unbind('mousemove.gallery').unbind('mouseup.gallery');
-
-
- return false;
-
-
- }
-
-
- image.bind('mousedown', function(event){
-
-
- origin = {
-
-
- x: event.clientX,
-
-
- y: event.clientY
-
-
- };
-
-
- imageOrigin = image.position();
-
-
- $(document).bind('mousemove.gallery', onMouseMove).bind('mouseup.gallery', onMouseUp);
-
-
- return false;
-
-
- });
-
-
- if (url) {
-
-
- updateGallery(url);
-
-
- }
-
-
- }*/
-
-
+       
+})(jQuery);
\ No newline at end of file
index 0f67110..9ca3f64 100644 (file)
@@ -1,49 +1,51 @@
 /* COMMENT */
 (function($) {
        
-       function CodeMirrorPerspective(doc, callback
+       function CodeMirrorPerspective(options
        {
-               this.perspective_id = 'CodeMirrorPerspective';
-               this.doc = doc; // document model
-               
-               var self = this;
-               
-               this.codemirror = CodeMirror.fromTextArea('codemirror_placeholder', {                   
-                       parserfile: 'parsexml.js',
-                       path: STATIC_URL + "js/lib/codemirror/",
-                       stylesheet: STATIC_URL + "css/xmlcolors_15032010.css",
-                       parserConfig: {
-                               useHTMLKludges: false
-                       },
-                       iframeClass: 'xml-iframe',
-                       textWrapping: true,
-                       lineNumbers: true,
-                       width: "100%",
-                       tabMode: 'spaces',
-                       indentUnit: 0,
-                       initCallback: function() {
-                               $('#source-editor .toolbar button').click(function(event){
-                   event.preventDefault();
-                   var params = eval("(" + $(this).attr('data-ui-action-params') + ")");
-                       scriptletCenter.scriptlets[$(this).attr('data-ui-action')](self.codemirror, params);
-                       });
-               
-                       $('.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();          
+               var old_callback = options.callback;        
+        options.callback = function(){         
+                       var self = this;
+                       
+                       this.codemirror = CodeMirror.fromTextArea('codemirror_placeholder', {
+                               parserfile: 'parsexml.js',
+                               path: STATIC_URL + "js/lib/codemirror/",
+                               stylesheet: STATIC_URL + "css/xmlcolors_15032010.css",
+                               parserConfig: {
+                                       useHTMLKludges: false
+                               },
+                               iframeClass: 'xml-iframe',
+                               textWrapping: true,
+                               lineNumbers: false,
+                               width: "100%",
+                               tabMode: 'spaces',
+                               indentUnit: 0,
+                               initCallback: function(){
+                                       $('#source-editor .toolbar button').click(function(event){
+                                               event.preventDefault();
+                                               var params = eval("(" + $(this).attr('data-ui-action-params') + ")");
+                                               scriptletCenter.scriptlets[$(this).attr('data-ui-action')](self.codemirror, params);
+                                       });
+                                       
+                                       $('.toolbar select').change(function(event){
+                                               var slug = $(this).val();
                                                
-                               console.log("Initialized CodeMirror");
-                               // textarea is no longer needed
-                               $('codemirror_placeholder').remove();
-                               callback.call(self);
-                       }       
-               });
+                                               $('.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
+                                       $('codemirror_placeholder').remove();
+                                       old_callback.call(self);
+                               }
+                       });     
+               };
+               
+               $.wiki.Perspective.call(this, options);
        };
        
        
@@ -56,7 +58,7 @@
        CodeMirrorPerspective.prototype.onEnter = function(success, failure) {
                $.wiki.Perspective.prototype.onEnter.call(this);
        
-               console.log(this.doc);
+               console.log('Entering', this.doc);
                this.codemirror.setCode(this.doc.text);
                if(success) success();
        }
@@ -64,7 +66,7 @@
        CodeMirrorPerspective.prototype.onExit = function(success, failure) {
                $.wiki.Perspective.prototype.onExit.call(this);
        
-               console.log(this.doc);
+               console.log('Exiting', this.doc);
                this.doc.setText(this.codemirror.getCode());
                if(success) success();
        }
index bed8155..35f03f7 100644 (file)
@@ -1,10 +1,12 @@
 (function($){
        
-       function SummaryPerspective(doc, callback) {
-               this.perspective_id = 'SummaryPerspective';
-               this.doc = doc;
+       function SummaryPerspective(options) {
+               var old_callback = options.callback;        
+        options.callback = function(){
+                       old_callback.call(this);
+               };              
                
-               callback.call(this);
+               $.wiki.Perspective.call(this, options);
     };
     
     SummaryPerspective.prototype = new $.wiki.Perspective();
index ee444ca..9bf5555 100644 (file)
 //             this._context_lock = -1;
 //             return old;
 //     };
+
+       WikiDocument.prototype.triggerDocumentChanged = function() {
+               $(document).trigger('wlapi_document_changed', this);            
+       };
        
        /*
         * Fetch text of this document.
                                        self.revision = data.revision;
                                        self.gallery = data.gallery;                                    
                                        changed = true;
+                                       self.triggerDocumentChanged();          
                                }
                                
                                self.has_local_changes = false;                         
        };
        
        WikiDocument.prototype.fetchDiff = function(params) {           
-               /* this doesn't modify anything, so no locks */         
+               /* this doesn't modify anything, so no locks */
+               var self = this;
+                               
                params = $.extend({
                        'from': self.revision, 
                        'to': self.revision
                }, noops, params);
                                        
-               var self = this;        
-                                       
                $.ajax({                        
                        method: "GET",
                        url: reverse("ajax_document_diff", self.id),
-                       dataType: 'json',
+                       dataType: 'html',
                        data: {"from": params['from'], "to": params['to']},
                        success: function(data) {
                                params['success'](self, data);
                        dataType: 'json',
                        // data: {},
                        success: function(data) {
-                               this.galleryImages = data.images;
-                               params['success'](self, data);
+                               self.galleryImages = data;
+                               params['success'](self, data);                          
                        },
                        error: function() {
-                               this.galleryImages = [];        
+                               self.galleryImages = [];        
                                params['failure'](self, "<p>Nie udało się wczytać gallerii pod nazwą: '"
                                        + self.galleryLink + "'.</p>");
                                                        
        /*
         * Set document's text
         */
-       WikiDocument.prototype.setText = function(text) {
-               if (this.text != text) {
-                       this.text = text;
-                       this.has_local_changes = true;
-               }                       
+       WikiDocument.prototype.setText = function(text) {               
+               this.text = text;
+               this.has_local_changes = true;                                  
        };
        
        /*
         * Save text back to the server
         */
        WikiDocument.prototype.save = function(params){
-               params = $.extend({'comment': 'No comment.'}, noops, params);
+               params = $.extend({}, noops, params);
                var self = this;
-               
-               /* you can't set text while some is fetching it (or saving) */
-               
+                               
                if (!self.has_local_changes) {
                        console.log("Abort: no changes.");
                        return params['success'](self, false, "Nie ma zmian do zapisania.");
                };              
                
+               // Serialize form to dictionary
+               var data = {};          
+               $.each(params['form'].serializeArray(), function() {
+                       data[this.name] = this.value;                   
+               });
+               
                var metaComment = '<!--';
                metaComment += '\n\tgallery:' + self.galleryLink;
                metaComment += '\n-->\n'
                
-               var data = {
-                       name: self.id,
-                       text: metaComment + self.text,
-                       parent_revision: self.revision,
-                       comment: params['comment'],
-               };
+               data.text = metaComment + self.text;
+               data.comment = data.comment; 
                
                $.ajax({
                        url: reverse("ajax_document_text", self.id),
                                        self.revision = data.revision;
                                        self.gallery = data.gallery;
                                        changed = true;
+                                       self.triggerDocumentChanged();
                                }
-                               params['success'](self, changed, "Zapisano");
+                               params['success'](self, changed, 
+                                       ((changed && "Udało się zapisać :)") || "Twoja wersja i serwera jest identyczna") );
                        },
-                       error: function() {
-                               params['failure'](self, "Nie udało się zapisać.");
+                       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>"});                            
+                               };
                        }
                });             
        }; /* end of save() */
        
+       WikiDocument.prototype.setTag = function(params) {
+               
+       };
+       
+       
        $.wikiapi.WikiDocument = WikiDocument;
        
 })(jQuery);
index 4a84e9d..eba8695 100644 (file)
             });
         }
         
-        $('.delete-button', $overlay).click(function(){
-            if ($origin.is('.motyw')) {
-                $('[theme-class=' + $origin.attr('theme-class') + ']').remove();
-            }
-            else {
-                $origin.remove();
-            }
-            $overlay.remove();
-            $(document).unbind('click.blur-overlay');
-            return false;
-        })
+               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();
+                                       $overlay.remove();
+                                       $(document).unbind('click.blur-overlay');
+                                       return false;
+                               };
+            });
+               }
+               else {
+                       $('.delete-button', $overlay).hide();
+               }
         
         
         var serializer = new XMLSerializer();
             }
         });
     }
-           
-    function VisualPerspective(doc, callback) 
-       {
-               this.perspective_id = 'VisualPerspective';
-               this.doc = doc;
+    
+    function VisualPerspective(options){
                
-               var element = $("html-view");           
-               var button = $('<button class="edit-button">Edytuj</button>');
+        var old_callback = options.callback;
                
-        $('#html-view').bind('mousemove', function(event){
-            var editable = $(event.target).closest('*[x-editable]');
-            $('.active[x-editable]', element).not(editable).removeClass('active').children('.edit-button').remove();
-            if (!editable.hasClass('active')) {
-                editable.addClass('active').append(button);
-            }
-            if (editable.is('.annotation-inline-box')) {
-                $('*[x-annotation-box]', editable).css({
-                    position: 'absolute',
-                    left: event.clientX - editable.offset().left + 5,
-                    top: event.clientY - editable.offset().top + 5
-                }).show();
-            }
-            else {
-                $('*[x-annotation-box]').hide();
-            }
-        });
-        
-        $('.motyw').live('click', function(){
-            selectTheme($(this).attr('theme-class'));
-        });
-        
-        $('#insert-annotation-button').click(function(){
-            addAnnotation();
-            return false;
-        });
-        
-        $('#insert-theme-button').click(function(){
-            addTheme();
-            return false;
-        });
+        options.callback = function() {       
+            var element = $("#html-view");
+            var button = $('<button class="edit-button">Edytuj</button>');
+            
+            $('#html-view').bind('mousemove', function(event){
+                var editable = $(event.target).closest('*[x-editable]');
+                $('.active', element).not(editable).removeClass('active').children('.edit-button').remove();
+                
+                               if (!editable.hasClass('active')) {
+                    editable.addClass('active').append(button);
+                }
+                if (editable.is('.annotation-inline-box')) {
+                    $('*[x-annotation-box]', editable).css({
+                        position: 'absolute',
+                        left: event.clientX - editable.offset().left + 5,
+                        top: event.clientY - editable.offset().top + 5
+                    }).show();
+                }
+                else {
+                    $('*[x-annotation-box]').hide();
+                }
+            });
+            
+            $('.motyw').live('click', function(){
+                selectTheme($(this).attr('theme-class'));
+            });
+            
+            $('#insert-annotation-button').click(function(){
+                addAnnotation();
+                return false;
+            });
+            
+            $('#insert-theme-button').click(function(){
+                addTheme();
+                return false;
+            });
+            
+            $('.edit-button').live('click', function(event){
+                event.preventDefault();
+                openForEdit($(this).parent());
+            });
+                       
+                       old_callback.call(this);
+        };
         
-        $('.edit-button').live('click', function(event){
-            event.preventDefault();
-            openForEdit($(this).parent());
-        });
-               
-               callback.call(this);
+        $.wiki.Perspective.call(this, options);
     };
     
     VisualPerspective.prototype = new $.wiki.Perspective();
-       
-    VisualPerspective.prototype.freezeState = function() {
+    
+    VisualPerspective.prototype.freezeState = function(){
     
     };
-       
-       VisualPerspective.prototype.onEnter = function(success, failure) 
-       {
-               $.wiki.Perspective.prototype.onEnter.call(this);
-               
+    
+    VisualPerspective.prototype.onEnter = function(success, failure){
+        $.wiki.Perspective.prototype.onEnter.call(this);
+        
         $.blockUI({
             message: 'Uaktualnianie widoku...'
         });
-               
-               function _finalize(callback) {
-                       $.unblockUI();
-                       if (callback) callback();                
-               } 
-               
+        
+        function _finalize(callback){
+            $.unblockUI();
+            if (callback) 
+                callback();
+        }
+        
         xml2html({
             xml: this.doc.text,
             success: function(element){
                 $('#html-view').html(element);
                 _finalize(success);
             },
-            error: function(text) {
+            error: function(text){
                 var message = $('<pre></pre>');
                 message.text(text);
                 $('#html-view').html('<p class="error">Wystąpił błąd:</p><pre>' +
                 message.html() +
-                '</pre>');                                                             
-                               _finalize(failure);
+                '</pre>');
+                _finalize(failure);
             }
-        });   
-       };
-       
-       VisualPerspective.prototype.onExit = function(success, failure) 
-       {
-               var self = this;
-               
+        });
+    };
+    
+    VisualPerspective.prototype.onExit = function(success, failure){
+        var self = this;
+        
         $.blockUI({
             message: 'Zapisywanie widoku...'
-        });    
-               
-               function _finalize(callback) {
-                       $.unblockUI();
-                       if (callback) callback();                
-               }
-               
-               if ($('#html-view .error').length > 0) 
-                       return _finalize(failure);        
-               
+        });
+        
+        function _finalize(callback){
+            $.unblockUI();
+            if (callback) 
+                callback();
+        }
+        
+        if ($('#html-view .error').length > 0) 
+            return _finalize(failure);
+        
         html2text({
             element: $('#html-view div').get(0),
-            success: function(text) {
+            success: function(text){
                 self.doc.setText(text);
                 _finalize(success);
             },
-            error: function(text) {                
-                $('#source-editor').html('<p>Wystąpił błąd:</p><pre>' + text + '</pre>');                                          
-                               _finalize(failure);
+            error: function(text){
+                $('#source-editor').html('<p>Wystąpił błąd:</p><pre>' + text + '</pre>');
+                _finalize(failure);
             }
-        });   
-       };
-       
-       $.wiki.VisualPerspective = VisualPerspective;    
+        });
+    };
+    
+    $.wiki.VisualPerspective = VisualPerspective;
     
 })(jQuery);
index cb518a3..ac728d0 100644 (file)
@@ -11,8 +11,7 @@
        <div id="body-wrap">
         <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>
+       <!-- <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" type="text/javascript"></script> -->
     {% block extrabody %}{% endblock %}
     </body>
 </html>