Roo/bootstrap/HtmlEditor.js
[roojs1] / Roo / bootstrap / HtmlEditor.js
1 /*
2  * - LGPL
3  *
4  * HtmlEditor
5  * 
6  */
7
8 /**
9  * @class Roo.bootstrap.HtmlEditor
10  * @extends Roo.bootstrap.Component
11  * Bootstrap HtmlEditor class
12
13  * @constructor
14  * Create a new HtmlEditor
15  * @param {Object} config The config object
16  */
17
18 Roo.bootstrap.HtmlEditor = function(config){
19     Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
20     if (!this.toolbars) {
21         this.toolbars = [];
22     }
23     this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
24     this.addEvents({
25             /**
26              * @event initialize
27              * Fires when the editor is fully initialized (including the iframe)
28              * @param {HtmlEditor} this
29              */
30             initialize: true,
31             /**
32              * @event activate
33              * Fires when the editor is first receives the focus. Any insertion must wait
34              * until after this event.
35              * @param {HtmlEditor} this
36              */
37             activate: true,
38              /**
39              * @event beforesync
40              * Fires before the textarea is updated with content from the editor iframe. Return false
41              * to cancel the sync.
42              * @param {HtmlEditor} this
43              * @param {String} html
44              */
45             beforesync: true,
46              /**
47              * @event beforepush
48              * Fires before the iframe editor is updated with content from the textarea. Return false
49              * to cancel the push.
50              * @param {HtmlEditor} this
51              * @param {String} html
52              */
53             beforepush: true,
54              /**
55              * @event sync
56              * Fires when the textarea is updated with content from the editor iframe.
57              * @param {HtmlEditor} this
58              * @param {String} html
59              */
60             sync: true,
61              /**
62              * @event push
63              * Fires when the iframe editor is updated with content from the textarea.
64              * @param {HtmlEditor} this
65              * @param {String} html
66              */
67             push: true,
68              /**
69              * @event editmodechange
70              * Fires when the editor switches edit modes
71              * @param {HtmlEditor} this
72              * @param {Boolean} sourceEdit True if source edit, false if standard editing.
73              */
74             editmodechange: true,
75             /**
76              * @event editorevent
77              * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
78              * @param {HtmlEditor} this
79              */
80             editorevent: true,
81             /**
82              * @event firstfocus
83              * Fires when on first focus - needed by toolbars..
84              * @param {HtmlEditor} this
85              */
86             firstfocus: true,
87             /**
88              * @event autosave
89              * Auto save the htmlEditor value as a file into Events
90              * @param {HtmlEditor} this
91              */
92             autosave: true,
93             /**
94              * @event savedpreview
95              * preview the saved version of htmlEditor
96              * @param {HtmlEditor} this
97              */
98             savedpreview: true
99         });
100 };
101
102
103 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea,  {
104     
105     
106       /**
107      * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
108      */
109     toolbars : false,
110    
111      /**
112      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
113      *                        Roo.resizable.
114      */
115     resizable : false,
116      /**
117      * @cfg {Number} height (in pixels)
118      */   
119     height: 300,
120    /**
121      * @cfg {Number} width (in pixels)
122      */   
123     width: 500,
124     
125     /**
126      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
127      * 
128      */
129     stylesheets: false,
130     
131     // id of frame..
132     frameId: false,
133     
134     // private properties
135     validationEvent : false,
136     deferHeight: true,
137     initialized : false,
138     activated : false,
139     
140     onFocus : Roo.emptyFn,
141     iframePad:3,
142     hideMode:'offsets',
143     
144      
145     toobarContainer :function() {
146         return this.wrap;
147     },
148
149     /**
150      * Protected method that will not generally be called directly. It
151      * is called when the editor creates its toolbar. Override this method if you need to
152      * add custom toolbar buttons.
153      * @param {HtmlEditor} editor
154      */
155     createToolbar : function(editor){
156         
157         
158         this.addxtypeChild({
159             
160         
161             xtype: 'Navbar',
162             xns: Roo.bootstrap,
163             bar: true,
164             items : [
165                 {
166                     xtype: 'NavGroup',
167                     xns: Roo.bootstrap,
168                     items : [
169                         {
170                             xtype: 'Item',
171                             xns: Roo.bootstrap.Navbar,
172                             html: "nav",
173                             href : 'http://roojs.com',
174                             
175                             menu:    {
176                                 xtype: 'Menu',
177                                 xns: Roo.bootstrap,
178                                 items : [
179                                     {
180                                         xtype: 'MenuItem',
181                                         xns: Roo.bootstrap,
182                                         html: "hello",
183                                         href : 'http://roojs.com'
184                                     },
185                                     {
186                                         xtype: 'MenuSeparator',
187                                         xns: Roo.bootstrap,
188                                     },
189                                     {
190                                         xtype: 'MenuItem',
191                                         xns: Roo.bootstrap,
192                                         html: "hello",
193                                         href: 'http://roojs.com'
194                                     }   
195                                 ]
196                             }
197                         }
198                     ]
199                 },
200                 {
201                     
202                     xtype: 'Form',
203                     xns: Roo.bootstrap,
204                     items : [
205                         {
206                             xtype: 'Input',
207                             xns: Roo.bootstrap,
208                             name : 'testinput'
209                         },{
210                         
211                             xtype: 'Button',
212                             xns: Roo.bootstrap,
213                             html : 'submit'
214                         }
215                     ]
216                 }
217             ]
218             
219             
220         }, 'toolbarContainer')
221         
222         Roo.log("create toolbars");
223         return;
224         if (!editor.toolbars || !editor.toolbars.length) {
225             editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
226         }
227         
228         for (var i =0 ; i < editor.toolbars.length;i++) {
229             editor.toolbars[i] = Roo.factory(
230                     typeof(editor.toolbars[i]) == 'string' ?
231                         { xtype: editor.toolbars[i]} : editor.toolbars[i],
232                 Roo.bootstrap.HtmlEditor);
233             editor.toolbars[i].init(editor);
234         }
235          
236         
237     },
238
239      
240     // private
241     onRender : function(ct, position)
242     {
243        // Roo.log("Call onRender: " + this.xtype);
244         
245         Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
246       
247         this.wrap = this.inputEl().wrap({
248             cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
249         });
250         
251         this.editorcore.onRender(ct, position);
252          
253         if (this.resizable) {
254             this.resizeEl = new Roo.Resizable(this.wrap, {
255                 pinned : true,
256                 wrap: true,
257                 dynamic : true,
258                 minHeight : this.height,
259                 height: this.height,
260                 handles : this.resizable,
261                 width: this.width,
262                 listeners : {
263                     resize : function(r, w, h) {
264                         _t.onResize(w,h); // -something
265                     }
266                 }
267             });
268             
269         }
270         this.createToolbar(this);
271        
272         
273         if(!this.width){
274             this.setSize(this.wrap.getSize());
275         }
276         if (this.resizeEl) {
277             this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
278             // should trigger onReize..
279         }
280         
281 //        if(this.autosave && this.w){
282 //            this.autoSaveFn = setInterval(this.autosave, 1000);
283 //        }
284     },
285
286     // private
287     onResize : function(w, h)
288     {
289         //Roo.log('resize: ' +w + ',' + h );
290         Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
291         var ew = false;
292         var eh = false;
293         
294         if(this.inputEl() ){
295             if(typeof w == 'number'){
296                 var aw = w - this.wrap.getFrameWidth('lr');
297                 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
298                 ew = aw;
299             }
300             if(typeof h == 'number'){
301                 var tbh = 0;
302                 for (var i =0; i < this.toolbars.length;i++) {
303                     // fixme - ask toolbars for heights?
304                     tbh += this.toolbars[i].tb.el.getHeight();
305                     if (this.toolbars[i].footer) {
306                         tbh += this.toolbars[i].footer.el.getHeight();
307                     }
308                 }
309                 
310                 
311                 
312                 
313                 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
314                 ah -= 5; // knock a few pixes off for look..
315                 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
316                 var eh = ah;
317             }
318         }
319         Roo.log('onResize:' + [w,h,ew,eh].join(',') );
320         this.editorcore.onResize(ew,eh);
321         
322     },
323
324     /**
325      * Toggles the editor between standard and source edit mode.
326      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
327      */
328     toggleSourceEdit : function(sourceEditMode)
329     {
330         this.editorcore.toggleSourceEdit(sourceEditMode);
331         
332         if(this.editorcore.sourceEditMode){
333             Roo.log('editor - showing textarea');
334             
335 //            Roo.log('in');
336 //            Roo.log(this.syncValue());
337             this.editorcore.syncValue();
338             this.inputEl().removeClass('hide');
339             this.inputEl().dom.removeAttribute('tabIndex');
340             this.inputEl().focus();
341         }else{
342             Roo.log('editor - hiding textarea');
343 //            Roo.log('out')
344 //            Roo.log(this.pushValue()); 
345             this.editorcore.pushValue();
346             
347             this.inputEl().addClass('hide');
348             this.inputEl().dom.setAttribute('tabIndex', -1);
349             //this.deferFocus();
350         }
351          
352         this.setSize(this.wrap.getSize());
353         this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
354     },
355  
356     // private (for BoxComponent)
357     adjustSize : Roo.BoxComponent.prototype.adjustSize,
358
359     // private (for BoxComponent)
360     getResizeEl : function(){
361         return this.wrap;
362     },
363
364     // private (for BoxComponent)
365     getPositionEl : function(){
366         return this.wrap;
367     },
368
369     // private
370     initEvents : function(){
371         this.originalValue = this.getValue();
372     },
373
374     /**
375      * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
376      * @method
377      */
378     markInvalid : Roo.emptyFn,
379     /**
380      * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
381      * @method
382      */
383     clearInvalid : Roo.emptyFn,
384
385     setValue : function(v){
386         Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
387         this.editorcore.pushValue();
388     },
389
390      
391     // private
392     deferFocus : function(){
393         this.focus.defer(10, this);
394     },
395
396     // doc'ed in Field
397     focus : function(){
398         this.editorcore.focus();
399         
400     },
401       
402
403     // private
404     onDestroy : function(){
405         
406         
407         
408         if(this.rendered){
409             
410             for (var i =0; i < this.toolbars.length;i++) {
411                 // fixme - ask toolbars for heights?
412                 this.toolbars[i].onDestroy();
413             }
414             
415             this.wrap.dom.innerHTML = '';
416             this.wrap.remove();
417         }
418     },
419
420     // private
421     onFirstFocus : function(){
422         //Roo.log("onFirstFocus");
423         this.editorcore.onFirstFocus();
424          for (var i =0; i < this.toolbars.length;i++) {
425             this.toolbars[i].onFirstFocus();
426         }
427         
428     },
429     
430     // private
431     syncValue : function()
432     {
433         this.editorcore.syncValue();
434     }
435      
436     
437     // hide stuff that is not compatible
438     /**
439      * @event blur
440      * @hide
441      */
442     /**
443      * @event change
444      * @hide
445      */
446     /**
447      * @event focus
448      * @hide
449      */
450     /**
451      * @event specialkey
452      * @hide
453      */
454     /**
455      * @cfg {String} fieldClass @hide
456      */
457     /**
458      * @cfg {String} focusClass @hide
459      */
460     /**
461      * @cfg {String} autoCreate @hide
462      */
463     /**
464      * @cfg {String} inputType @hide
465      */
466     /**
467      * @cfg {String} invalidClass @hide
468      */
469     /**
470      * @cfg {String} invalidText @hide
471      */
472     /**
473      * @cfg {String} msgFx @hide
474      */
475     /**
476      * @cfg {String} validateOnBlur @hide
477      */
478 });
479  
480     
481    
482    
483    
484