Kolejne zmiany w fabfile i requirements.txt.
[redakcja.git] / platforma / static / js / views / xml.js
1 /*global View CodeMirror ToolbarView render_template panels */
2 var XMLView = View.extend({
3     _className: 'XMLView',
4     element: null,
5     model: null,
6     template: 'xml-view-template',
7     editor: null,
8     buttonToolbar: null,
9   
10     init: function(element, model, parent, template) {
11         this._super(element, model, template);
12         this.parent = parent;
13         this.buttonToolbar = new ButtonToolbarView(
14             $('.xmlview-toolbar', this.element),
15             this.model.toolbarButtonsModel, parent);
16
17         this.hotkeys = [];
18         var self = this;
19
20         $('.xmlview-toolbar', this.element).bind('resize.xmlview', this.resized.bind(this));
21
22         // scroll to the given position (if availble)
23         this.scrollCallback = this.scrollOnRequest.bind(this);
24         $(document).bind('xml-scroll-request', this.scrollCallback);
25        
26         this.parent.freeze('Ładowanie edytora...');
27         this.editor = new CodeMirror($('.xmlview', this.element).get(0), {
28             parserfile: 'parsexml.js',
29             path: "/static/js/lib/codemirror/",
30             stylesheet: "/static/css/xmlcolors.css",
31             parserConfig: {
32                 useHTMLKludges: false
33             },
34             textWrapping: true,
35             tabMode: 'spaces',
36             indentUnit: 0,
37             onChange: this.editorDataChanged.bind(this),
38             initCallback: this.editorDidLoad.bind(this)
39         });
40     },
41   
42     resized: function(event) {
43         var height = this.element.height() - $('.xmlview-toolbar', this.element).outerHeight();
44         $('.xmlview', this.element).height(height);
45     },
46   
47     reload: function() {
48         this.model.load(true);
49     },
50   
51     editorDidLoad: function(editor) {
52         $(editor.frame).css({
53             width: '100%',
54             height: '100%'
55         });
56         this.model
57         .addObserver(this, 'data', this.modelDataChanged.bind(this))
58         .addObserver(this, 'state', this.modelStateChanged.bind(this))
59         .load();
60     
61         this.parent.unfreeze();
62       
63         this.editor.setCode(this.model.get('data'));
64         this.modelStateChanged('state', this.model.get('state'));
65         
66         editor.grabKeys(
67             this.hotkeyPressed.bind(this),
68             this.isHotkey.bind(this)
69             );
70     },
71   
72     editorDataChanged: function() {
73         this.model.set('data', this.editor.getCode());
74     },
75   
76     modelDataChanged: function(property, value) {
77         if (this.editor.getCode() != value) {
78             this.editor.setCode(value);
79         }
80     },
81   
82     modelStateChanged: function(property, value) {
83         if (value == 'synced' || value == 'dirty') {
84             this.unfreeze();
85         } else if (value == 'unsynced') {
86             this.freeze('Niezsynchronizowany...');
87         } else if (value == 'loading') {
88             this.freeze('Ładowanie...');
89         } else if (value == 'saving') {
90             this.freeze('Zapisywanie...');
91         } else if (value == 'error') {
92             this.freeze(this.model.get('error'));
93         }
94     },
95     
96     dispose: function() {
97         $(document).unbind('xml-scroll-request', this.scrollCallback);
98         
99         this.model.removeObserver(this);
100         $(this.editor.frame).remove();
101         this._super();
102     },    
103
104     getHotkey: function(event) {
105         var code = event.keyCode;
106         if(!((code >= 97 && code <= 122)
107            || (code >= 65 && code <= 90)) ) return null;
108
109         var ch = String.fromCharCode(code & 0xff).toLowerCase();
110         /* # console.log(ch.charCodeAt(0), '#', buttons); */
111
112         var buttons = $('.buttontoolbarview-button[hotkey='+ch+']', this.element);
113         var mod = 0;
114             
115         if(event.altKey) mod |= 0x01;
116         if(event.ctrlKey) mod |= 0x02;
117         if(event.shiftKey) mod |= 0x04;
118
119         if(buttons.length) {
120             var match = null;
121
122             buttons.each(function() {
123                 if( parseInt($(this).attr('ui:hotkey_mod')) == mod ) {
124                     match = this;
125                     return;
126                 }
127             })
128
129             return match;
130         }
131         else {
132             return null;
133         }
134     },
135
136     isHotkey: function() {
137         /* console.log(arguments); */
138         if(this.getHotkey.apply(this, arguments))
139             return true;
140         else
141             return false;
142     },
143
144     hotkeyPressed: function() {
145         var button = this.getHotkey.apply(this, arguments);
146         this.buttonToolbar.buttonPressed({
147             target: button
148         });
149     },
150
151     scrollOnRequest: function(event, data) 
152     {
153         try {
154             var line = this.editor.nthLine(data.line);
155             this.editor.selectLines(line, (data.column-1));
156         } catch(e) {
157             console.log('Exception in scrollOnRequest:', e);
158         }
159     }
160
161 });
162
163 function Hotkey(code) {
164     this.code = code;
165     this.has_alt = ((code & 0x01 << 8) !== 0);
166     this.has_ctrl = ((code & 0x01 << 9) !== 0);
167     this.has_shift = ((code & 0x01 << 10) !== 0);
168     this.character = String.fromCharCode(code & 0xff);
169 }
170
171 Hotkey.prototype.toString = function() {
172     var mods = [];
173     if(this.has_alt) mods.push('Alt');
174     if(this.has_ctrl) mods.push('Ctrl');
175     if(this.has_shift) mods.push('Shift');
176     mods.push('"'+this.character+'"');
177     return mods.join('+');
178 };
179
180 // Register view
181 panels['xml'] = XMLView;