Quote escape dla tooltipów.
[redakcja.git] / project / static / js / views / xml.js
index 333b1c2..1681cae 100644 (file)
-/*global View CodeMirror render_template panels */
+/*global View CodeMirror ToolbarView render_template panels */
 var XMLView = View.extend({
-  element: null,
-  model: null,
-  template: 'xml-view-template',
-  editor: null,
+    _className: 'XMLView',
+    element: null,
+    model: null,
+    template: 'xml-view-template',
+    editor: null,
+    buttonToolbar: null,
   
-  init: function(element, model, template) {
-    this.element = $(element);
-    this.model = $(model).get(0);
-    this.template = template || this.template;
-    this.element.html(render_template(this.template, {}));
-    
-    this.model
-      .addObserver(this, 'xml-freeze')
-      .addObserver(this, 'xml-unfreeze');
+    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);
+
+        this.hotkeys = [];
+        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',
+            path: "/static/js/lib/codemirror/",
+            stylesheet: "/static/css/xmlcolors.css",
+            parserConfig: {
+                useHTMLKludges: false
+            },
+            textWrapping: true,
+            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);
+    },
+  
+    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();
     
-    this.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.changed.bind(this),
-      initCallback: this.editorDidLoad.bind(this)
-    });
-  },
+        this.parent.unfreeze();
+      
+        this.editor.setCode(this.model.get('data'));
+        this.modelStateChanged('state', this.model.get('state'));
+        
+        editor.grabKeys(
+            this.hotkeyPressed.bind(this),
+            this.isHotkey.bind(this)
+            );
+    },
   
-  changed: function() {
-    this.model.set('text', this.editor.getCode());
-  },
+    editorDataChanged: function() {
+        this.model.set('data', this.editor.getCode());
+    },
   
-  editorDidLoad: function(editor) {
-    editor.setCode('Ładowanie edytora...');
-    $(editor.frame).css({width: '100%', height: '100%'});
-    this.editor.setCode(this.model.get('text'));
-    this.model.addObserver(this, 'text-changed');
-    this.unfreeze();
-    // editor.grabKeys(
-    //   $.fbind(self, self.hotkeyPressed),
-    //   $.fbind(self, self.isHotkey)
-    // );
-  },
+    modelDataChanged: function(property, value) {
+        if (this.editor.getCode() != value) {
+            this.editor.setCode(value);
+        }
+    },
   
-  handle: function(event, data) {
-    console.log('handle', this, event, data);
-    if (event == 'text-changed') {
-      this.freeze('Niezsynchronizowany');
-      // this.unfreeze();      
-    } else if (event == 'xml-freeze') {
-      this.freeze('Ładowanie XMLa...');
-    } else if (event == 'xml-unfreeze') {
-      this.editor.setCode(this.model.get('text'));
-      this.unfreeze();
+    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() {
+        $(document).unbind('xml-scroll-request', this.scrollCallback);
+        
+        this.model.removeObserver(this);
+        $(this.editor.frame).remove();
+        this._super();
+    },    
+
+    getHotkey: function(event) {
+        var code = event.keyCode;
+        if(!((code >= 97 && code <= 122)
+           || (code >= 65 && code <= 90)) ) return null;
+
+        var ch = String.fromCharCode(code & 0xff).toLowerCase();
+        /* # console.log(ch.charCodeAt(0), '#', buttons); */
+
+        var buttons = $('.buttontoolbarview-button[hotkey='+ch+']', this.element);
+        var mod = 0;
+            
+        if(event.altKey) mod |= 0x01;
+        if(event.ctrlKey) mod |= 0x02;
+        if(event.shiftKey) mod |= 0x04;
+
+        if(buttons.length) {
+            var match = null;
+
+            buttons.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
+        });
+    },
+
+    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);
+        }
     }
-  },
-  
-  dispose: function() {
-    this.model.removeObserver(this);
-    $(this.editor.frame).remove();
-    this._super();
-  }
+
 });
 
+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.push({name: 'xml', klass: XMLView});
+panels['xml'] = XMLView;