Merge branch 'master' of stigma.nowoczesnapolska.org.pl:platforma
authorzuber <marek@stepniowski.com>
Sat, 10 Oct 2009 23:10:20 +0000 (01:10 +0200)
committerzuber <marek@stepniowski.com>
Sat, 10 Oct 2009 23:10:20 +0000 (01:10 +0200)
Conflicts:
fabfile.py

23 files changed:
apps/api/handlers/library_handlers.py
apps/api/handlers/manage_handlers.py
apps/api/handlers/toolbar_handlers.py
apps/api/urls.py
apps/explorer/views.py
apps/toolbar/models.py
fabfile.py
lib/wlrepo/mercurial_backend/__init__.py
lib/wlrepo/mercurial_backend/document.py
project/settings.py
project/static/css/html_print.css [new file with mode: 0644]
project/static/css/managment.css [new file with mode: 0644]
project/static/js/app.js
project/static/js/models.js
project/static/js/views/button_toolbar.js
project/static/js/views/editor.js
project/static/js/views/html.js
project/static/js/views/split.js
project/static/js/views/xml.js
project/templates/explorer/editor.html
project/templates/html4print.html
project/templates/manager/pull_request.html
project/urls.py

index 4435fe9..488c2d4 100644 (file)
@@ -38,6 +38,7 @@ log = logging.getLogger('platforma.api')
 #
 # Document List Handlers
 #
+# TODO: security check
 class BasicLibraryHandler(AnonymousBaseHandler):
     allowed_methods = ('GET',)
 
@@ -51,10 +52,14 @@ class BasicLibraryHandler(AnonymousBaseHandler):
         return {'documents' : document_list}
         
 
+#
+# This handler controlls the document collection
+#
 class LibraryHandler(BaseHandler):
     allowed_methods = ('GET', 'POST')
     anonymous = BasicLibraryHandler
 
+
     @hglibrary
     def read(self, request, lib):
         """Return the list of documents."""
@@ -138,12 +143,15 @@ class LibraryHandler(BaseHandler):
                 lock.release()
         except LibraryException, e:
             import traceback
-            return response.InternalError().django_response(\
-                {'exception': traceback.format_exc()} )
+            return response.InternalError().django_response({
+                "reason": traceback.format_exc()
+            })
         except DocumentAlreadyExists:
             # Document is already there
-            return response.EntityConflict().django_response(\
-                {"reason": "Document %s already exists." % docid})
+            return response.EntityConflict().django_response({
+                "reason": "already-exists",
+                "message": "Document already exists." % docid
+            })
 
 #
 # Document Handlers
@@ -216,7 +224,7 @@ class DocumentHTMLHandler(BaseHandler):
     allowed_methods = ('GET')
 
     @hglibrary
-    def read(self, request, docid, lib):
+    def read(self, request, docid, lib, stylesheet='partial'):
         """Read document as html text"""
         try:
             revision = request.GET.get('revision', 'latest')
@@ -231,7 +239,7 @@ class DocumentHTMLHandler(BaseHandler):
                     'message': 'Provided revision refers, to document "%s", but provided "%s"' % (document.id, docid) })
 
             return librarian.html.transform(document.data('xml'), is_file=False, \
-                parse_dublincore=False, stylesheet="partial",\
+                parse_dublincore=False, stylesheet=stylesheet,\
                 options={
                     "with-paths": 'boolean(1)',                    
                 })
@@ -318,7 +326,8 @@ class DocumentTextHandler(BaseHandler):
                 # we're done :)
                 return document.data('xml')
             else:
-                xdoc = parser.WLDocument.from_string(document.data('xml'))
+                xdoc = parser.WLDocument.from_string(document.data('xml'),\
+                    parse_dublincore=False)
                 ptext = xdoc.part_as_text(part)
 
                 if ptext is None:
@@ -547,33 +556,35 @@ class MergeHandler(BaseHandler):
                     "provided": target_rev,
                     "latest": udoc.revision })
 
-        if not request.user.has_perm('explorer.document.can_share'):
-            # User is not permitted to make a merge, right away
-            # So we instead create a pull request in the database
-            try:
-                prq, created = PullRequest.get_or_create(                                        
-                    source_revision = str(udoc.revision),
-                    defaults = {
-                        'comitter': request.user,
-                        'document': docid,
-                        'status': "N",
-                        'comment': form.cleaned_data['message'] or '$AUTO$ Document shared.',
-                    }
-                )
-
-                return response.RequestAccepted().django_response(\
-                    ticket_status=prq.status, \
-                    ticket_uri=reverse("pullrequest_view", args=[prq.id]) )
-            except IntegrityError, e:
-                return response.InternalError().django_response()
-
         if form.cleaned_data['type'] == 'update':
             # update is always performed from the file branch
             # to the user branch
             success, changed = udoc.update(request.user.username)
 
