Changeset 6393

Show
Ignore:
Timestamp:
11/01/06 09:24:01 (19 months ago)
Author:
liucougar
Message:

Change Editor2Commands to be per instance, rather than global
Improved toolbar share support
ContextMenu? share support
All plugins are updated
Fixes #1505: two editor instances do not respect the shareToolbar:false flag
Fixes #1799: move EditorToolbarLight?.html to tests dir

Will blog this in dojo.foo soon

Location:
trunk
Files:
2 added
1 removed
10 modified

Legend:

Unmodified
Added
Removed
  • trunk/src/widget/Editor2.js

    r6370 r6393  
    66 
    77// Object: Manager of current focused Editor2 Instance and available editor2 commands 
    8 dojo.widget.Editor2Manager = { 
     8dojo.widget.Editor2Manager = new dojo.widget.HandlerManager; 
     9dojo.lang.mixin(dojo.widget.Editor2Manager, 
     10{ 
    911        _currentInstance: null, 
    10         _loadedCommands: {}, 
    1112 
    1213        // Object: state a command may be in 
     
    2122                this._currentInstance = inst; 
    2223        }, 
    23         registerCommand: function(/*String*/name, /*Object*/cmd){ 
    24                 // summary: Register an Editor2 command 
    25                 // name: name of the command (case insensitive) 
    26                 // cmd: an object which implements interface dojo.widget.Editor2Command 
    27                 name = name.toLowerCase(); 
    28                 if(this._loadedCommands[name]){ 
    29                         delete this._loadedCommands[name]; 
    30                 } 
    31                 this._loadedCommands[name] = cmd; 
    32         }, 
    33         getCommand: function(/*String*/name){ 
     24        getCommand: function(/*dojo.widget.Editor2*/editor,/*String*/name){ 
    3425                // summary: Return Editor2 command with the given name 
    3526                // name: name of the command (case insensitive) 
     27                var oCommand; 
    3628                name = name.toLowerCase(); 
    37                 var oCommand = this._loadedCommands[name]; 
    38                 if(oCommand){ 
    39                         return oCommand; 
     29                for(var i=0;i<this._registeredHandlers.length;i++){ 
     30                        oCommand = this._registeredHandlers[i](editor, name); 
     31                        if(oCommand){ 
     32                                return oCommand; 
     33                        } 
    4034                } 
    41  
    4235                switch(name){ 
    4336                        case 'htmltoggle': 
    4437                                //Editor2 natively provide the htmltoggle functionalitity 
    4538                                //and it is treated as a builtin command 
    46                                 oCommand = new dojo.widget.Editor2BrowserCommand(name); 
     39                                oCommand = new dojo.widget.Editor2BrowserCommand(editor, name); 
    4740                                break; 
    4841                        case 'formatblock': 
    49                                 oCommand = new dojo.widget.Editor2FormatBlockCommand(name); 
     42                                oCommand = new dojo.widget.Editor2FormatBlockCommand(editor, name); 
    5043                                break; 
    5144                        case 'anchor': 
    52                                 oCommand = new dojo.widget.Editor2Command(name); 
     45                                oCommand = new dojo.widget.Editor2Command(editor, name); 
    5346                                break; 
    5447 
    5548                        //dialog command 
    5649                        case 'createlink': 
    57                                 oCommand = new dojo.widget.Editor2DialogCommand(name, 
     50                                oCommand = new dojo.widget.Editor2DialogCommand(editor, name, 
    5851                                                {contentFile: "dojo.widget.Editor2Plugin.CreateLinkDialog", 
    5952                                                        contentClass: "Editor2CreateLinkDialog", 
     
    6154                                break; 
    6255                        case 'insertimage': 
    63                                 oCommand = new dojo.widget.Editor2DialogCommand(name, 
     56                                oCommand = new dojo.widget.Editor2DialogCommand(editor, name, 
    6457                                                {contentFile: "dojo.widget.Editor2Plugin.InsertImageDialog", 
    6558                                                        contentClass: "Editor2InsertImageDialog", 
     
    7164                                if((curtInst && curtInst.queryCommandAvailable(name)) || 
    7265                                        (!curtInst && dojo.widget.Editor2.prototype.queryCommandAvailable(name))){ 
    73                                         oCommand = new dojo.widget.Editor2BrowserCommand(name); 
     66                                        oCommand = new dojo.widget.Editor2BrowserCommand(editor, name); 
    7467                                }else{ 
    7568                                        dojo.debug("dojo.widget.Editor2Manager.getCommand: Unknown command "+name); 
     
    7770                                } 
    7871                } 
    79                 this._loadedCommands[name] = oCommand; 
    8072                return oCommand; 
    8173        }, 
     
    8375                // summary: Cleaning up. This is called automatically on page unload. 
    8476                this._currentInstance = null; 
    85                 for(var cmd in this._loadedCommands){ 
    86                         this._loadedCommands[cmd].destory(); 
    87                 } 
     77                dojo.widget.HandlerManager.prototype.destroy.call(this); 
    8878        } 
    89 }; 
     79}); 
    9080 
    9181dojo.addOnUnload(dojo.widget.Editor2Manager, "destroy"); 
     
    9484//              dojo.widget.Editor2Command is the base class for all command in Editor2 
    9585dojo.lang.declare("dojo.widget.Editor2Command",null, 
    96         function(name){ 
    97                 // summary: Constructor of this class 
     86        function(editor,name){ 
     87                this._editor = editor; 
     88                this._updateTime = 0; 
    9889                this._name = name; 
    9990        }, 
     
    177168//              in commands 
    178169dojo.lang.declare("dojo.widget.Editor2BrowserCommand", dojo.widget.Editor2Command,  
    179         function(name){ 
     170        function(editor,name){ 
    180171                // summary: Constructor of this class 
    181172                 
     
    187178{ 
    188179                execute: function(para){ 
    189                         var curInst = dojo.widget.Editor2Manager.getCurrentInstance(); 
    190                         if(curInst){ 
    191                                 curInst.execCommand(this._name, para); 
    192                         } 
     180                        this._editor.execCommand(this._name, para); 
    193181                }, 
    194182                getState: function(){ 
    195                         var curInst = dojo.widget.Editor2Manager.getCurrentInstance(); 
    196                         if(curInst){ 
     183                        if(this._editor._lastStateTimestamp > this._updateTime || this._state == undefined){ 
     184                                this._updateTime = this._editor._lastStateTimestamp; 
    197185                                try{ 
    198                                         if(curInst.queryCommandEnabled(this._name)){ 
    199                                                 if(curInst.queryCommandState(this._name)){ 
    200                                                         return dojo.widget.Editor2Manager.commandState.Latched; 
     186                                        if(this._editor.queryCommandEnabled(this._name)){ 
     187                                                if(this._editor.queryCommandState(this._name)){ 
     188                                                        this._state = dojo.widget.Editor2Manager.commandState.Latched; 
    201189                                                }else{ 
    202                                                         return dojo.widget.Editor2Manager.commandState.Enabled; 
     190                                                        this._state = dojo.widget.Editor2Manager.commandState.Enabled; 
    203191                                                } 
    204192                                        }else{ 
    205                                                 return dojo.widget.Editor2Manager.commandState.Disabled; 
     193                                                this._state = dojo.widget.Editor2Manager.commandState.Disabled; 
    206194                                        } 
    207195                                }catch (e) { 
    208196                                        //dojo.debug("exception when getting state for command "+this._name+": "+e); 
    209                                         return dojo.widget.Editor2Manager.commandState.Enabled; 
    210                                 } 
    211                         } 
    212                         return dojo.widget.Editor2Manager.commandState.Disabled; 
     197                                        this._state = dojo.widget.Editor2Manager.commandState.Enabled; 
     198                                } 
     199                        } 
     200                        return this._state; 
    213201                }, 
    214202                getValue: function(){ 
    215                         var curInst = dojo.widget.Editor2Manager.getCurrentInstance(); 
    216                         if(curInst){ 
    217                                 try{ 
    218                                         return curInst.queryCommandValue(this._name); 
    219                                 }catch(e){} 
    220                         } 
     203                        try{ 
     204                                return this._editor.queryCommandValue(this._name); 
     205                        }catch(e){} 
    221206                } 
    222207        } 
     
    350335                        } 
    351336                        dojo.widget.Editor2Dialog.superclass.hide.call(this); 
     337                }, 
     338                //modified from ModalDialogBase.checkSize to call _sizeBackground conditionally 
     339                checkSize: function(){ 
     340                        if(this.isShowing()){ 
     341                                if(this.modal){ 
     342                                        this._sizeBackground(); 
     343                                } 
     344                                this.placeModalDialog(); 
     345                                this.onResized(); 
     346                        } 
    352347                } 
    353348        } 
     
    377372//              the command is executed. 
    378373dojo.lang.declare("dojo.widget.Editor2DialogCommand", dojo.widget.Editor2BrowserCommand, 
    379         function(name, dialogParas){ 
     374        function(editor, name, dialogParas){ 
    380375                this.dialogParas = dialogParas; 
    381376        }, 
     
    396391        } 
    397392}); 
     393 
     394// Object: keeping track of all available share toolbar groups 
     395dojo.widget.Editor2ToolbarGroups = {}; 
    398396 
    399397// summary: 
     
    407405        "dojo.widget.Editor2", 
    408406        dojo.widget.RichText, 
     407        function(){ 
     408                this._loadedCommands={}; 
     409        }, 
    409410        { 
    410411//              // String: url to which save action should send content to 
     
    415416//              closeOnSave: false, 
    416417 
    417                 // Boolean: Whether to share toolbar with other instances of Editor2 
    418                 shareToolbar: false, 
    419418                // Boolean: Whether the toolbar should scroll to keep it in the view 
    420419                toolbarAlwaysVisible: false, 
     
    435434                _htmlEditNode: null, 
    436435 
     436                // String:  
     437                //              This instance of editor will share the same toolbar with other editor with the same toolbarGroup.  
     438                //              By default, toolbarGroup is empty and standalone toolbar is used for this instance. 
     439                toolbarGroup: '', 
     440                // Boolean: Whether to share toolbar with other instances of Editor2. Deprecated in favor of toolbarGroup 
     441                shareToolbar: false, 
     442 
     443                // String: specify which context menu set should be used for this instance. Include ContextMenu plugin to use this 
     444                contextMenuGroupSet: '', 
     445 
    437446                editorOnLoad: function(){ 
    438447                        // summary: 
     
    446455                        } 
    447456 
    448                         var toolbars = dojo.widget.byType("Editor2Toolbar"); 
    449                         if((!toolbars.length)||(!this.shareToolbar)){ 
    450                                 if(this.toolbarWidget){ 
    451                                         this.toolbarWidget.show(); 
    452                                         //re-add the toolbar to the new domNode (caused by open() on another element) 
    453                                         dojo.html.insertBefore(this.toolbarWidget.domNode, this.domNode.firstChild); 
    454                                 }else{ 
    455                                         var tbOpts = {}; 
    456                                         tbOpts.templatePath = this.toolbarTemplatePath; 
    457                                         if(this.toolbarTemplateCssPath){ 
    458                                                 tbOpts.templateCssPath = this.toolbarTemplateCssPath; 
     457                        if(this.toolbarWidget){ 
     458                                this.toolbarWidget.show(); 
     459                                //re-add the toolbar to the new domNode (caused by open() on another element) 
     460                                dojo.html.insertBefore(this.toolbarWidget.domNode, this.domNode.firstChild); 
     461                        }else{ 
     462                                if(this.shareToolbar){ 
     463                                        dojo.deprecated("Editor2:shareToolbar is deprecated in favor of toolbarGroup", "0.5"); 
     464                                        this.toolbarGroup = 'defaultDojoToolbarGroup'; 
     465                                } 
     466                                if(this.toolbarGroup){ 
     467                                        if(dojo.widget.Editor2ToolbarGroups[this.toolbarGroup]){ 
     468                                                this.toolbarWidget = dojo.widget.Editor2ToolbarGroups[this.toolbarGroup]; 
    459469                                        } 
    460                                         this.toolbarWidget = dojo.widget.createWidget("Editor2Toolbar", tbOpts, this.domNode.firstChild, "before"); 
    461  
    462                                         dojo.event.connect(this, "close", this.toolbarWidget, "hide"); 
    463  
    464                                         this.toolbarLoaded(); 
    465                                 } 
    466                         }else{ 
    467                                 // FIXME:       selecting in one shared toolbar doesn't clobber 
    468                                 //                      selection in the others. This is problematic. 
    469                                 this.toolbarWidget = toolbars[0]; 
     470                                } 
     471                                if(!this.toolbarWidget){ 
     472                                                var tbOpts = {shareGroup: this.toolbarGroup, parent: this}; 
     473                                                tbOpts.templatePath = this.toolbarTemplatePath; 
     474                                                if(this.toolbarTemplateCssPath){ 
     475                                                        tbOpts.templateCssPath = this.toolbarTemplateCssPath; 
     476                                                } 
     477                                                this.toolbarWidget = dojo.widget.createWidget("Editor2Toolbar", tbOpts, this.domNode.firstChild, "before"); 
     478                                                if(this.toolbarGroup){ 
     479                                                        dojo.widget.Editor2ToolbarGroups[this.toolbarGroup] = this.toolbarWidget; 
     480                                                } 
     481                                                dojo.event.connect(this, "close", this.toolbarWidget, "hide"); 
     482         
     483                                                this.toolbarLoaded(); 
     484                                } 
    470485                        } 
    471486 
     
    662677                }, 
    663678 
     679                _lastStateTimestamp: 0, 
    664680                onDisplayChanged: function(/*Object*/e){ 
     681                        this._lastStateTimestamp = (new Date()).getTime(); 
    665682                        dojo.widget.Editor2.superclass.onDisplayChanged.call(this,e); 
    666683                        this.updateToolbar(); 
     
    689706                }, 
    690707 
     708                getCommand: function(/*String*/name){ 
     709                        // summary: return a command associated with this instance of editor 
     710                        if(this._loadedCommands[name]){ 
     711                                return this._loadedCommands[name]; 
     712                        } 
     713                        var cmd = dojo.widget.Editor2Manager.getCommand(this, name); 
     714                        this._loadedCommands[name] = cmd; 
     715                        return cmd; 
     716                }, 
    691717                // Array: Commands shortcuts. Each element can has up to 3 fields: 
    692718                //              1. String: the name of the command 
     
    702728                        var self = this; 
    703729                        dojo.lang.forEach(this.shortcuts, function(item){ 
    704                                 var cmd = dojo.widget.Editor2Manager.getCommand(item[0]); 
     730                                var cmd = self.getCommand(item[0]); 
    705731                                if(cmd){ 
    706732                                        self.addKeyHandler(item[1]?item[1]:item[0].charAt(0), item[2]==undefined?self.KEY_CTRL:item[2], exec(cmd)); 
  • trunk/src/widget/Editor2Plugin/ContextMenu.js

    r5993 r6393  
    11dojo.provide("dojo.widget.Editor2Plugin.ContextMenu"); 
    22 
    3 //ContextMenu plugin should be dojo.required-ed before all other plugins which 
    4 //support contextmenu, otherwise the menu for that plugin won't be shown 
     3// summary: dojo.widget.Editor2Plugin.ContextMenu provides context menu for Editor2 widget 
     4// description: 
     5//              This plugin should be dojo.required-ed before all other plugins which 
     6//              support contextmenu, otherwise the menu for that plugin won't be shown 
     7//              For each Editor2, what will appear in its context menu can be set by changing 
     8//              Editor2.contextMenuGroupSet property (by default it is empty, which means use the 
     9//              default contextMenu). A contextMenuGroupSet has to be registered by calling 
     10//              dojo.widget.Editor2Plugin.ContextMenuManager.registerGroupSet() 
     11//              All Editor2 with the same contextMenuGroupSet will share the same ContextMenu 
    512 
    613dojo.require("dojo.widget.Menu2"); 
    714 
    815dojo.event.topic.subscribe("dojo.widget.Editor2::onLoad", function(editor){ 
    9         var p = new dojo.widget.Editor2Plugin.ContextMenu(editor); 
    10 }); 
     16        dojo.widget.Editor2Plugin.ContextMenuManager.getContextMenu(editor); 
     17//      var p = new dojo.widget.Editor2Plugin.ContextMenu(); 
     18}); 
     19 
    1120dojo.widget.Editor2Plugin.ContextMenuManager = { 
    1221        menuGroups: ['Generic', 'Link', 'Anchor', 'Image', 'List', 'Table'], 
     22        _contextMenuGroupSets: {}, 
    1323        _registeredGroups: {}, 
     24        _menus: {}, 
    1425        registerGroup: function(name, handler){ 
    1526                if(this._registeredGroups[name]){ 
     
    3344                        case 'Link': 
    3445                        case 'Image': 
    35                                 return new dojo.widget.Editor2Plugin[name+"ContextMenu"](contextmenuplugin); 
     46                                return new dojo.widget.Editor2Plugin[name+"ContextMenuGroup"](contextmenuplugin); 
    3647                        //TODO 
    3748                        case 'Anchor': 
    3849                        case 'List': 
    3950                } 
     51        }, 
     52        registerGroupSet: function(/*String*/name, /*Array*/set){ 
     53                // summary: register a group set 
     54                // name: name of the group set 
     55                // set: an array of groups, such as ['Generic','Link'] 
     56                this._contextMenuGroupSets[name] = set; 
     57        }, 
     58        removeGroupSet: function(name){ 
     59                var set = this._contextMenuGroupSets[name]; 
     60                delete this._contextMenuGroupSets[name]; 
     61                return set; 
     62        }, 
     63        getContextMenu: function(editor){ 
     64                var set = editor.contextMenuGroupSet || 'defaultDojoEditor2MenuGroupSet'; 
     65                if(this._menus[set]){ 
     66                        this._menus[set].bindEditor(editor); 
     67                        return this._menus[set]; 
     68                } 
     69 
     70                var gs = (editor.contextMenuGroupSet && this._contextMenuGroupSets[editor.contextMenuGroupSet]) || this.menuGroups; 
     71                var menu = new dojo.widget.Editor2Plugin.ContextMenu(editor, gs); 
     72                this._menus[set] = menu; 
     73                return menu; 
    4074        } 
    4175}; 
    4276 
    4377dojo.declare("dojo.widget.Editor2Plugin.ContextMenu", null, 
    44         function(editor){ 
     78        function(editor, gs){ 
    4579                this.groups = []; 
    4680                this.separators = []; 
     
    4983                this.contextMenu = dojo.widget.createWidget("PopupMenu2", {}); 
    5084                dojo.body().appendChild(this.contextMenu.domNode); 
    51                 this.contextMenu.bindDomNode(this.editor.document.body); 
     85                this.bindEditor(this.editor); 
    5286 
    5387                dojo.event.connect(this.contextMenu, "aboutToShow", this, "aboutToShow"); 
    5488                dojo.event.connect(this.editor, "destroy", this, "destroy"); 
    5589 
    56                 this.setup(); 
     90                this.setup(gs); 
    5791        }, 
    5892        { 
    59         setup: function(){ 
    60                 var gs = dojo.widget.Editor2Plugin.ContextMenuManager.menuGroups; 
     93        bindEditor: function(editor){ 
     94                this.contextMenu.bindDomNode(editor.document.body); 
     95        }, 
     96        setup: function(gs){ 
    6197                for(var i in gs){ 
    6298                        var g = dojo.widget.Editor2Plugin.ContextMenuManager.getGroup(gs[i], this); 
     
    100136dojo.widget.defineWidget( 
    101137        "dojo.widget.Editor2ContextMenuItem", 
    102         dojo.widget.MenuItem2, { 
    103         command: null, 
    104         postCreate: function(){ 
    105                 if(!this.command){ 
    106                         this.command = this.caption; 
    107                 } 
    108  
    109                 dojo.widget.Editor2ContextMenuItem.superclass.postCreate.apply(this, arguments); 
    110         }, 
    111         setup: function(){ 
    112                 this.cmd = dojo.widget.Editor2Manager.getCommand(this.command); 
    113                 if(!this.cmd){ 
    114                         alert("command " + this.command + " is not recognized!"); 
    115                 } 
     138        dojo.widget.MenuItem2, 
     139{ 
     140        command: '', 
     141        buildRendering: function(){ 
     142                var curInst = dojo.widget.Editor2Manager.getCurrentInstance(); 
     143                this.caption = curInst.getCommand(this.command).getText(); 
     144 
     145                dojo.widget.Editor2ContextMenuItem.superclass.buildRendering.apply(this, arguments); 
    116146        }, 
    117147        onClick: function(){ 
    118                 if(!this.cmd){ 
    119                         this.setup(); 
    120                 } 
    121                 if(this.cmd){ 
    122                         this.cmd.execute(); 
     148                var curInst = dojo.widget.Editor2Manager.getCurrentInstance(); 
     149                if(curInst){ 
     150                        var _command = curInst.getCommand(this.command); 
     151                        if(_command){ 
     152                                _command.execute(); 
     153                        } 
    123154                } 
    124155        }, 
    125156        refresh: function(){ 
    126                 if(!this.cmd){ 
    127                         this.setup(); 
    128                 } 
    129                 if(this.cmd){ 
    130                         if(this.cmd.getState() == dojo.widget.Editor2Manager.commandState.Disabled){ 
    131                                 this.disable(); 
    132                                 return false; 
    133                         }else{ 
    134                                 this.enable(); 
    135                                 return true; 
     157                var curInst = dojo.widget.Editor2Manager.getCurrentInstance(); 
     158                if(curInst){ 
     159                        var _command = curInst.getCommand(this.command); 
     160                        if(_command){ 
     161                                if(_command.getState() == dojo.widget.Editor2Manager.commandState.Disabled){ 
     162                                        this.disable(); 
     163                                        return false; 
     164                                }else{ 
     165                                        this.enable(); 
     166                                        return true; 
     167                                } 
    136168                        } 
    137169                } 
     
    145177        } 
    146178}); 
    147 dojo.declare("dojo.widget.Editor2Plugin.SimpleContextMenu", null, 
     179dojo.declare("dojo.widget.Editor2Plugin.SimpleContextMenuGroup", null, 
    148180        function(contextmenuplugin){ 
    149181                this.contextMenu = contextmenuplugin.contextMenu; 
     
    184216        } 
    185217}); 
    186 dojo.declare("dojo.widget.Editor2Plugin.GenericContextMenu", 
    187         dojo.widget.Editor2Plugin.SimpleContextMenu, 
     218dojo.declare("dojo.widget.Editor2Plugin.GenericContextMenuGroup", 
     219        dojo.widget.Editor2Plugin.SimpleContextMenuGroup, 
    188220{ 
    189221        createItems: function(){ 
    190                 this.items.push(dojo.widget.createWidget("Editor2ContextMenuItem", {caption: "Cut", iconClass: "dojoE2TBIcon dojoE2TBIcon_Cut"})); 
    191                 this.items.push(dojo.widget.createWidget("Editor2ContextMenuItem", {caption: "Copy", iconClass: "dojoE2TBIcon dojoE2TBIcon_Copy"})); 
    192                 this.items.push(dojo.widget.createWidget("Editor2ContextMenuItem", {caption: "Paste", iconClass: "dojoE2TBIcon dojoE2TBIcon_Paste"})); 
    193         } 
    194 }); 
    195 dojo.declare("dojo.widget.Editor2Plugin.LinkContextMenu", 
    196         dojo.widget.Editor2Plugin.SimpleContextMenu, 
     222                this.items.push(dojo.widget.createWidget("Editor2ContextMenuItem", {command: "cut", iconClass: "dojoE2TBIcon dojoE2TBIcon_Cut"})); 
     223                this.items.push(dojo.widget.createWidget("Editor2ContextMenuItem", {command: "copy", iconClass: "dojoE2TBIcon dojoE2TBIcon_Copy"})); 
     224                this.items.push(dojo.widget.createWidget("Editor2ContextMenuItem", {command: "paste", iconClass: "dojoE2TBIcon dojoE