Bienvenue sur PostGIS.fr

Bienvenue sur PostGIS.fr , le site de la communauté des utilisateurs francophones de PostGIS.

PostGIS ajoute le support d'objets géographique à la base de données PostgreSQL. En effet, PostGIS "spatialise" le serverur PostgreSQL, ce qui permet de l'utiliser comme une base de données SIG.

Maintenu à jour, en fonction de nos disponibilités et des diverses sorties des outils que nous testons, nous vous proposons l'ensemble de nos travaux publiés en langue française.

source: trunk/workshop-routing-foss4g/web/ext/src/widgets/form/HtmlEditor.js @ 81

Revision 76, 38.5 KB checked in by djay, 13 years ago (diff)

Ajout du répertoire web

  • Property svn:executable set to *
Line 
1/*!
2 * Ext JS Library 3.4.0
3 * Copyright(c) 2006-2011 Sencha Inc.
4 * licensing@sencha.com
5 * http://www.sencha.com/license
6 */
7/**
8 * @class Ext.form.HtmlEditor
9 * @extends Ext.form.Field
10 * Provides a lightweight HTML Editor component. Some toolbar features are not supported by Safari and will be
11 * automatically hidden when needed.  These are noted in the config options where appropriate.
12 * <br><br>The editor's toolbar buttons have tooltips defined in the {@link #buttonTips} property, but they are not
13 * enabled by default unless the global {@link Ext.QuickTips} singleton is {@link Ext.QuickTips#init initialized}.
14 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
15 * supported by this editor.</b>
16 * <br><br>An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
17 * any element that has display set to 'none' can cause problems in Safari and Firefox due to their default iframe reloading bugs.
18 * <br><br>Example usage:
19 * <pre><code>
20// Simple example rendered with default options:
21Ext.QuickTips.init();  // enable tooltips
22new Ext.form.HtmlEditor({
23    renderTo: Ext.getBody(),
24    width: 800,
25    height: 300
26});
27
28// Passed via xtype into a container and with custom options:
29Ext.QuickTips.init();  // enable tooltips
30new Ext.Panel({
31    title: 'HTML Editor',
32    renderTo: Ext.getBody(),
33    width: 600,
34    height: 300,
35    frame: true,
36    layout: 'fit',
37    items: {
38        xtype: 'htmleditor',
39        enableColors: false,
40        enableAlignments: false
41    }
42});
43</code></pre>
44 * @constructor
45 * Create a new HtmlEditor
46 * @param {Object} config
47 * @xtype htmleditor
48 */
49
50Ext.form.HtmlEditor = Ext.extend(Ext.form.Field, {
51    /**
52     * @cfg {Boolean} enableFormat Enable the bold, italic and underline buttons (defaults to true)
53     */
54    enableFormat : true,
55    /**
56     * @cfg {Boolean} enableFontSize Enable the increase/decrease font size buttons (defaults to true)
57     */
58    enableFontSize : true,
59    /**
60     * @cfg {Boolean} enableColors Enable the fore/highlight color buttons (defaults to true)
61     */
62    enableColors : true,
63    /**
64     * @cfg {Boolean} enableAlignments Enable the left, center, right alignment buttons (defaults to true)
65     */
66    enableAlignments : true,
67    /**
68     * @cfg {Boolean} enableLists Enable the bullet and numbered list buttons. Not available in Safari. (defaults to true)
69     */
70    enableLists : true,
71    /**
72     * @cfg {Boolean} enableSourceEdit Enable the switch to source edit button. Not available in Safari. (defaults to true)
73     */
74    enableSourceEdit : true,
75    /**
76     * @cfg {Boolean} enableLinks Enable the create link button. Not available in Safari. (defaults to true)
77     */
78    enableLinks : true,
79    /**
80     * @cfg {Boolean} enableFont Enable font selection. Not available in Safari. (defaults to true)
81     */
82    enableFont : true,
83    /**
84     * @cfg {String} createLinkText The default text for the create link prompt
85     */
86    createLinkText : 'Please enter the URL for the link:',
87    /**
88     * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
89     */
90    defaultLinkValue : 'http:/'+'/',
91    /**
92     * @cfg {Array} fontFamilies An array of available font families
93     */
94    fontFamilies : [
95        'Arial',
96        'Courier New',
97        'Tahoma',
98        'Times New Roman',
99        'Verdana'
100    ],
101    defaultFont: 'tahoma',
102    /**
103     * @cfg {String} defaultValue A default value to be put into the editor to resolve focus issues (defaults to &#160; (Non-breaking space) in Opera and IE6, &#8203; (Zero-width space) in all other browsers).
104     */
105    defaultValue: (Ext.isOpera || Ext.isIE6) ? '&#160;' : '&#8203;',
106
107    // private properties
108    actionMode: 'wrap',
109    validationEvent : false,
110    deferHeight: true,
111    initialized : false,
112    activated : false,
113    sourceEditMode : false,
114    onFocus : Ext.emptyFn,
115    iframePad:3,
116    hideMode:'offsets',
117    defaultAutoCreate : {
118        tag: "textarea",
119        style:"width:500px;height:300px;",
120        autocomplete: "off"
121    },
122
123    // private
124    initComponent : function(){
125        this.addEvents(
126            /**
127             * @event initialize
128             * Fires when the editor is fully initialized (including the iframe)
129             * @param {HtmlEditor} this
130             */
131            'initialize',
132            /**
133             * @event activate
134             * Fires when the editor is first receives the focus. Any insertion must wait
135             * until after this event.
136             * @param {HtmlEditor} this
137             */
138            'activate',
139             /**
140             * @event beforesync
141             * Fires before the textarea is updated with content from the editor iframe. Return false
142             * to cancel the sync.
143             * @param {HtmlEditor} this
144             * @param {String} html
145             */
146            'beforesync',
147             /**
148             * @event beforepush
149             * Fires before the iframe editor is updated with content from the textarea. Return false
150             * to cancel the push.
151             * @param {HtmlEditor} this
152             * @param {String} html
153             */
154            'beforepush',
155             /**
156             * @event sync
157             * Fires when the textarea is updated with content from the editor iframe.
158             * @param {HtmlEditor} this
159             * @param {String} html
160             */
161            'sync',
162             /**
163             * @event push
164             * Fires when the iframe editor is updated with content from the textarea.
165             * @param {HtmlEditor} this
166             * @param {String} html
167             */
168            'push',
169             /**
170             * @event editmodechange
171             * Fires when the editor switches edit modes
172             * @param {HtmlEditor} this
173             * @param {Boolean} sourceEdit True if source edit, false if standard editing.
174             */
175            'editmodechange'
176        );
177        Ext.form.HtmlEditor.superclass.initComponent.call(this);
178    },
179
180    // private
181    createFontOptions : function(){
182        var buf = [], fs = this.fontFamilies, ff, lc;
183        for(var i = 0, len = fs.length; i< len; i++){
184            ff = fs[i];
185            lc = ff.toLowerCase();
186            buf.push(
187                '<option value="',lc,'" style="font-family:',ff,';"',
188                    (this.defaultFont == lc ? ' selected="true">' : '>'),
189                    ff,
190                '</option>'
191            );
192        }
193        return buf.join('');
194    },
195
196    /*
197     * Protected method that will not generally be called directly. It
198     * is called when the editor creates its toolbar. Override this method if you need to
199     * add custom toolbar buttons.
200     * @param {HtmlEditor} editor
201     */
202    createToolbar : function(editor){
203        var items = [];
204        var tipsEnabled = Ext.QuickTips && Ext.QuickTips.isEnabled();
205
206
207        function btn(id, toggle, handler){
208            return {
209                itemId : id,
210                cls : 'x-btn-icon',
211                iconCls: 'x-edit-'+id,
212                enableToggle:toggle !== false,
213                scope: editor,
214                handler:handler||editor.relayBtnCmd,
215                clickEvent:'mousedown',
216                tooltip: tipsEnabled ? editor.buttonTips[id] || undefined : undefined,
217                overflowText: editor.buttonTips[id].title || undefined,
218                tabIndex:-1
219            };
220        }
221
222
223        if(this.enableFont && !Ext.isSafari2){
224            var fontSelectItem = new Ext.Toolbar.Item({
225               autoEl: {
226                    tag:'select',
227                    cls:'x-font-select',
228                    html: this.createFontOptions()
229               }
230            });
231
232            items.push(
233                fontSelectItem,
234                '-'
235            );
236        }
237
238        if(this.enableFormat){
239            items.push(
240                btn('bold'),
241                btn('italic'),
242                btn('underline')
243            );
244        }
245
246        if(this.enableFontSize){
247            items.push(
248                '-',
249                btn('increasefontsize', false, this.adjustFont),
250                btn('decreasefontsize', false, this.adjustFont)
251            );
252        }
253
254        if(this.enableColors){
255            items.push(
256                '-', {
257                    itemId:'forecolor',
258                    cls:'x-btn-icon',
259                    iconCls: 'x-edit-forecolor',
260                    clickEvent:'mousedown',
261                    tooltip: tipsEnabled ? editor.buttonTips.forecolor || undefined : undefined,
262                    tabIndex:-1,
263                    menu : new Ext.menu.ColorMenu({
264                        allowReselect: true,
265                        focus: Ext.emptyFn,
266                        value:'000000',
267                        plain:true,
268                        listeners: {
269                            scope: this,
270                            select: function(cp, color){
271                                this.execCmd('forecolor', Ext.isWebKit || Ext.isIE ? '#'+color : color);
272                                this.deferFocus();
273                            }
274                        },
275                        clickEvent:'mousedown'
276                    })
277                }, {
278                    itemId:'backcolor',
279                    cls:'x-btn-icon',
280                    iconCls: 'x-edit-backcolor',
281                    clickEvent:'mousedown',
282                    tooltip: tipsEnabled ? editor.buttonTips.backcolor || undefined : undefined,
283                    tabIndex:-1,
284                    menu : new Ext.menu.ColorMenu({
285                        focus: Ext.emptyFn,
286                        value:'FFFFFF',
287                        plain:true,
288                        allowReselect: true,
289                        listeners: {
290                            scope: this,
291                            select: function(cp, color){
292                                if(Ext.isGecko){
293                                    this.execCmd('useCSS', false);
294                                    this.execCmd('hilitecolor', color);
295                                    this.execCmd('useCSS', true);
296                                    this.deferFocus();
297                                }else{
298                                    this.execCmd(Ext.isOpera ? 'hilitecolor' : 'backcolor', Ext.isWebKit || Ext.isIE ? '#'+color : color);
299                                    this.deferFocus();
300                                }
301                            }
302                        },
303                        clickEvent:'mousedown'
304                    })
305                }
306            );
307        }
308
309        if(this.enableAlignments){
310            items.push(
311                '-',
312                btn('justifyleft'),
313                btn('justifycenter'),
314                btn('justifyright')
315            );
316        }
317
318        if(!Ext.isSafari2){
319            if(this.enableLinks){
320                items.push(
321                    '-',
322                    btn('createlink', false, this.createLink)
323                );
324            }
325
326            if(this.enableLists){
327                items.push(
328                    '-',
329                    btn('insertorderedlist'),
330                    btn('insertunorderedlist')
331                );
332            }
333            if(this.enableSourceEdit){
334                items.push(
335                    '-',
336                    btn('sourceedit', true, function(btn){
337                        this.toggleSourceEdit(!this.sourceEditMode);
338                    })
339                );
340            }
341        }
342
343        // build the toolbar
344        var tb = new Ext.Toolbar({
345            renderTo: this.wrap.dom.firstChild,
346            items: items
347        });
348
349        if (fontSelectItem) {
350            this.fontSelect = fontSelectItem.el;
351
352            this.mon(this.fontSelect, 'change', function(){
353                var font = this.fontSelect.dom.value;
354                this.relayCmd('fontname', font);
355                this.deferFocus();
356            }, this);
357        }
358
359        // stop form submits
360        this.mon(tb.el, 'click', function(e){
361            e.preventDefault();
362        });
363
364        this.tb = tb;
365        this.tb.doLayout();
366    },
367
368    onDisable: function(){
369        this.wrap.mask();
370        Ext.form.HtmlEditor.superclass.onDisable.call(this);
371    },
372
373    onEnable: function(){
374        this.wrap.unmask();
375        Ext.form.HtmlEditor.superclass.onEnable.call(this);
376    },
377
378    setReadOnly: function(readOnly){
379
380        Ext.form.HtmlEditor.superclass.setReadOnly.call(this, readOnly);
381        if(this.initialized){
382            if(Ext.isIE){
383                this.getEditorBody().contentEditable = !readOnly;
384            }else{
385                this.setDesignMode(!readOnly);
386            }
387            var bd = this.getEditorBody();
388            if(bd){
389                bd.style.cursor = this.readOnly ? 'default' : 'text';
390            }
391            this.disableItems(readOnly);
392        }
393    },
394
395    /**
396     * Protected method that will not generally be called directly. It
397     * is called when the editor initializes the iframe with HTML contents. Override this method if you
398     * want to change the initialization markup of the iframe (e.g. to add stylesheets).
399     *
400     * Note: IE8-Standards has unwanted scroller behavior, so the default meta tag forces IE7 compatibility
401     */
402    getDocMarkup : function(){
403        var h = Ext.fly(this.iframe).getHeight() - this.iframePad * 2;
404        return String.format('<html><head><style type="text/css">body{border: 0; margin: 0; padding: {0}px; height: {1}px; cursor: text}</style></head><body></body></html>', this.iframePad, h);
405    },
406
407    // private
408    getEditorBody : function(){
409        var doc = this.getDoc();
410        return doc.body || doc.documentElement;
411    },
412
413    // private
414    getDoc : function(){
415        return Ext.isIE ? this.getWin().document : (this.iframe.contentDocument || this.getWin().document);
416    },
417
418    // private
419    getWin : function(){
420        return Ext.isIE ? this.iframe.contentWindow : window.frames[this.iframe.name];
421    },
422
423    // private
424    onRender : function(ct, position){
425        Ext.form.HtmlEditor.superclass.onRender.call(this, ct, position);
426        this.el.dom.style.border = '0 none';
427        this.el.dom.setAttribute('tabIndex', -1);
428        this.el.addClass('x-hidden');
429        if(Ext.isIE){ // fix IE 1px bogus margin
430            this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;');
431        }
432        this.wrap = this.el.wrap({
433            cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
434        });
435
436        this.createToolbar(this);
437
438        this.disableItems(true);
439
440        this.tb.doLayout();
441
442        this.createIFrame();
443
444        if(!this.width){
445            var sz = this.el.getSize();
446            this.setSize(sz.width, this.height || sz.height);
447        }
448        this.resizeEl = this.positionEl = this.wrap;
449    },
450
451    createIFrame: function(){
452        var iframe = document.createElement('iframe');
453        iframe.name = Ext.id();
454        iframe.frameBorder = '0';
455        iframe.style.overflow = 'auto';
456        iframe.src = Ext.SSL_SECURE_URL;
457
458        this.wrap.dom.appendChild(iframe);
459        this.iframe = iframe;
460
461        this.monitorTask = Ext.TaskMgr.start({
462            run: this.checkDesignMode,
463            scope: this,
464            interval:100
465        });
466    },
467
468    initFrame : function(){
469        Ext.TaskMgr.stop(this.monitorTask);
470        var doc = this.getDoc();
471        this.win = this.getWin();
472
473        doc.open();
474        doc.write(this.getDocMarkup());
475        doc.close();
476
477        var task = { // must defer to wait for browser to be ready
478            run : function(){
479                var doc = this.getDoc();
480                if(doc.body || doc.readyState == 'complete'){
481                    Ext.TaskMgr.stop(task);
482                    this.setDesignMode(true);
483                    this.initEditor.defer(10, this);
484                }
485            },
486            interval : 10,
487            duration:10000,
488            scope: this
489        };
490        Ext.TaskMgr.start(task);
491    },
492
493
494    checkDesignMode : function(){
495        if(this.wrap && this.wrap.dom.offsetWidth){
496            var doc = this.getDoc();
497            if(!doc){
498                return;
499            }
500            if(!doc.editorInitialized || this.getDesignMode() != 'on'){
501                this.initFrame();
502            }
503        }
504    },
505
506    /* private
507     * set current design mode. To enable, mode can be true or 'on', off otherwise
508     */
509    setDesignMode : function(mode){
510        var doc = this.getDoc();
511        if (doc) {
512            if(this.readOnly){
513                mode = false;
514            }
515            doc.designMode = (/on|true/i).test(String(mode).toLowerCase()) ?'on':'off';
516        }
517
518    },
519
520    // private
521    getDesignMode : function(){
522        var doc = this.getDoc();
523        if(!doc){ return ''; }
524        return String(doc.designMode).toLowerCase();
525
526    },
527
528    disableItems: function(disabled){
529        if(this.fontSelect){
530            this.fontSelect.dom.disabled = disabled;
531        }
532        this.tb.items.each(function(item){
533            if(item.getItemId() != 'sourceedit'){
534                item.setDisabled(disabled);
535            }
536        });
537    },
538
539    // private
540    onResize : function(w, h){
541        Ext.form.HtmlEditor.superclass.onResize.apply(this, arguments);
542        if(this.el && this.iframe){
543            if(Ext.isNumber(w)){
544                var aw = w - this.wrap.getFrameWidth('lr');
545                this.el.setWidth(aw);
546                this.tb.setWidth(aw);
547                this.iframe.style.width = Math.max(aw, 0) + 'px';
548            }
549            if(Ext.isNumber(h)){
550                var ah = h - this.wrap.getFrameWidth('tb') - this.tb.el.getHeight();
551                this.el.setHeight(ah);
552                this.iframe.style.height = Math.max(ah, 0) + 'px';
553                var bd = this.getEditorBody();
554                if(bd){
555                    bd.style.height = Math.max((ah - (this.iframePad*2)), 0) + 'px';
556                }
557            }
558        }
559    },
560
561    /**
562     * Toggles the editor between standard and source edit mode.
563     * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
564     */
565    toggleSourceEdit : function(sourceEditMode){
566        var iframeHeight,
567            elHeight;
568
569        if (sourceEditMode === undefined) {
570            sourceEditMode = !this.sourceEditMode;
571        }
572        this.sourceEditMode = sourceEditMode === true;
573        var btn = this.tb.getComponent('sourceedit');
574
575        if (btn.pressed !== this.sourceEditMode) {
576            btn.toggle(this.sourceEditMode);
577            if (!btn.xtbHidden) {
578                return;
579            }
580        }
581        if (this.sourceEditMode) {
582            // grab the height of the containing panel before we hide the iframe
583            this.previousSize = this.getSize();
584
585            iframeHeight = Ext.get(this.iframe).getHeight();
586
587            this.disableItems(true);
588            this.syncValue();
589            this.iframe.className = 'x-hidden';
590            this.el.removeClass('x-hidden');
591            this.el.dom.removeAttribute('tabIndex');
592            this.el.focus();
593            this.el.dom.style.height = iframeHeight + 'px';
594        }
595        else {
596            elHeight = parseInt(this.el.dom.style.height, 10);
597            if (this.initialized) {
598                this.disableItems(this.readOnly);
599            }
600            this.pushValue();
601            this.iframe.className = '';
602            this.el.addClass('x-hidden');
603            this.el.dom.setAttribute('tabIndex', -1);
604            this.deferFocus();
605
606            this.setSize(this.previousSize);
607            delete this.previousSize;
608            this.iframe.style.height = elHeight + 'px';
609        }
610        this.fireEvent('editmodechange', this, this.sourceEditMode);
611    },
612
613    // private used internally
614    createLink : function() {
615        var url = prompt(this.createLinkText, this.defaultLinkValue);
616        if(url && url != 'http:/'+'/'){
617            this.relayCmd('createlink', url);
618        }
619    },
620
621    // private
622    initEvents : function(){
623        this.originalValue = this.getValue();
624    },
625
626    /**
627     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
628     * @method
629     */
630    markInvalid : Ext.emptyFn,
631
632    /**
633     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
634     * @method
635     */
636    clearInvalid : Ext.emptyFn,
637
638    // docs inherit from Field
639    setValue : function(v){
640        Ext.form.HtmlEditor.superclass.setValue.call(this, v);
641        this.pushValue();
642        return this;
643    },
644
645    /**
646     * Protected method that will not generally be called directly. If you need/want
647     * custom HTML cleanup, this is the method you should override.
648     * @param {String} html The HTML to be cleaned
649     * @return {String} The cleaned HTML
650     */
651    cleanHtml: function(html) {
652        html = String(html);
653        if(Ext.isWebKit){ // strip safari nonsense
654            html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
655        }
656
657        /*
658         * Neat little hack. Strips out all the non-digit characters from the default
659         * value and compares it to the character code of the first character in the string
660         * because it can cause encoding issues when posted to the server.
661         */
662        if(html.charCodeAt(0) == this.defaultValue.replace(/\D/g, '')){
663            html = html.substring(1);
664        }
665        return html;
666    },
667
668    /**
669     * Protected method that will not generally be called directly. Syncs the contents
670     * of the editor iframe with the textarea.
671     */
672    syncValue : function(){
673        if(this.initialized){
674            var bd = this.getEditorBody();
675            var html = bd.innerHTML;
676            if(Ext.isWebKit){
677                var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
678                var m = bs.match(/text-align:(.*?);/i);
679                if(m && m[1]){
680                    html = '<div style="'+m[0]+'">' + html + '</div>';
681                }
682            }
683            html = this.cleanHtml(html);
684            if(this.fireEvent('beforesync', this, html) !== false){
685                this.el.dom.value = html;
686                this.fireEvent('sync', this, html);
687            }
688        }
689    },
690
691    //docs inherit from Field
692    getValue : function() {
693        this[this.sourceEditMode ? 'pushValue' : 'syncValue']();
694        return Ext.form.HtmlEditor.superclass.getValue.call(this);
695    },
696
697    /**
698     * Protected method that will not generally be called directly. Pushes the value of the textarea
699     * into the iframe editor.
700     */
701    pushValue : function(){
702        if(this.initialized){
703            var v = this.el.dom.value;
704            if(!this.activated && v.length < 1){
705                v = this.defaultValue;
706            }
707            if(this.fireEvent('beforepush', this, v) !== false){
708                this.getEditorBody().innerHTML = v;
709                if(Ext.isGecko){
710                    // Gecko hack, see: https://bugzilla.mozilla.org/show_bug.cgi?id=232791#c8
711                    this.setDesignMode(false);  //toggle off first
712                    this.setDesignMode(true);
713                }
714                this.fireEvent('push', this, v);
715            }
716
717        }
718    },
719
720    // private
721    deferFocus : function(){
722        this.focus.defer(10, this);
723    },
724
725    // docs inherit from Field
726    focus : function(){
727        if(this.win && !this.sourceEditMode){
728            this.win.focus();
729        }else{
730            this.el.focus();
731        }
732    },
733
734    // private
735    initEditor : function(){
736        //Destroying the component during/before initEditor can cause issues.
737        try{
738            var dbody = this.getEditorBody(),
739                ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat', 'background-color', 'color'),
740                doc,
741                fn;
742
743            ss['background-attachment'] = 'fixed'; // w3c
744            dbody.bgProperties = 'fixed'; // ie
745
746            Ext.DomHelper.applyStyles(dbody, ss);
747
748            doc = this.getDoc();
749
750            if(doc){
751                try{
752                    Ext.EventManager.removeAll(doc);
753                }catch(e){}
754            }
755
756            /*
757             * We need to use createDelegate here, because when using buffer, the delayed task is added
758             * as a property to the function. When the listener is removed, the task is deleted from the function.
759             * Since onEditorEvent is shared on the prototype, if we have multiple html editors, the first time one of the editors
760             * is destroyed, it causes the fn to be deleted from the prototype, which causes errors. Essentially, we're just anonymizing the function.
761             */
762            fn = this.onEditorEvent.createDelegate(this);
763            Ext.EventManager.on(doc, {
764                mousedown: fn,
765                dblclick: fn,
766                click: fn,
767                keyup: fn,
768                buffer:100
769            });
770
771            if(Ext.isGecko){
772                Ext.EventManager.on(doc, 'keypress', this.applyCommand, this);
773            }
774            if(Ext.isIE || Ext.isWebKit || Ext.isOpera){
775                Ext.EventManager.on(doc, 'keydown', this.fixKeys, this);
776            }
777            doc.editorInitialized = true;
778            this.initialized = true;
779            this.pushValue();
780            this.setReadOnly(this.readOnly);
781            this.fireEvent('initialize', this);
782        }catch(e){}
783    },
784
785    // private
786    beforeDestroy : function(){
787        if(this.monitorTask){
788            Ext.TaskMgr.stop(this.monitorTask);
789        }
790        if(this.rendered){
791            Ext.destroy(this.tb);
792            var doc = this.getDoc();
793            if(doc){
794                try{
795                    Ext.EventManager.removeAll(doc);
796                    for (var prop in doc){
797                        delete doc[prop];
798                    }
799                }catch(e){}
800            }
801            if(this.wrap){
802                this.wrap.dom.innerHTML = '';
803                this.wrap.remove();
804            }
805        }
806        Ext.form.HtmlEditor.superclass.beforeDestroy.call(this);
807    },
808
809    // private
810    onFirstFocus : function(){
811        this.activated = true;
812        this.disableItems(this.readOnly);
813        if(Ext.isGecko){ // prevent silly gecko errors
814            this.win.focus();
815            var s = this.win.getSelection();
816            if(!s.focusNode || s.focusNode.nodeType != 3){
817                var r = s.getRangeAt(0);
818                r.selectNodeContents(this.getEditorBody());
819                r.collapse(true);
820                this.deferFocus();
821            }
822            try{
823                this.execCmd('useCSS', true);
824                this.execCmd('styleWithCSS', false);
825            }catch(e){}
826        }
827        this.fireEvent('activate', this);
828    },
829
830    // private
831    adjustFont: function(btn){
832        var adjust = btn.getItemId() == 'increasefontsize' ? 1 : -1,
833            doc = this.getDoc(),
834            v = parseInt(doc.queryCommandValue('FontSize') || 2, 10);
835        if((Ext.isSafari && !Ext.isSafari2) || Ext.isChrome || Ext.isAir){
836            // Safari 3 values
837            // 1 = 10px, 2 = 13px, 3 = 16px, 4 = 18px, 5 = 24px, 6 = 32px
838            if(v <= 10){
839                v = 1 + adjust;
840            }else if(v <= 13){
841                v = 2 + adjust;
842            }else if(v <= 16){
843                v = 3 + adjust;
844            }else if(v <= 18){
845                v = 4 + adjust;
846            }else if(v <= 24){
847                v = 5 + adjust;
848            }else {
849                v = 6 + adjust;
850            }
851            v = v.constrain(1, 6);
852        }else{
853            if(Ext.isSafari){ // safari
854                adjust *= 2;
855            }
856            v = Math.max(1, v+adjust) + (Ext.isSafari ? 'px' : 0);
857        }
858        this.execCmd('FontSize', v);
859    },
860
861    // private
862    onEditorEvent : function(e){
863        this.updateToolbar();
864    },
865
866
867    /**
868     * Protected method that will not generally be called directly. It triggers
869     * a toolbar update by reading the markup state of the current selection in the editor.
870     */
871    updateToolbar: function(){
872
873        if(this.readOnly){
874            return;
875        }
876
877        if(!this.activated){
878            this.onFirstFocus();
879            return;
880        }
881
882        var btns = this.tb.items.map,
883            doc = this.getDoc();
884
885        if(this.enableFont && !Ext.isSafari2){
886            var name = (doc.queryCommandValue('FontName')||this.defaultFont).toLowerCase();
887            if(name != this.fontSelect.dom.value){
888                this.fontSelect.dom.value = name;
889            }
890        }
891        if(this.enableFormat){
892            btns.bold.toggle(doc.queryCommandState('bold'));
893            btns.italic.toggle(doc.queryCommandState('italic'));
894            btns.underline.toggle(doc.queryCommandState('underline'));
895        }
896        if(this.enableAlignments){
897            btns.justifyleft.toggle(doc.queryCommandState('justifyleft'));
898            btns.justifycenter.toggle(doc.queryCommandState('justifycenter'));
899            btns.justifyright.toggle(doc.queryCommandState('justifyright'));
900        }
901        if(!Ext.isSafari2 && this.enableLists){
902            btns.insertorderedlist.toggle(doc.queryCommandState('insertorderedlist'));
903            btns.insertunorderedlist.toggle(doc.queryCommandState('insertunorderedlist'));
904        }
905
906        Ext.menu.MenuMgr.hideAll();
907
908        this.syncValue();
909    },
910
911    // private
912    relayBtnCmd : function(btn){
913        this.relayCmd(btn.getItemId());
914    },
915
916    /**
917     * Executes a Midas editor command on the editor document and performs necessary focus and
918     * toolbar updates. <b>This should only be called after the editor is initialized.</b>
919     * @param {String} cmd The Midas command
920     * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
921     */
922    relayCmd : function(cmd, value){
923        (function(){
924            this.focus();
925            this.execCmd(cmd, value);
926            this.updateToolbar();
927        }).defer(10, this);
928    },
929
930    /**
931     * Executes a Midas editor command directly on the editor document.
932     * For visual commands, you should use {@link #relayCmd} instead.
933     * <b>This should only be called after the editor is initialized.</b>
934     * @param {String} cmd The Midas command
935     * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
936     */
937    execCmd : function(cmd, value){
938        var doc = this.getDoc();
939        doc.execCommand(cmd, false, value === undefined ? null : value);
940        this.syncValue();
941    },
942
943    // private
944    applyCommand : function(e){
945        if(e.ctrlKey){
946            var c = e.getCharCode(), cmd;
947            if(c > 0){
948                c = String.fromCharCode(c);
949                switch(c){
950                    case 'b':
951                        cmd = 'bold';
952                    break;
953                    case 'i':
954                        cmd = 'italic';
955                    break;
956                    case 'u':
957                        cmd = 'underline';
958                    break;
959                }
960                if(cmd){
961                    this.win.focus();
962                    this.execCmd(cmd);
963                    this.deferFocus();
964                    e.preventDefault();
965                }
966            }
967        }
968    },
969
970    /**
971     * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
972     * to insert text.
973     * @param {String} text
974     */
975    insertAtCursor : function(text){
976        if(!this.activated){
977            return;
978        }
979        if(Ext.isIE){
980            this.win.focus();
981            var doc = this.getDoc(),
982                r = doc.selection.createRange();
983            if(r){
984                r.pasteHTML(text);
985                this.syncValue();
986                this.deferFocus();
987            }
988        }else{
989            this.win.focus();
990            this.execCmd('InsertHTML', text);
991            this.deferFocus();
992        }
993    },
994
995    // private
996    fixKeys : function(){ // load time branching for fastest keydown performance
997        if(Ext.isIE){
998            return function(e){
999                var k = e.getKey(),
1000                    doc = this.getDoc(),
1001                        r;
1002                if(k == e.TAB){
1003                    e.stopEvent();
1004                    r = doc.selection.createRange();
1005                    if(r){
1006                        r.collapse(true);
1007                        r.pasteHTML('&nbsp;&nbsp;&nbsp;&nbsp;');
1008                        this.deferFocus();
1009                    }
1010                }else if(k == e.ENTER){
1011                    r = doc.selection.createRange();
1012                    if(r){
1013                        var target = r.parentElement();
1014                        if(!target || target.tagName.toLowerCase() != 'li'){
1015                            e.stopEvent();
1016                            r.pasteHTML('<br />');
1017                            r.collapse(false);
1018                            r.select();
1019                        }
1020                    }
1021                }
1022            };
1023        }else if(Ext.isOpera){
1024            return function(e){
1025                var k = e.getKey();
1026                if(k == e.TAB){
1027                    e.stopEvent();
1028                    this.win.focus();
1029                    this.execCmd('InsertHTML','&nbsp;&nbsp;&nbsp;&nbsp;');
1030                    this.deferFocus();
1031                }
1032            };
1033        }else if(Ext.isWebKit){
1034            return function(e){
1035                var k = e.getKey();
1036                if(k == e.TAB){
1037                    e.stopEvent();
1038                    this.execCmd('InsertText','\t');
1039                    this.deferFocus();
1040                }else if(k == e.ENTER){
1041                    e.stopEvent();
1042                    this.execCmd('InsertHtml','<br /><br />');
1043                    this.deferFocus();
1044                }
1045             };
1046        }
1047    }(),
1048
1049    /**
1050     * Returns the editor's toolbar. <b>This is only available after the editor has been rendered.</b>
1051     * @return {Ext.Toolbar}
1052     */
1053    getToolbar : function(){
1054        return this.tb;
1055    },
1056
1057    /**
1058     * Object collection of toolbar tooltips for the buttons in the editor. The key
1059     * is the command id associated with that button and the value is a valid QuickTips object.
1060     * For example:
1061<pre><code>
1062{
1063    bold : {
1064        title: 'Bold (Ctrl+B)',
1065        text: 'Make the selected text bold.',
1066        cls: 'x-html-editor-tip'
1067    },
1068    italic : {
1069        title: 'Italic (Ctrl+I)',
1070        text: 'Make the selected text italic.',
1071        cls: 'x-html-editor-tip'
1072    },
1073    ...
1074</code></pre>
1075    * @type Object
1076     */
1077    buttonTips : {
1078        bold : {
1079            title: 'Bold (Ctrl+B)',
1080            text: 'Make the selected text bold.',
1081            cls: 'x-html-editor-tip'
1082        },
1083        italic : {
1084            title: 'Italic (Ctrl+I)',
1085            text: 'Make the selected text italic.',
1086            cls: 'x-html-editor-tip'
1087        },
1088        underline : {
1089            title: 'Underline (Ctrl+U)',
1090            text: 'Underline the selected text.',
1091            cls: 'x-html-editor-tip'
1092        },
1093        increasefontsize : {
1094            title: 'Grow Text',
1095            text: 'Increase the font size.',
1096            cls: 'x-html-editor-tip'
1097        },
1098        decreasefontsize : {
1099            title: 'Shrink Text',
1100            text: 'Decrease the font size.',
1101            cls: 'x-html-editor-tip'
1102        },
1103        backcolor : {
1104            title: 'Text Highlight Color',
1105            text: 'Change the background color of the selected text.',
1106            cls: 'x-html-editor-tip'
1107        },
1108        forecolor : {
1109            title: 'Font Color',
1110            text: 'Change the color of the selected text.',
1111            cls: 'x-html-editor-tip'
1112        },
1113        justifyleft : {
1114            title: 'Align Text Left',
1115            text: 'Align text to the left.',
1116            cls: 'x-html-editor-tip'
1117        },
1118        justifycenter : {
1119            title: 'Center Text',
1120            text: 'Center text in the editor.',
1121            cls: 'x-html-editor-tip'
1122        },
1123        justifyright : {
1124            title: 'Align Text Right',
1125            text: 'Align text to the right.',
1126            cls: 'x-html-editor-tip'
1127        },
1128        insertunorderedlist : {
1129            title: 'Bullet List',
1130            text: 'Start a bulleted list.',
1131            cls: 'x-html-editor-tip'
1132        },
1133        insertorderedlist : {
1134            title: 'Numbered List',
1135            text: 'Start a numbered list.',
1136            cls: 'x-html-editor-tip'
1137        },
1138        createlink : {
1139            title: 'Hyperlink',
1140            text: 'Make the selected text a hyperlink.',
1141            cls: 'x-html-editor-tip'
1142        },
1143        sourceedit : {
1144            title: 'Source Edit',
1145            text: 'Switch to source editing mode.',
1146            cls: 'x-html-editor-tip'
1147        }
1148    }
1149
1150    // hide stuff that is not compatible
1151    /**
1152     * @event blur
1153     * @hide
1154     */
1155    /**
1156     * @event change
1157     * @hide
1158     */
1159    /**
1160     * @event focus
1161     * @hide
1162     */
1163    /**
1164     * @event specialkey
1165     * @hide
1166     */
1167    /**
1168     * @cfg {String} fieldClass @hide
1169     */
1170    /**
1171     * @cfg {String} focusClass @hide
1172     */
1173    /**
1174     * @cfg {String} autoCreate @hide
1175     */
1176    /**
1177     * @cfg {String} inputType @hide
1178     */
1179    /**
1180     * @cfg {String} invalidClass @hide
1181     */
1182    /**
1183     * @cfg {String} invalidText @hide
1184     */
1185    /**
1186     * @cfg {String} msgFx @hide
1187     */
1188    /**
1189     * @cfg {String} validateOnBlur @hide
1190     */
1191    /**
1192     * @cfg {Boolean} allowDomMove  @hide
1193     */
1194    /**
1195     * @cfg {String} applyTo @hide
1196     */
1197    /**
1198     * @cfg {String} autoHeight  @hide
1199     */
1200    /**
1201     * @cfg {String} autoWidth  @hide
1202     */
1203    /**
1204     * @cfg {String} cls  @hide
1205     */
1206    /**
1207     * @cfg {String} disabled  @hide
1208     */
1209    /**
1210     * @cfg {String} disabledClass  @hide
1211     */
1212    /**
1213     * @cfg {String} msgTarget  @hide
1214     */
1215    /**
1216     * @cfg {String} readOnly  @hide
1217     */
1218    /**
1219     * @cfg {String} style  @hide
1220     */
1221    /**
1222     * @cfg {String} validationDelay  @hide
1223     */
1224    /**
1225     * @cfg {String} validationEvent  @hide
1226     */
1227    /**
1228     * @cfg {String} tabIndex  @hide
1229     */
1230    /**
1231     * @property disabled
1232     * @hide
1233     */
1234    /**
1235     * @method applyToMarkup
1236     * @hide
1237     */
1238    /**
1239     * @method disable
1240     * @hide
1241     */
1242    /**
1243     * @method enable
1244     * @hide
1245     */
1246    /**
1247     * @method validate
1248     * @hide
1249     */
1250    /**
1251     * @event valid
1252     * @hide
1253     */
1254    /**
1255     * @method setDisabled
1256     * @hide
1257     */
1258    /**
1259     * @cfg keys
1260     * @hide
1261     */
1262});
1263Ext.reg('htmleditor', Ext.form.HtmlEditor);
Note: See TracBrowser for help on using the repository browser.