Reverted CM to version 0.63 with 2 patches:
authorŁukasz Rekucki <lrekucki@gmail.com>
Mon, 5 Oct 2009 10:56:58 +0000 (12:56 +0200)
committerŁukasz Rekucki <lrekucki@gmail.com>
Mon, 5 Oct 2009 10:56:58 +0000 (12:56 +0200)
* pass anb event to filter instead of just the key code
* check text-value properly

apps/explorer/context_processors.py
project/static/js/lib/codemirror/codemirror.js
project/static/js/lib/codemirror/editor.js
project/static/js/lib/codemirror/select.js
project/static/js/lib/codemirror/undo.js
project/static/js/lib/codemirror/util.js
project/static/js/views/button_toolbar.js
project/static/js/views/xml.js
project/templates/explorer/editor.html
project/templates/html4print.html [new file with mode: 0644]

index 634b015..eff3032 100755 (executable)
@@ -4,6 +4,8 @@ __date__ ="$2009-09-03 08:34:10$"
 
 def settings(request):
     from django.conf import settings
-    return {'MEDIA_URL': settings.MEDIA_URL, 'STATIC_URL': settings.STATIC_URL}
+    return {'MEDIA_URL': settings.MEDIA_URL, 
+            'STATIC_URL': settings.STATIC_URL,
+            'REDMINE_URL': settings.REDMINE_URL }
 
 
index f63ed07..97e2657 100644 (file)
@@ -81,10 +81,13 @@ var CodeMirror = (function(){
 
     var nextNum = 1, barWidth = null;
     function sizeBar() {
-      for (var root = frame; root.parentNode; root = root.parentNode);
-      if (root != document || !win.Editor) {
-        clearInterval(sizeInterval);
-        return;
+      if (!frame.offsetWidth || !win.Editor) {
+        for (var cur = frame; cur.parentNode; cur = cur.parentNode) {
+          if (cur != document) {
+            clearInterval(sizeInterval);
+            return;
+          }
+        }
       }
 
       if (nums.offsetWidth != barWidth) {
@@ -132,7 +135,6 @@ var CodeMirror = (function(){
       var node = place;
       place = function(n){node.appendChild(n);};
     }
-    
     if (options.lineNumbers) place = wrapLineNumberDiv(place);
     place(frame);
 
@@ -173,14 +175,10 @@ var CodeMirror = (function(){
 
     getCode: function() {return this.editor.getCode();},
     setCode: function(code) {this.editor.importCode(code);},
-    selection: function() {this.focusIfIE(); return this.editor.selectedText();},
+    selection: function() {return this.editor.selectedText();},
     reindent: function() {this.editor.reindent();},
-    reindentSelection: function() {this.focusIfIE(); this.editor.reindentSelection(null);},
+    reindentSelection: function() {this.editor.reindentSelection(null);},
 
-    focusIfIE: function() {
-      // in IE, a lot of selection-related functionality only works when the frame is focused
-      if (this.win.select.ie_selection) this.focus();
-    },
     focus: function() {
       this.win.focus();
       if (this.editor.selectionSnapshot) // IE hack
@@ -208,7 +206,10 @@ var CodeMirror = (function(){
 
     setParser: function(name) {this.editor.setParser(name);},
 
-    cursorPosition: function(start) {this.focusIfIE(); return this.editor.cursorPosition(start);},
+    cursorPosition: function(start) {
+      if (this.win.select.ie_selection) this.focus();
+      return this.editor.cursorPosition(start);
+    },
     firstLine: function() {return this.editor.firstLine();},
     lastLine: function() {return this.editor.lastLine();},
     nextLine: function(line) {return this.editor.nextLine(line);},
index b7c53c7..0f7a8af 100644 (file)
@@ -80,13 +80,13 @@ var Editor = (function(){
         if (text.length) leaving = false;
         result.push(node);
       }
-      else if (isBR(node) && node.childNodes.length == 0) {
+      else if (node.nodeName == "BR" && node.childNodes.length == 0) {
         leaving = true;
         result.push(node);
       }
       else {
         forEach(node.childNodes, simplifyNode);
-        if (!leaving && newlineElements.hasOwnProperty(node.nodeName.toUpperCase())) {
+        if (!leaving && newlineElements.hasOwnProperty(node.nodeName)) {
           leaving = true;
           if (!atEnd || !top)
             result.push(doc.createElement("BR"));
@@ -175,7 +175,7 @@ var Editor = (function(){
         nodeQueue.push(node);
         return yield(node.currentText, c);
       }
-      else if (isBR(node)) {
+      else if (node.nodeName == "BR") {
         nodeQueue.push(node);
         return yield("\n", c);
       }
@@ -195,20 +195,23 @@ var Editor = (function(){
 
   // Determine the text size of a processed node.
   function nodeSize(node) {
-    return isBR(node) ? 1 : node.currentText.length;
+    if (node.nodeName == "BR")
+      return 1;
+    else
+      return node.currentText.length;
   }
 
   // Search backwards through the top-level nodes until the next BR or
   // the start of the frame.
   function startOfLine(node) {
-    while (node && !isBR(node)) node = node.previousSibling;
+    while (node && node.nodeName != "BR") node = node.previousSibling;
     return node;
   }
   function endOfLine(node, container) {
     if (!node) node = container.firstChild;
-    else if (isBR(node)) node = node.nextSibling;
+    else if (node.nodeName == "BR") node = node.nextSibling;
 
-    while (node && !isBR(node)) node = node.nextSibling;
+    while (node && node.nodeName != "BR") node = node.nextSibling;
     return node;
   }
 
@@ -363,6 +366,8 @@ var Editor = (function(){
     this.dirty = [];
     if (options.content)
       this.importCode(options.content);
+    else // FF acts weird when the editable document is completely empty
+      container.appendChild(this.doc.createElement("BR"));
 
     if (!options.readOnly) {
       if (options.continuousScanning !== false) {
@@ -501,7 +506,7 @@ var Editor = (function(){
       this.checkLine(line);
       var accum = [];
       for (line = line ? line.nextSibling : this.container.firstChild;
-           line && !isBR(line); line = line.nextSibling)
+           line && line.nodeName != "BR"; line = line.nextSibling)
         accum.push(nodeText(line));
       return cleanText(accum.join(""));
     },
@@ -526,7 +531,7 @@ var Editor = (function(){
             before = cur;
             break;
           }
-          var text = nodeText(cur);
+          var text = (cur.innerText || cur.textContent || cur.nodeValue || "");
           if (text.length > position) {
             before = cur.nextSibling;
             content = text.slice(0, position) + content + text.slice(position);
@@ -658,7 +663,7 @@ var Editor = (function(){
     // Intercept enter and tab, and assign their new functions.
     keyDown: function(event) {
       if (this.frozen == "leave") this.frozen = null;
-      if (this.frozen && (!this.keyFilter || this.keyFilter(event.keyCode))) {
+      if (this.frozen && (!this.keyFilter || this.keyFilter(event)) ) {
         event.stop();
         this.frozen(event);
         return;
@@ -838,10 +843,10 @@ var Editor = (function(){
 
     home: function() {
       var cur = select.selectionTopNode(this.container, true), start = cur;
-      if (cur === false || !(!cur || cur.isPart || isBR(cur)) || !this.container.firstChild)
+      if (cur === false || !(!cur || cur.isPart || cur.nodeName == "BR") || !this.container.firstChild)
         return false;
 
-      while (cur && !isBR(cur)) cur = cur.previousSibling;
+      while (cur && cur.nodeName != "BR") cur = cur.previousSibling;
       var next = cur ? cur.nextSibling : this.container.firstChild;
       if (next && next != start && next.isPart && hasClass(next, "whitespace"))
         select.focusAfterNode(next, this.container);
@@ -896,7 +901,7 @@ var Editor = (function(){
       function tryFindMatch() {
         var stack = [], ch, ok = true;;
         for (var runner = cursor; runner; runner = dir ? runner.nextSibling : runner.previousSibling) {
-          if (runner.className == className && isSpan(runner) && (ch = paren(runner))) {
+          if (runner.className == className && runner.nodeName == "SPAN" && (ch = paren(runner))) {
             if (forward(ch) == dir)
               stack.push(ch);
             else if (!stack.length)
@@ -905,7 +910,7 @@ var Editor = (function(){
               ok = false;
             if (!stack.length) break;
           }
-          else if (runner.dirty || !isSpan(runner) && !isBR(runner)) {
+          else if (runner.dirty || runner.nodeName != "SPAN" && runner.nodeName != "BR") {
             return {node: runner, status: "dirty"};
           }
         }
@@ -963,7 +968,7 @@ var Editor = (function(){
     // selection.
     indentRegion: function(start, end, direction) {
       var current = (start = startOfLine(start)), before = start && startOfLine(start.previousSibling);
-      if (!isBR(end)) end = endOfLine(end, this.container);
+      if (end.nodeName != "BR") end = endOfLine(end, this.container);
 
       do {
         var next = endOfLine(current, this.container);
@@ -1122,7 +1127,7 @@ var Editor = (function(){
       // Backtrack to the first node before from that has a partial
       // parse stored.
       while (from && (!from.parserFromHere || from.dirty)) {
-        if (maxBacktrack != null && isBR(from) && (--maxBacktrack) < 0)
+        if (maxBacktrack != null && from.nodeName == "BR" && (--maxBacktrack) < 0)
           return false;
         from = from.previousSibling;
       }
@@ -1203,7 +1208,7 @@ var Editor = (function(){
           // Allow empty nodes when they are alone on a line, needed
           // for the FF cursor bug workaround (see select.js,
           // insertNewlineAtCursor).
-          while (part && isSpan(part) && part.currentText == "") {
+          while (part && part.nodeName == "SPAN" && part.currentText == "") {
             var old = part;
             this.remove();
             part = this.get();
@@ -1225,7 +1230,7 @@ var Editor = (function(){
         if (token.value == "\n"){
           // The idea of the two streams actually staying synchronized
           // is such a long shot that we explicitly check.
-          if (!isBR(part))
+          if (part.nodeName != "BR")
             throw "Parser out of sync. Expected BR.";
 
           if (part.dirty || !part.indentation) lineDirty = true;
@@ -1253,7 +1258,7 @@ var Editor = (function(){
           parts.next();
         }
         else {
-          if (!isSpan(part))
+          if (part.nodeName != "SPAN")
             throw "Parser out of sync. Expected SPAN.";
           if (part.dirty)
             lineDirty = true;
index 7746240..d513ba5 100644 (file)
@@ -52,7 +52,7 @@ var select = {};
     while (pos && pos.offsetParent) {
       y += pos.offsetTop;
       // Don't count X offset for <br> nodes
-      if (!isBR(pos))
+      if (pos.nodeName != "BR")
         x += pos.offsetLeft;
       pos = pos.offsetParent;
     }
@@ -247,17 +247,13 @@ var select = {};
           }
           if (cur) {
             try{range.moveToElementText(cur);}
-            catch(e){return false;}
+            catch(e){}
             range.collapse(false);
           }
           else range.moveToElementText(node.parentNode);
           if (count) range.move("character", count);
         }
-        else {
-          try{range.moveToElementText(node);}
-          catch(e){return false;}
-        }
-        return true;
+        else range.moveToElementText(node);
       }
 
       // Do a binary search through the container object, comparing
@@ -266,7 +262,7 @@ var select = {};
       while (start < end) {
         var middle = Math.ceil((end + start) / 2), node = container.childNodes[middle];
         if (!node) return false; // Don't ask. IE6 manages this sometimes.
-        if (!moveToNodeStart(range2, node)) return false;
+        moveToNodeStart(range2, node);
         if (range.compareEndPoints("StartToStart", range2) == 1)
           start = middle;
         else
@@ -318,7 +314,7 @@ var select = {};
       if (!selection) return null;
 
       var topNode = select.selectionTopNode(container, start);
-      while (topNode && !isBR(topNode))
+      while (topNode && topNode.nodeName != "BR")
         topNode = topNode.previousSibling;
 
       var range = selection.createRange(), range2 = range.duplicate();
@@ -411,7 +407,7 @@ var select = {};
       // ancestors with a suitable offset. This goes down the DOM tree
       // until a 'leaf' is reached (or is it *up* the DOM tree?).
       function normalize(point){
-        while (point.node.nodeType != 3 && !isBR(point.node)) {
+        while (point.node.nodeType != 3 && point.node.nodeName != "BR") {
           var newNode = point.node.childNodes[point.offset] || point.node.nextSibling;
           point.offset = 0;
           while (!newNode && point.node.parentNode) {
@@ -429,9 +425,8 @@ var select = {};
     };
 
     select.selectMarked = function () {
-      var cs = currentSelection;
-      if (!(cs && (cs.changed || (webkit && cs.start.node == cs.end.node)))) return;
-      var win = cs.window, range = win.document.createRange();
+      if (!currentSelection || !currentSelection.changed) return;
+      var win = currentSelection.window, range = win.document.createRange();
 
       function setPoint(point, which) {
         if (point.node) {
@@ -447,8 +442,8 @@ var select = {};
         }
       }
 
-      setPoint(cs.end, "End");
-      setPoint(cs.start, "Start");
+      setPoint(currentSelection.end, "End");
+      setPoint(currentSelection.start, "Start");
       selectRange(range, win);
     };
 
@@ -476,7 +471,7 @@ var select = {};
       var offset = start ? range.startOffset : range.endOffset;
       // Work around (yet another) bug in Opera's selection model.
       if (window.opera && !start && range.endContainer == container && range.endOffset == range.startOffset + 1 &&
-          container.childNodes[range.startOffset] && isBR(container.childNodes[range.startOffset]))
+          container.childNodes[range.startOffset] && container.childNodes[range.startOffset].nodeName == "BR")
         offset--;
 
       // For text nodes, we look at the node itself if the cursor is
@@ -491,7 +486,7 @@ var select = {};
       // Occasionally, browsers will return the HTML node as
       // selection. If the offset is 0, we take the start of the frame
       // ('after null'), otherwise, we take the last node.
-      else if (node.nodeName.toUpperCase() == "HTML") {
+      else if (node.nodeName == "HTML") {
         return (offset == 1 ? null : container.lastChild);
       }
       // If the given node is our 'container', we just look up the
@@ -562,7 +557,7 @@ var select = {};
       if (!range) return;
 
       var topNode = select.selectionTopNode(container, start);
-      while (topNode && !isBR(topNode))
+      while (topNode && topNode.nodeName != "BR")
         topNode = topNode.previousSibling;
 
       range = range.cloneRange();
index 97daf59..5f717a9 100644 (file)
@@ -250,7 +250,7 @@ History.prototype = {
     function buildLine(node) {
       var text = [];
       for (var cur = node ? node.nextSibling : self.container.firstChild;
-           cur && !isBR(cur); cur = cur.nextSibling)
+           cur && cur.nodeName != "BR"; cur = cur.nextSibling)
         if (cur.currentText) text.push(cur.currentText);
       return {from: node, to: cur, text: cleanText(text.join(""))};
     }
@@ -275,7 +275,7 @@ History.prototype = {
     // Get the BR element after/before the given node.
     function nextBR(node, dir) {
       var link = dir + "Sibling", search = node[link];
-      while (search && !isBR(search))
+      while (search && search.nodeName != "BR")
         search = search[link];
       return search;
     }
index 0cd91d4..796025e 100644 (file)
@@ -123,12 +123,3 @@ function nodeTop(node) {
   }
   return top;
 }
-
-function isBR(node) {
-  var nn = node.nodeName;
-  return nn == "BR" || nn == "br";
-}
-function isSpan(node) {
-  var nn = node.nodeName;
-  return nn == "SPAN" || nn == "span";
-}
index 71bfa97..7e4b6ea 100644 (file)
@@ -39,23 +39,30 @@ var ButtonToolbarView = View.extend({
             $(self.element).trigger('resize');
         });
     
-        $('.buttontoolbarview-button', this.element).bind('click.buttontoolbarview', function(event) {
-            var groupIndex = parseInt($(this).attr('ui:groupindex'), 10);
-            var buttonIndex = parseInt($(this).attr('ui:buttonindex'), 10);
-            var button = self.get('buttons')[groupIndex].buttons[buttonIndex];
-            var scriptletId = button.scriptlet_id;
-            var params = eval('(' + button.params + ')'); // To nie powinno być potrzebne
-
-            console.log('Executing', scriptletId, 'with params', params);
-            try {
-                scriptletCenter.scriptlets[scriptletId](self.parent, params);
-            } catch(e) {
-                console.log("Scriptlet", scriptletId, "failed.");
-            }
-        });
-    
+        $('.buttontoolbarview-button', this.element).
+        bind('click.buttontoolbarview', this.buttonPressed.bind(this) );
+            
         $(this.element).trigger('resize');
     },
+
+    buttonPressed: function(event)
+    {
+        var target = event.target;
+        
+        var groupIndex = parseInt($(target).attr('ui:groupindex'), 10);
+        var buttonIndex = parseInt($(target).attr('ui:buttonindex'), 10);
+        var button = this.get('buttons')[groupIndex].buttons[buttonIndex];
+        var scriptletId = button.scriptlet_id;
+        var params = eval('(' + button.params + ')'); // To nie powinno być potrzebne
+
+        console.log('Executing', scriptletId, 'with params', params);
+        try {
+            scriptletCenter.scriptlets[scriptletId](this.parent, params);
+        } catch(e) {
+            console.log("Scriptlet", scriptletId, "failed.");
+        }
+
+    },
   
     dispose: function() {
         $('.buttontoolbarview-tab', this.element).unbind('click.buttontoolbarview');
index caafa71..d24dfa9 100644 (file)
 /*global View CodeMirror ButtonToolbarView render_template panels */
 var XMLView = View.extend({
-  _className: 'XMLView',
-  element: null,
-  model: null,
-  template: 'xml-view-template',
-  editor: null,
-  buttonToolbar: null,
+    _className: 'XMLView',
+    element: null,
+    model: null,
+    template: 'xml-view-template',
+    editor: null,
+    buttonToolbar: null,
   
-  init: function(element, model, parent, template) {
-    this._super(element, model, template);
-    this.parent = parent;
-    this.buttonToolbar = new ButtonToolbarView(
-      $('.xmlview-toolbar', this.element), 
-      this.model.toolbarButtonsModel, parent);
+    init: function(element, model, parent, template) {
+        this._super(element, model, template);
+        this.parent = parent;
+        this.buttonToolbar = new ButtonToolbarView(
+            $('.xmlview-toolbar', this.element),
+            this.model.toolbarButtonsModel, parent);
 
-    $('.xmlview-toolbar', this.element).bind('resize.xmlview', this.resized.bind(this));
+        this.hotkeys = [];
+        var self = this;
+
+        $('.xmlview-toolbar', this.element).bind('resize.xmlview', this.resized.bind(this));
+   
     
-    this.parent.freeze('Ładowanie edytora...');
-       this.editor = new CodeMirror($('.xmlview', this.element).get(0), {
-      parserfile: 'parsexml.js',
-      path: "/static/js/lib/codemirror/",
-      stylesheet: "/static/css/xmlcolors.css",
-      parserConfig: {useHTMLKludges: false},
-      textWrapping: false,
-      tabMode: 'spaces',
-      indentUnit: 0,
-      onChange: this.editorDataChanged.bind(this),
-      initCallback: this.editorDidLoad.bind(this)
-    });
-  },
+        this.parent.freeze('Ładowanie edytora...');
+        this.editor = new CodeMirror($('.xmlview', this.element).get(0), {
+            parserfile: 'parsexml.js',
+            path: "/static/js/lib/codemirror/",
+            stylesheet: "/static/css/xmlcolors.css",
+            parserConfig: {
+                useHTMLKludges: false
+            },
+            textWrapping: false,
+            tabMode: 'spaces',
+            indentUnit: 0,
+            onChange: this.editorDataChanged.bind(this),
+            initCallback: this.editorDidLoad.bind(this)
+        });
+    },
   
-  resized: function(event) {
-    var height = this.element.height() - $('.xmlview-toolbar', this.element).outerHeight();
-    $('.xmlview', this.element).height(height);
-  },
+    resized: function(event) {
+        var height = this.element.height() - $('.xmlview-toolbar', this.element).outerHeight();
+        $('.xmlview', this.element).height(height);
+    },
   
-  reload: function() {
-    this.model.load(true);
-  },
+    reload: function() {
+        this.model.load(true);
+    },
   
-  editorDidLoad: function(editor) {
-    $(editor.frame).css({width: '100%', height: '100%'});
-    this.model
-      .addObserver(this, 'data', this.modelDataChanged.bind(this))
-      .addObserver(this, 'state', this.modelStateChanged.bind(this))
-      .load();
+    editorDidLoad: function(editor) {
+        $(editor.frame).css({
+            width: '100%',
+            height: '100%'
+        });
+        this.model
+        .addObserver(this, 'data', this.modelDataChanged.bind(this))
+        .addObserver(this, 'state', this.modelStateChanged.bind(this))
+        .load();
     
-    this.parent.unfreeze();
+        this.parent.unfreeze();
       
-    this.editor.setCode(this.model.get('data'));
-    this.modelStateChanged('state', this.model.get('state'));
+        this.editor.setCode(this.model.get('data'));
+        this.modelStateChanged('state', this.model.get('state'));
         
-    // editor.grabKeys(
-    //   $.fbind(self, self.hotkeyPressed),
-    //   $.fbind(self, self.isHotkey)
-    // );
-  },
+        editor.grabKeys(
+            this.hotkeyPressed.bind(this),
+            this.isHotkey.bind(this)
+            );
+    },
   
-  editorDataChanged: function() {
-    this.model.set('data', this.editor.getCode());
-  },
+    editorDataChanged: function() {
+        this.model.set('data', this.editor.getCode());
+    },
   
-  modelDataChanged: function(property, value) {
-    if (this.editor.getCode() != value) {
-      this.editor.setCode(value);
-    }
-  },
+    modelDataChanged: function(property, value) {
+        if (this.editor.getCode() != value) {
+            this.editor.setCode(value);
+        }
+    },
   
-  modelStateChanged: function(property, value) {
-    if (value == 'synced' || value == 'dirty') {
-      this.unfreeze();
-    } else if (value == 'unsynced') {
-      this.freeze('Niezsynchronizowany...');
-    } else if (value == 'loading') {
-      this.freeze('Ładowanie...');
-    } else if (value == 'saving') {
-      this.freeze('Zapisywanie...');
-    } else if (value == 'error') {
-      this.freeze(this.model.get('error'));
-    }
-  },
+    modelStateChanged: function(property, value) {
+        if (value == 'synced' || value == 'dirty') {
+            this.unfreeze();
+        } else if (value == 'unsynced') {
+            this.freeze('Niezsynchronizowany...');
+        } else if (value == 'loading') {
+            this.freeze('Ładowanie...');
+        } else if (value == 'saving') {
+            this.freeze('Zapisywanie...');
+        } else if (value == 'error') {
+            this.freeze(this.model.get('error'));
+        }
+    },
     
-  dispose: function() {
-    this.model.removeObserver(this);
-    $(this.editor.frame).remove();
-    this._super();
-  }
+    dispose: function() {
+        this.model.removeObserver(this);
+        $(this.editor.frame).remove();
+        this._super();
+    },    
+
+    getHotkey: function(event) {
+        var code = event.keyCode;
+        var ch = String.fromCharCode(code & 0xff).toLowerCase();
+        var button = $('.buttontoolbarview-button[title='+ch+']', this.element)[0]
+
+        console.log(ch, '#', button);       
+        var mod = 0;
+            
+        if(event.altKey) mod |= 0x01;
+        if(event.ctrlKey) mod |= 0x02;
+        if(event.shiftKey) mod |= 0x04;
+
+        if(button) {
+            var match = null;
+
+            $(button).each(function() {
+                if( parseInt($(this).attr('ui:hotkey_mod')) == mod ) {
+                    match = this;
+                    return;
+                }
+            })
+
+            return match;
+        }
+        else {
+            return null;
+        }
+    },
+
+    isHotkey: function() {
+        console.log(arguments);
+        
+        if(this.getHotkey.apply(this, arguments))
+            return true;
+        else
+            return false;
+    },
+
+    hotkeyPressed: function() {
+        var button = this.getHotkey.apply(this, arguments);
+        this.buttonToolbar.buttonPressed({
+            target: button
+        });
+    }
+
 });
 
+function Hotkey(code) {
+    this.code = code;
+    this.has_alt = ((code & 0x01 << 8) !== 0);
+    this.has_ctrl = ((code & 0x01 << 9) !== 0);
+    this.has_shift = ((code & 0x01 << 10) !== 0);
+    this.character = String.fromCharCode(code & 0xff);
+}
+
+Hotkey.prototype.toString = function() {
+    var mods = [];
+    if(this.has_alt) mods.push('Alt');
+    if(this.has_ctrl) mods.push('Ctrl');
+    if(this.has_shift) mods.push('Shift');
+    mods.push('"'+this.character+'"');
+    return mods.join('+');
+};
+
 // Register view
 panels['xml'] = XMLView;
index 7d288d3..85808f2 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" ui:groupindex="<%= i %>" ui:buttonindex="<%= j %>">
+                                               <button type="button" class="buttontoolbarview-button" 
+                                                    title="<%= 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 %>
                                                </button>
                                                <% } %>
             <textarea cols="60" rows="10" name="message" id="commit-dialog-message"></textarea>
             <p id="commit-dialog-error-empty-message">Wiadomość nie może być pusta.</p>                
             <fieldset id="commit-dialog-related-issues" 
-                      ui:ajax-src="http://localhost:3000/publications/issues/{{fileid}}">
+                      ui:ajax-src="{{REDMINE_URL}}/publications/issues/{{fileid}}">
                 <legend>Related issues</legend>
                 <div class="loading-box" style="display: none;">
                     <p>Loading related issues...</p>
diff --git a/project/templates/html4print.html b/project/templates/html4print.html
new file mode 100644 (file)
index 0000000..53a798a
--- /dev/null
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+  <head>
+    <title>{{docid}}</title>
+    <link rel="stylesheet" href="{{STATIC_URL}}css/html.css" type="text/css" charset="utf-8">
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+  </head>
+  <body>
+      <div class="htmlview">
+        {{ output|safe }}
+      </div>
+  </body>
+</html>