-        if form.cleaned_data['type'] == 'share':
-            success, changed = udoc.share(form.cleaned_data['message'])
+        if form.cleaned_data['type'] == 'share':        
+            if not request.user.has_perm('explorer.document.can_share'):
+                # User is not permitted to make a merge, right away
+                # So we instead create a pull request in the database
+                try:
+                    prq, created = PullRequest.objects.get_or_create(
+                        source_revision = str(udoc.revision),
+                        defaults = {
+                            'comitter': request.user,
+                            'document': docid,
+                            'status': "N",
+                            'comment': form.cleaned_data['message'] or '$AUTO$ Document shared.',
+                        }
+                    )
+
+                    return response.RequestAccepted().django_response(\
+                        ticket_status=prq.status, \
+                        ticket_uri=reverse("pullrequest_view", args=[prq.id]) )
+                except IntegrityError:
+                    return response.EntityConflict().django_response({
+                        'reason': 'request-already-exist'
+                    })
+            else:
+                success, changed = udoc.share(form.cleaned_data['message'])
 
         if not success:
             return response.EntityConflict().django_response({
index 9615958..b3e2760 100644 (file)
@@ -6,7 +6,9 @@ __doc__ = "Module documentation."
 
 from piston.handler import BaseHandler, AnonymousBaseHandler
 
+from api.utils import hglibrary
 from explorer.models import PullRequest
+from api.response import *
 
 class PullRequestListHandler(BaseHandler):
     allowed_methods = ('GET',)
@@ -19,7 +21,64 @@ class PullRequestListHandler(BaseHandler):
 
 
 class PullRequestHandler(BaseHandler):
-    allowed_methods = ('GET',)
+    allowed_methods = ('GET', 'PUT')
 
     def read(self, request, prq_id):
-        return PullRequest.objects.get(id=prq_id)    
\ No newline at end of file
+        return PullRequest.objects.get(id=prq_id)
+
+    def update(self, request, prq_id):
+        """Change the status of request"""
+
+        if not request.user.has_perm('explorer.document.can_share'):
+            return AccessDenied().django_response("Insufficient priviliges")
+        
+        prq = PullRequest.objects.get(id=prq_id)
+
+        if not prq:
+            return EntityNotFound().django_response()
+
+
+        action = request.PUT.get('action', None)
+
+        if action == 'accept' and prq.status == 'N':
+            return self.accept_merge(prq)
+        elif action == 'reject' and prq.status in ['N', 'R']:
+            return self.reject_merge(prq)
+        else:
+            return BadRequest().django_response()
+
+
+    @hglibrary
+    def accept_merge(self, prq, lib):        
+        doc = lib.document( prq.document )
+        udoc = doc.take( prq.comitter.username )
+        success, changed = udoc.share(prq.comment)
+
+        if not success:
+            return EntityConflict().django_response()
+
+        doc = doc.latest()
+
+        prq.status = 'A'
+        prq.merged_revisions = unicode(doc.revision)
+        prq.save()
+        
+        return SuccessAllOk().django_response({
+            'status': prq.status
+        })
+
+    
+    def reject_merge(self, prq, lib):
+        prq.status = 'R'
+        prq.save()
+
+        return SuccessAllOk().django_response({
+            'status': prq.status
+        })
+        
+
+        
+
+
+        
+
index be77359..5408db3 100644 (file)
@@ -17,9 +17,7 @@ class ToolbarHandler(BaseHandler):
 
     def read(self, request):
         groups = toolbar.models.ButtonGroup.objects.all()
-        return [ {'name': g.name, 'position': g.position,\
-            'buttons': g.button_set.all()} for g in groups ]
-            
+        return [g.to_dict(with_buttons=True) for g in groups]
             
 class ScriptletsHandler(BaseHandler):
     allowed_methods = ('GET',)
index deac319..5464374 100644 (file)
@@ -30,11 +30,11 @@ urlpatterns = patterns('',
 
     # Pull requests
     url(r"^pull-requests$", pullrequest_collection,
-        {'emitter_format': 'json'} ),
+        {'emitter_format': 'json'}, name="pullrequest_list" ),
         
     url(r"^pull-requests/(?P<prq_id>\d+)$", pullrequest_rsrc,
-        {'emitter_format': 'json'}, name="pullrequest_view" ),    
-    
+        {'emitter_format': 'json'}, name="pullrequest_view" ),
+        
     # Documents
     url(r'^documents$', library_resource,
         {'emitter_format': 'json'}, name="document_list_view"),
index 7a42b43..124a574 100644 (file)
@@ -116,6 +116,8 @@ def file_upload(request, repo):
 @login_required
 def print_html(request, **kwargs):
     from api.resources import document_html_resource
+
+    kwargs['stylesheet'] = 'legacy'
     
     output = document_html_resource.handler.read(request, **kwargs)
 
@@ -145,6 +147,14 @@ def _get_issues_for_file(fileid):
 # =================
 # = Pull requests =
 # =================
-#def pull_requests(request):
-#    return direct_to_template(request, 'manager/pull_request.html', extra_context = {
-#        'objects': models.PullRequest.objects.all()} )
+def pull_requests(request):
+    from explorer.models import PullRequest
+
+    objects = PullRequest.objects.order_by('status')
+
+    if not request.user.has_perm('explorer.book.can_share'):
+        objects = objects.filter(comitter=request.user)
+
+    
+    return direct_to_template(request, 'manager/pull_request.html', 
+        extra_context = {'objects': objects} )
index 0414622..1b986c3 100644 (file)
@@ -14,6 +14,13 @@ class ButtonGroup(models.Model):
     def __unicode__(self):
         return self.name
 
+    def to_dict(self, with_buttons=False):
+        d = {'name': self.name, 'position': self.position}
+
+        if with_buttons:
+            d['buttons'] = [ b.to_dict() for b in self.button_set.all() ]
+
+        return d
 
 #class ButtonGroupManager(models.Manager):
 #
@@ -67,8 +74,18 @@ class Button(models.Model):
         if self.key_mod & 0x01: mods.append('Alt')
         if self.key_mod & 0x02: mods.append('Ctrl')
         if self.key_mod & 0x04: mods.append('Shift')
-        mods.append('"'+self.key+'"')
-        return '+'.join(mods)
+        mods.append(str(self.key))
+        return '[' + '+'.join(mods) + ']'
+
+    def to_dict(self):
+        return {
+            'label': self.label,
+            'tooltip': (self.tooltip or '') + self.hotkey_name(),
+            'key': self.key,
+            'key_mod': self.key_mod,
+            'params': self.params,
+            'scriptlet_id': self.scriptlet_id
+        }
     
     def __unicode__(self):
         return self.label
index c06c50b..6304aae 100644 (file)
@@ -1,4 +1,6 @@
-from fabric.api import run, local, settings, abort, env, cd, require, abort
+from __future__ import with_statement
+from fabric.api import *
+
 
 def staging():
     '''Use staging server'''
index f919e81..630939f 100644 (file)
@@ -79,6 +79,7 @@ class MercurialRevision(wlrepo.Revision):
         return bool(self._library._hgrepo.changelog.children(self.hgrev()))
 
     def merge_with(self, other, user, message):
+        message = self._library._sanitize_string(message)
         lock = self._library.lock(True)
         try:
             self._library._checkout(self._changectx.node())
index e714561..a8f7adc 100644 (file)
@@ -115,7 +115,8 @@ class MercurialDocument(wlrepo.Document):
                 return (True, False)
 
 
-            return self._revision.merge_with(sv._revision, user=user)
+            return self._revision.merge_with(sv._revision, user=user,
+                message="$AUTO$ Personal branch update.")
         finally:
             lock.release()  
 
@@ -160,6 +161,9 @@ class MercurialDocument(wlrepo.Document):
                 if not local.parentof(main):
                     success, changed = main.merge_with(local, user=user, message=message)
 
+                success = True
+                changed = False
+
             # Case 3:
             # main *
             #      |
@@ -179,6 +183,9 @@ class MercurialDocument(wlrepo.Document):
                 if not local.parentof(main):
                     success, changed = local.merge_with(main, user=user, \
                         message='$AUTO$ Local branch update during share.')
+
+                success = True
+                changed = False
                     
             else:
                 print "case 4"
index 143f292..3a1f3ad 100644 (file)
@@ -8,6 +8,7 @@ TEMPLATE_DEBUG = DEBUG
 
 ADMINS = (
     (u'Marek Stępniowski', 'marek@stepniowski.com'),
+    (u'Łukasz Rekucki', 'lrekucki@gmail.com'),
 )
 
 MANAGERS = ADMINS
@@ -30,8 +31,8 @@ TIME_ZONE = 'Europe/Warsaw Poland'
 # http://www.i18nguy.com/unicode/language-identifiers.html
 LANGUAGE_CODE = 'pl'
 
-import locale
-locale.setlocale(locale.LC_ALL, '')
+#import locale
+#locale.setlocale(locale.LC_ALL, '')
 
 SITE_ID = 1
 
@@ -115,7 +116,8 @@ INSTALLED_APPS = (
     'django.contrib.sites',
     'django.contrib.admin',
     'django.contrib.admindocs',
-    
+
+    'piston',
     'explorer',
     'toolbar',
     'api',
diff --git a/project/static/css/html_print.css b/project/static/css/html_print.css
new file mode 100644 (file)
index 0000000..38cb596
--- /dev/null
@@ -0,0 +1,229 @@
+/* Style widoku HTML. Nie należy tu ustawiać position ani marginesów */
+.htmlview {
+    font-size: 16px;
+    font: Georgia, "Times New Roman", serif;
+    line-height: 1.5em;
+    padding: 3em;    
+}
+
+.htmlview div {
+    max-width: 36em;
+}
+
+.htmlview #toc {
+    display: none;
+}
+
+.htmlview a {
+    color: blue;
+    text-decoration: none;
+}
+
+.htmlview h1 {
+    font-size: 3em;
+    margin: 1.5em 0;
+    text-align: center;
+    line-height: 1.5em;
+    font-weight: bold;
+}
+
+.htmlview h2 {
+    font-size: 2em;
+    margin: 1.5em 0 0;
+    font-weight: bold;
+    line-height: 1.5em;
+}
+
+.htmlview h3 {
+    font-size: 1.5em;
+    margin: 1.5em 0 0;
+    font-weight: normal;
+    line-height: 1.5em;
+}
+
+.htmlview h4 {
+    font-size: 1em;
+    margin: 1.5em 0 0;
+    line-height: 1.5em;
+}
+
+.htmlview p {
+    margin: 0;
+}
+
+/* ======================== */
+/* = Footnotes and themes = */
+/* ======================== */
+.htmlview .theme-begin {
+    border-left: 0.1em solid #DDDDDD;
+    color: #777;
+    padding: 0 0.5em;
+    width: 7.5em;
+    font-style: normal;
+    font-weight: normal;
+    font-size: 16px;
+    float: right;
+    margin-right: -9.5em;
+    clear: both;
+    left: 40em;
+    line-height: 1.5em;
+    text-align: left;
+}
+
+.htmlview .annotation {
+    font-style: normal;
+    font-weight: normal;
+    font-size: 12px;
+}
+
+.htmlview #footnotes .annotation {
+    display: block;
+    float: left;
+    width: 2.5em;
+    clear: both;
+}
+
+.htmlview #footnotes div {
+    margin: 1.5em 0 0 0;
+}
+
+.htmlview #footnotes p {
+    margin-left: 2.5em;
+    font-size: 0.875em;
+}
+
+.htmlview blockquote {
+    font-size: 0.875em;
+}
+
+/* ============= */
+/* = Numbering = */
+/* ============= */
+.htmlview p {
+    position: relative;
+}
+
+.htmlview .anchor {
+    position: absolute;
+    margin: 0em;
+    left: -3em;
+    color: #777;
+    font-size: 12px;
+    width: 2em;
+    text-align: center;
+    padding: 0.25em 0.5em;
+    line-height: 1.5em;
+}
+
+.htmlview .anchor:hover, .htmlview .anchor:active {
+    color: #FFF;
+    background-color: #CCC;
+}
+
+/* =================== */
+/* = Custom elements = */
+/* =================== */
+.htmlview span.author {
+    font-size: 0.5em;
+    display: block;
+    line-height: 1.5em;
+    margin-bottom: 0.25em;
+}
+
+.htmlview span.collection {
+    font-size: 0.375em;
+    display: block;
+    line-height: 1.5em;
+    margin-bottom: -0.25em;
+}
+
+.htmlview span.subtitle {
+    font-size: 0.5em;
+    display: block;
+    line-height: 1.5em;
+    margin-top: -0.25em;
+}
+
+.htmlview div.didaskalia {
+    font-style: italic;
+    margin: 0.5em 0 0 1.5em;
+}
+
+.htmlview div.kwestia {
+    margin: 0.5em 0 0;
+}
+
+.htmlview div.stanza {
+    margin: 1.5em 0 0;
+}
+
+.htmlview div.kwestia div.stanza {
+    margin: 0;
+}
+
+.htmlview p.paragraph {
+    text-align: justify;
+    margin: 1.5em 0 0;
+}
+
+.htmlview p.motto {
+    text-align: justify;
+    font-style: italic;
+    margin: 1.5em 0 0;
+}
+
+.htmlview p.motto_podpis {
+    font-size: 0.875em;
+    text-align: right;
+}
+
+.htmlview div.fragment {
+    border-bottom: 0.1em solid #999;
+    padding-bottom: 1.5em;
+}
+
+.htmlview div.note p, .htmlview div.dedication p,
+.htmlview div.note p.paragraph, .htmlview div.dedication p.paragraph {
+    text-align: right;
+    font-style: italic;
+}
+
+.htmlview hr.spacer {
+    height: 3em;
+    visibility: hidden;
+}
+
+.htmlview hr.spacer-line {
+    margin: 1.5em 0;
+    border: none;
+    border-bottom: 0.1em solid #000;
+}
+
+.htmlview p.spacer-asterisk {
+    padding: 0;
+    margin: 1.5em 0;
+    text-align: center;
+}
+
+.htmlview div.person-list ol {
+    list-style: none;
+    padding: 0 0 0 1.5em;
+}
+
+.htmlview p.place-and-time {
+    font-style: italic;
+}
+
+.htmlview em.math, .htmlview em.foreign-word,
+.htmlview em.book-title, .htmlview em.didaskalia {
+    font-style: italic;
+}
+
+.htmlview em.author-emphasis {
+    letter-spacing: 0.1em;
+}
+
+.htmlview em.person {
+    font-style: normal;
+    font-variant: small-caps;
+}
diff --git a/project/static/css/managment.css b/project/static/css/managment.css
new file mode 100644 (file)
index 0000000..3777bcf
--- /dev/null
@@ -0,0 +1,36 @@
+table.request-report 
+{
+    border: 2px groove black;
+    font-size: 12pt;
+
+    margin-top: 3em;
+    margin-bottom: 2em;
+    margin-left: auto;
+    margin-right: auto;
+}
+
+.request-report td, .request-report th  {
+    vertical-align: top;
+    border-right: 1px solid black;
+    border-bottom: 1px solid black;
+
+    padding: 0.4em 1em;
+    margin: 0em;
+}
+
+.request-report th {
+    background-color: black;
+    color: white;
+}
+
+.request-report .status-N {
+    background-color: teal;
+}
+
+.request-report .status-R {
+    background-color: red;
+}
+
+.request-report .status-A {
+    background-color: gray;
+}
\ No newline at end of file
index 9de3c7f..fde1539 100644 (file)
@@ -49,20 +49,21 @@ if (typeof console === 'undefined') {
 
   this.render_template = function render_template(str, data){
     // Figure out if we're getting a template, or if we need to
-    // load the template - and be sure to cache the result.
+    // load the template - and be sure to cache the result.    
     var fn = !/^[\d\s-_]/.test(str) ?
       cache[str] = cache[str] ||
         render_template(document.getElementById(str).innerHTML) :
 
       // Generate a reusable function that will serve as a template
       // generator (and which will be cached).
+      
       new Function("obj",
         "var p=[],print=function(){p.push.apply(p,arguments);};" +
 
         // Introduce the data as local variables using with(){}
         "with(obj){p.push('" +
 
-        // Convert the template into pure JavaScript
+        // Convert the template into pure JavaScript       
         str
           .replace(/[\r\t\n]/g, " ")
           .split("<%").join("\t")
index e2ee8b1..ab021f5 100644 (file)
@@ -23,7 +23,15 @@ Editor.ToolbarButtonsModel = Editor.Model.extend({
         }
     },
   
-    loadSucceeded: function(data) {
+    loadSucceeded: function(data)
+    {
+        // do some escaping
+        $.each(data, function() {
+            $.each(this.buttons, function() {
+                //do some lame escapes
+                this.tooltip = this.tooltip.replace(/"/g, "&#34;");
+            });
+        });
         this.set('buttons', data);
     }
 });
@@ -176,7 +184,7 @@ Editor.HTMLModel = Editor.Model.extend({
             this.set('state', 'loading');
 
             // load the transformed data
-            messageCenter.addMessage('info', 'Wczytuję HTML...');
+            // messageCenter.addMessage('info', 'Wczytuję HTML...');
 
             $.ajax({
                 url: this.htmlURL,
@@ -196,16 +204,42 @@ Editor.HTMLModel = Editor.Model.extend({
         }
         this.set('data', data);
         this.set('state', 'synced');
-        messageCenter.addMessage('success', 'Wczytałem HTML :-)');
+        // messageCenter.addMessage('success', 'Wczytałem HTML :-)');
     },
   
-    loadingFailed: function() {
+    loadingFailed: function(response) {
         if (this.get('state') != 'loading') {
             alert('erroneous state:', this.get('state'));
         }
-        this.set('error', 'Nie udało się załadować panelu');
+
+        var json_response = null;
+        var message = "";
+
+        try {
+            json_response = $.evalJSON(response.responseText);
+
+            if(json_response.reason == 'xml-parse-error') {
+
+                message = json_response.message.replace(/(line\s+)(\d+)(\s+)/i,
+                    "<a class='xml-editor-ref' href='#xml-$2-1'>$1$2$3</a>");
+
+                message = message.replace(/(line\s+)(\d+)(\,\s*column\s+)(\d+)/i,
+                    "<a class='xml-editor-ref' href='#xml-$2-$4'>$1$2$3$4</a>");
+
+                
+            }
+            else {
+                message = json_response.message || json_response.reason || "nieznany błąd.";
+            }
+        }
+        catch (e) {
+            message = response.statusText;
+        }
+
+        this.set('error', '<p>Nie udało się wczytać widoku HTML: </p>' + message);
+
         this.set('state', 'error');
-        messageCenter.addMessage('error', 'Nie udało mi się wczytać HTML. Spróbuj ponownie :-(');
+        // messageCenter.addMessage('error', 'Nie udało mi się wczytać HTML. Spróbuj ponownie :-(');
     },
 
     getXMLPart: function(elem, callback)
@@ -224,7 +258,7 @@ Editor.HTMLModel = Editor.Model.extend({
 
         $.ajax({
             url: this.dataURL,
-            dataType: 'text; charset=utf-8',
+            dataType: 'text',
             data: {
                 revision: this.get('revision'),
                 part: path
@@ -548,12 +582,12 @@ $(function()
     toolbarUrl = $('#api-toolbar-url').text();
 
     doc = new Editor.DocumentModel();
-    var editor = new EditorView('#body-wrap', doc);
-    editor.freeze();
 
-    var flashView = new FlashView('#flashview', messageCenter);
-    var splitView = new SplitView('#splitview', doc);
+    EditorView = new EditorView('#body-wrap', doc);
+    EditorView.freeze();
 
     leftPanelView = new PanelContainerView('#left-panel-container', doc);
     rightPanelContainer = new PanelContainerView('#right-panel-container', doc);
+
+    var flashView = new FlashView('#flashview', messageCenter);   
 });
index 7e4b6ea..7f03998 100644 (file)
@@ -47,6 +47,7 @@ var ButtonToolbarView = View.extend({
 
     buttonPressed: function(event)
     {
+        var self = this;
         var target = event.target;
         
         var groupIndex = parseInt($(target).attr('ui:groupindex'), 10);
@@ -57,9 +58,13 @@ var ButtonToolbarView = View.extend({
 
         console.log('Executing', scriptletId, 'with params', params);
         try {
-            scriptletCenter.scriptlets[scriptletId](this.parent, params);
+            self.parent.freeze('Wykonuję akcję...');
+            setTimeout(function() {
+                scriptletCenter.scriptlets[scriptletId](self.parent, params);
+                self.parent.unfreeze();
+            }, 10);
         } catch(e) {
-            console.log("Scriptlet", scriptletId, "failed.");
+            console.log("Scriptlet", scriptletId, "failed.", e);
         }
 
     },
index 10c77f6..2793141 100644 (file)
 /*global View render_template panels */
 var EditorView = View.extend({
-  _className: 'EditorView',
-  element: null,
-  model: null,
-  template: null,
+    _className: 'EditorView',
+    element: null,
+    model: null,
+    template: null,
   
-  init: function(element, model, template) {
-    this._super(element, model, template);
+    init: function(element, model, template) {
+        this._super(element, model, template);
     
-    this.quickSaveButton = $('#action-quick-save', this.element).bind('click.editorview', this.quickSave.bind(this));
-    this.commitButton = $('#action-commit', this.element).bind('click.editorview', this.commit.bind(this));
-    this.updateButton = $('#action-update', this.element).bind('click.editorview', this.update.bind(this));
-    this.mergeButton = $('#action-merge', this.element).bind('click.editorview', this.merge.bind(this));
+        this.quickSaveButton = $('#action-quick-save', this.element).bind('click.editorview', this.quickSave.bind(this));
+        this.commitButton = $('#action-commit', this.element).bind('click.editorview', this.commit.bind(this));
+        this.updateButton = $('#action-update', this.element).bind('click.editorview', this.update.bind(this));
+        this.mergeButton = $('#action-merge', this.element).bind('click.editorview', this.merge.bind(this));
     
-    this.model.addObserver(this, 'state', this.modelStateChanged.bind(this));
-    this.modelStateChanged('state', this.model.get('state'));
-      
-    // Inicjalizacja okien jQuery Modal
-    $('#commit-dialog', this.element).
-    jqm({
-        modal: true,
-        onShow: this.loadRelatedIssues.bind(this)
-    });
+        this.model.addObserver(this, 'state', this.modelStateChanged.bind(this));
+        this.modelStateChanged('state', this.model.get('state'));        
+
+        this.splitView = new SplitView('#splitview', doc);
+        
+        // Inicjalizacja okien jQuery Modal
+        $('#commit-dialog', this.element).
+        jqm({
+            modal: true,
+            onShow: this.loadRelatedIssues.bind(this)
+        });
     
-    $('#commit-dialog-cancel-button', this.element).click(function() {
-        $('#commit-dialog-error-empty-message').hide();
-        $('#commit-dialog').jqmHide();
-    });   
+        $('#commit-dialog-cancel-button', this.element).click(function() {
+            $('#commit-dialog-error-empty-message').hide();
+            $('#commit-dialog').jqmHide();
+        });
     
-    // $('#split-dialog').jqm({
-    //      modal: true,
-    //      onShow: $.fbind(self, self.loadSplitDialog)
-    //  }).
-    //  jqmAddClose('button.dialog-close-button');
+        // $('#split-dialog').jqm({
+        //      modal: true,
+        //      onShow: $.fbind(self, self.loadSplitDialog)
+        //  }).
+        //  jqmAddClose('button.dialog-close-button');
     
-    this.model.load();
-  },
+        this.model.load();
+    },
   
-  quickSave: function(event) {
-    this.model.saveDirtyContentModel();
-  },
+    quickSave: function(event) {
+        this.model.saveDirtyContentModel();
+    },
   
-  commit: function(event) {
-    $('#commit-dialog', this.element).jqmShow({callback: this.doCommit.bind(this)});
-  },
+    commit: function(event) {
+        $('#commit-dialog', this.element).jqmShow({
+            callback: this.doCommit.bind(this)
+            });
+    },
   
-  doCommit: function(message) {
-    this.model.saveDirtyContentModel(message);
-  },
+    doCommit: function(message) {
+        this.model.saveDirtyContentModel(message);
+    },
   
-  update: function(event) {
-    this.model.update();
-  },
+    update: function(event) {
+        this.model.update();
+    },
   
-  merge: function(event) {
-    $('#commit-dialog', this.element).jqmShow({callback: this.doMerge.bind(this)});
-  },
+    merge: function(event) {
+        $('#commit-dialog', this.element).jqmShow({
+            callback: this.doMerge.bind(this)
+            });
+    },
   
-  doMerge: function(message) {
-    this.model.merge(message);
-  },
+    doMerge: function(message) {
+        this.model.merge(message);
+    },
   
-  loadRelatedIssues: function(hash) {
-    var self = this;
-    var c = $('#commit-dialog-related-issues');
+    loadRelatedIssues: function(hash) {
+        var self = this;
+        var c = $('#commit-dialog-related-issues');
 
-    $('#commit-dialog-save-button').click(function(event, data)
-    {
-      if ($('#commit-dialog-message').val().match(/^\s*$/)) {
-        $('#commit-dialog-error-empty-message').fadeIn();
-      } else {
-        $('#commit-dialog-error-empty-message').hide();
-        $('#commit-dialog').jqmHide();
+        $('#commit-dialog-save-button').click(function(event, data)
+        {
+            if ($('#commit-dialog-message').val().match(/^\s*$/)) {
+                $('#commit-dialog-error-empty-message').fadeIn();
+            } else {
+                $('#commit-dialog-error-empty-message').hide();
+                $('#commit-dialog').jqmHide();
 
-        var message = $('#commit-dialog-message').val();
-        $('#commit-dialog-related-issues input:checked')
-          .each(function() { message += ' refs #' + $(this).val(); });
-        console.log("COMMIT APROVED", hash.t);
-        hash.t.callback(message);
-      }
-      return false;
-    });
+                var message = $('#commit-dialog-message').val();
+                $('#commit-dialog-related-issues input:checked')
+                .each(function() {
+                    message += ' refs #' + $(this).val();
+                });
+                console.log("COMMIT APROVED", hash.t);
+                hash.t.callback(message);
+            }
+            return false;
+        });
 
-    $("div.loading-box", c).show();
-    $("div.fatal-error-box", c).hide();
-    $("div.container-box", c).hide();
+        $("div.loading-box", c).show();
+        $("div.fatal-error-box", c).hide();
+        $("div.container-box", c).hide();
     
-    $.getJSON(c.attr('ui:ajax-src') + '?callback=?',
-    function(data, status)
-    {
-        var fmt = '';
-        $(data).each( function() {
-            fmt += '<label><input type="checkbox" checked="checked"';
-            fmt += ' value="' + this.id + '" />' + this.subject +'</label>\n';
-        });
-        $("div.container-box", c).html(fmt);
-        $("div.loading-box", c).hide();
-        $("div.container-box", c).show();        
-    });   
+        $.getJSON(c.attr('ui:ajax-src') + '?callback=?',
+            function(data, status)
+            {
+                var fmt = '';
+                $(data).each( function() {
+                    fmt += '<label><input type="checkbox" checked="checked"';
+                    fmt += ' value="' + this.id + '" />' + this.subject +'</label>\n';
+                });
+                $("div.container-box", c).html(fmt);
+                $("div.loading-box", c).hide();
+                $("div.container-box", c).show();
+            });
     
-    hash.w.show();
-  },
+        hash.w.show();
+    },
   
-  modelStateChanged: function(property, value) {
-    // Uaktualnia stan przycisków
-    if (value == 'dirty') {
-      this.quickSaveButton.attr('disabled', null);
-      this.commitButton.attr('disabled', null);
-      this.updateButton.attr('disabled', 'disabled');
-      this.mergeButton.attr('disabled', 'disabled');
-    } else if (value == 'synced') {
-      this.quickSaveButton.attr('disabled', 'disabled');
-      this.commitButton.attr('disabled', 'disabled');
-      this.updateButton.attr('disabled', null);
-      this.mergeButton.attr('disabled', null);      
-    } else if (value == 'empty') {
-      this.quickSaveButton.attr('disabled', 'disabled');
-      this.commitButton.attr('disabled', 'disabled');
-      this.updateButton.attr('disabled', 'disabled');
-      this.mergeButton.attr('disabled', 'disabled');
-    }
-  },
+    modelStateChanged: function(property, value) {
+        // Uaktualnia stan przycisków
+        if (value == 'dirty') {
+            this.quickSaveButton.attr('disabled', null);
+            this.commitButton.attr('disabled', null);
+            this.updateButton.attr('disabled', 'disabled');
+            this.mergeButton.attr('disabled', 'disabled');
+        } else if (value == 'synced') {
+            this.quickSaveButton.attr('disabled', 'disabled');
+            this.commitButton.attr('disabled', 'disabled');
+            this.updateButton.attr('disabled', null);
+            this.mergeButton.attr('disabled', null);
+        } else if (value == 'empty') {
+            this.quickSaveButton.attr('disabled', 'disabled');
+            this.commitButton.attr('disabled', 'disabled');
+            this.updateButton.attr('disabled', 'disabled');
+            this.mergeButton.attr('disabled', 'disabled');
+        }
+    },
   
-  dispose: function() {
-    $('#action-quick-save', this.element).unbind('click.editorview');
-    $('#action-commit', this.element).unbind('click.editorview');
-    $('#action-update', this.element).unbind('click.editorview');
-    $('#action-merge', this.element).unbind('click.editorview');
+    dispose: function() {
+        $('#action-quick-save', this.element).unbind('click.editorview');
+        $('#action-commit', this.element).unbind('click.editorview');
+        $('#action-update', this.element).unbind('click.editorview');
+        $('#action-merge', this.element).unbind('click.editorview');
 
-    this.model.removeObserver(this);
-    this._super();
-  }
+        this.model.removeObserver(this);
+        this._super();
+    }    
 });
index ebdf90a..a3db1d2 100644 (file)
@@ -25,7 +25,10 @@ var HTMLView = View.extend({
         this.$printLink.attr('href', base + "?revision=" + this.model.get('revision'));
     },
   
-    modelStateChanged: function(property, value) {
+    modelStateChanged: function(property, value) 
+    {
+        var self = $(this);
+
         if (value == 'synced' || value == 'dirty') {
             this.unfreeze();
         } else if (value == 'unsynced') {
@@ -36,6 +39,21 @@ var HTMLView = View.extend({
             this.freeze('Zapisywanie...');
         } else if (value == 'error') {
             this.freeze(this.model.get('error'));
+            $('.xml-editor-ref', this.overlay).click(
+            function(event) {
+                console.log("Sending scroll rq.", this);
+                try {
+                    var href = $(this).attr('href').split('-');
+                    var line = parseInt(href[1]);
+                    var column = parseInt(href[2]);
+                    
+                    $(document).trigger('xml-scroll-request', {line:line, column:column});
+                } catch(e) {
+                    console.log(e);
+                }
+                
+                return false;
+            });
         }
     },
 
@@ -46,6 +64,9 @@ var HTMLView = View.extend({
         this._super();
         this.$printLink = $('.html-print-link', this.element);
 
+        var base = this.$printLink.attr('ui:baseref');
+        this.$printLink.attr('href', base + "?revision=" + this.model.get('revision'));
+
         this.element.bind('click', this.itemClicked.bind(this));
     },
   
index 48f0de7..30eda4a 100644 (file)
@@ -17,7 +17,7 @@ var SplitView = View.extend({
   init: function(element, model) {
     this._super(element, model, null);
     this.element.css('position', 'relative');
-    this._resizingSubviews = false;
+    this._resizingSubviews = false;    
     
     this.views = $(">*", this.element[0]).css({
        position: 'absolute',                     // positioned inside splitter container
@@ -28,6 +28,7 @@ var SplitView = View.extend({
     
     this.leftView = $(this.views[0]);
     this.rightView = $(this.views[1]);
+    
     this.splitbar = $(this.views[2] || '<div></div>')
       .insertAfter(this.leftView)
       .css({
index 00547d1..1681cae 100644 (file)
@@ -1,4 +1,4 @@
-/*global View CodeMirror ButtonToolbarView render_template panels */
+/*global View CodeMirror ToolbarView render_template panels */
 var XMLView = View.extend({
     _className: 'XMLView',
     element: null,
@@ -18,8 +18,11 @@ var XMLView = View.extend({
         var self = this;
 
         $('.xmlview-toolbar', this.element).bind('resize.xmlview', this.resized.bind(this));
-   
-    
+
+        // scroll to the given position (if availble)
+        this.scrollCallback = this.scrollOnRequest.bind(this);
+        $(document).bind('xml-scroll-request', this.scrollCallback);
+       
         this.parent.freeze('Ładowanie edytora...');
         this.editor = new CodeMirror($('.xmlview', this.element).get(0), {
             parserfile: 'parsexml.js',
@@ -28,7 +31,7 @@ var XMLView = View.extend({
             parserConfig: {
                 useHTMLKludges: false
             },
-            textWrapping: false,
+            textWrapping: true,
             tabMode: 'spaces',
             indentUnit: 0,
             onChange: this.editorDataChanged.bind(this),
@@ -91,6 +94,8 @@ var XMLView = View.extend({
     },
     
     dispose: function() {
+        $(document).unbind('xml-scroll-request', this.scrollCallback);
+        
         this.model.removeObserver(this);
         $(this.editor.frame).remove();
         this._super();
@@ -104,7 +109,7 @@ var XMLView = View.extend({
         var ch = String.fromCharCode(code & 0xff).toLowerCase();
         /* # console.log(ch.charCodeAt(0), '#', buttons); */
 
-        var buttons = $('.buttontoolbarview-button[title='+ch+']', this.element);
+        var buttons = $('.buttontoolbarview-button[hotkey='+ch+']', this.element);
         var mod = 0;
             
         if(event.altKey) mod |= 0x01;
@@ -141,6 +146,16 @@ var XMLView = View.extend({
         this.buttonToolbar.buttonPressed({
             target: button
         });
+    },
+
+    scrollOnRequest: function(event, data) 
+    {
+        try {
+            var line = this.editor.nthLine(data.line);
+            this.editor.selectLines(line, (data.column-1));
+        } catch(e) {
+            console.log('Exception in scrollOnRequest:', e);
+        }
     }
 
 });
index b338e6d..3c775d4 100644 (file)
                                <div class="buttontoolbarview-group toolbar-buttons-container" ui:groupIndex="<%= i %>" style="display: none">
                                        <% for (var j=0; j < buttons[i].buttons.length; j++) { %>
                                                <% if (buttons[i].buttons[j].scriptlet_id) { %>
-                                               <button type="button" class="buttontoolbarview-button" 
-                                                    title="<%= buttons[i].buttons[j].key %>"
+                                               <button type="button" class="buttontoolbarview-button"
+                                                    title="<%= buttons[i].buttons[j].tooltip %>"
+                                                    hotkey="<%= buttons[i].buttons[j].key %>"
                                                     ui:hotkey_mod="<%= buttons[i].buttons[j].key_mod %>"
                                                     ui:groupindex="<%= i %>" ui:buttonindex="<%= j %>">
                                                        <%= buttons[i].buttons[j].label %>
index 53a798a..1b4ef31 100644 (file)
@@ -2,7 +2,7 @@
 <html>
   <head>
     <title>{{docid}}</title>
-    <link rel="stylesheet" href="{{STATIC_URL}}css/html.css" type="text/css" charset="utf-8">
+    <link rel="stylesheet" href="{{STATIC_URL}}css/html_print.css" type="text/css" charset="utf-8">
     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
   </head>
   <body>
index c03caab..c2964c2 100644 (file)
@@ -1,7 +1,75 @@
+{% extends 'base.html' %}
+
+{% block extrahead %}
+<link rel="stylesheet" href="{{ STATIC_URL }}css/managment.css" type="text/css" />
+<script type="text/javascript">
+
+    
+    $(function() {
+
+        function refreshRow(id) {
+            var row = $('#request-' +id);
+
+            $.ajax({
+                url: '{% url pullrequest_list %}/'+id,
+                dataType: 'json',
+                type: 'GET',
+                success: function(data) {
+                    row.removeClass('status-N');
+                    row.removeClass('status-R');
+                    row.removeClass('status-A');
+                    row.addClass('status-'+ data.status);
+
+                    $('.column-doc', row).html(data.document);
+                    $('.column-status', row).html(data.status);
+
+                    alert('Merge accepted.');
+                }
+            });            
+            
+        }
+        
+        $('.accept-button').click(function()
+        {
+            var id = parseInt($(this).attr('title'));
+            
+
+            $.ajax({
+                url: '{% url pullrequest_list %}/'+id,
+                data: {action: 'accept'},
+                dataType: 'json',
+                type: 'PUT',
+                success: function(data) {
+                    refreshRow(id);
+                }
+            });
+            
+        });
+        
+    });
+</script>
+{% endblock %}
+
+{% block maincontent %}
+<table class="request-report" cellspacing="0">
+    <tr>
+        <th>Utwór</th><th>Użytkownik</th><th>Komentarz</th><th>Stan</th>
+        <th>Akcje</th>
+    </tr>
 {% if objects %}
     {% for pullreq in objects %}
-    <p>{{ pullreq }}</p>
+    <tr class="status-{{pullreq.status}}" id="request-{{pullreq.id}}">
+        <td class="column-doc">{{ pullreq.document }}</td>
+        <td class="column-user">{{ pullreq.comitter }}</td>
+        <td class="column-comment">{{ pullreq.comment }}</td>
+        <td class="column-status"> {{ pullreq.status }}</td>
+        <td><button type="button" class="accept-button" title="{{pullreq.id}}">Akceptuj</button></td>
+    </tr>
+    
     {% endfor %}
 {% else %}
-    <p>Brak żądań</p>
+    <tr><td colspan="*">Brak żądań</td></tr>
 {% endif %}
+</table>
+
+{% endblock %}
index c38f3f6..e107635 100644 (file)
@@ -12,6 +12,9 @@ urlpatterns = patterns('',
     # Explorer:
     url(r'^$', 'explorer.views.file_list', name='file_list'),        
     url(r'^file/upload', 'explorer.views.file_upload', name='file_upload'),
+
+
+    url(r'^managment/pull-requests$', 'explorer.views.pull_requests'),
     
 #    url(r'^images/(?P<folder>[^/]+)/$', 'explorer.views.folder_images', name='folder_image'),
 #    url(r'^images/$', 'explorer.views.folder_images', {'folder': '.'}, name='folder_image_ajax'),
@@ -37,7 +40,7 @@ urlpatterns = patterns('',
     url(r'^admin/(.*)', admin.site.root),
 
     # Prototypes
-    url(r'^wysiwyg-proto/', include('wysiwyg.urls')),
+#    url(r'^wysiwyg-proto/', include('wysiwyg.urls')),
 
     # Our über-restful api
     url(r'^api/', include('api.urls') ),