| /* |
| Copyright (c) 2004-2006, The Dojo Foundation |
| All Rights Reserved. |
| |
| Licensed under the Academic Free License version 2.1 or above OR the |
| modified BSD license. For more information on Dojo licensing, see: |
| |
| http://dojotoolkit.org/community/licensing.shtml |
| */ |
| |
| dojo.provide("dojo.widget.Editor2"); |
| |
| dojo.require("dojo.io.*"); |
| dojo.require("dojo.widget.RichText"); |
| dojo.require("dojo.widget.Editor2Toolbar"); |
| |
| dojo.widget.Editor2Manager = new dojo.widget.HandlerManager; |
| dojo.lang.mixin(dojo.widget.Editor2Manager, |
| { |
| // summary: Manager of current focused Editor2 Instance and available editor2 commands |
| |
| _currentInstance: null, |
| |
| // commandState: Object: state a command may be in |
| commandState: {Disabled: 0, Latched: 1, Enabled: 2}, |
| |
| getCurrentInstance: function(){ |
| // summary: Return the current focused Editor2 instance |
| return this._currentInstance; |
| }, |
| setCurrentInstance: function(/*Widget*/inst){ |
| // summary: Set current focused Editor2 instance |
| this._currentInstance = inst; |
| }, |
| getCommand: function(/*dojo.widget.Editor2*/editor,/*String*/name){ |
| // summary: Return Editor2 command with the given name |
| // name: name of the command (case insensitive) |
| var oCommand; |
| name = name.toLowerCase(); |
| for(var i=0;i<this._registeredHandlers.length;i++){ |
| oCommand = this._registeredHandlers[i](editor, name); |
| if(oCommand){ |
| return oCommand; |
| } |
| } |
| switch(name){ |
| case 'htmltoggle': |
| //Editor2 natively provide the htmltoggle functionalitity |
| //and it is treated as a builtin command |
| oCommand = new dojo.widget.Editor2BrowserCommand(editor, name); |
| break; |
| case 'formatblock': |
| oCommand = new dojo.widget.Editor2FormatBlockCommand(editor, name); |
| break; |
| case 'anchor': |
| oCommand = new dojo.widget.Editor2Command(editor, name); |
| break; |
| |
| //dialog command |
| case 'createlink': |
| oCommand = new dojo.widget.Editor2DialogCommand(editor, name, |
| {contentFile: "dojo.widget.Editor2Plugin.CreateLinkDialog", |
| contentClass: "Editor2CreateLinkDialog", |
| title: "Insert/Edit Link", width: "300px", height: "200px"}); |
| break; |
| case 'insertimage': |
| oCommand = new dojo.widget.Editor2DialogCommand(editor, name, |
| {contentFile: "dojo.widget.Editor2Plugin.InsertImageDialog", |
| contentClass: "Editor2InsertImageDialog", |
| title: "Insert/Edit Image", width: "400px", height: "270px"}); |
| break; |
| // By default we assume that it is a builtin simple command. |
| default: |
| var curtInst = this.getCurrentInstance(); |
| if((curtInst && curtInst.queryCommandAvailable(name)) || |
| (!curtInst && dojo.widget.Editor2.prototype.queryCommandAvailable(name))){ |
| oCommand = new dojo.widget.Editor2BrowserCommand(editor, name); |
| }else{ |
| dojo.debug("dojo.widget.Editor2Manager.getCommand: Unknown command "+name); |
| return; |
| } |
| } |
| return oCommand; |
| }, |
| destroy: function(){ |
| // summary: Cleaning up. This is called automatically on page unload. |
| this._currentInstance = null; |
| dojo.widget.HandlerManager.prototype.destroy.call(this); |
| } |
| }); |
| |
| dojo.addOnUnload(dojo.widget.Editor2Manager, "destroy"); |
| |
| dojo.lang.declare("dojo.widget.Editor2Command",null, |
| function(editor,name){ |
| // summary: |
| // dojo.widget.Editor2Command is the base class for all commands in Editor2 |
| |
| this._editor = editor; |
| this._updateTime = 0; |
| this._name = name; |
| }, |
| { |
| _text: 'Unknown', |
| execute: function(para){ |
| // summary: Execute the command. should be implemented in subclass |
| // description: this function should be re-implemented in subclass |
| dojo.unimplemented("dojo.widget.Editor2Command.execute"); |
| }, |
| getText: function(){ |
| // summary: return the text name of this command |
| return this._text; |
| }, |
| getState: function(){ |
| // summary: |
| // Return the state of the command. The default behavior is |
| // to always return Enabled |
| return dojo.widget.Editor2Manager.commandState.Enabled; |
| }, |
| destroy: function(){ |
| // summary: Destructor |
| } |
| } |
| ); |
| |
| dojo.widget.Editor2BrowserCommandNames={ |
| 'bold': 'Bold', |
| 'copy': 'Copy', |
| 'cut': 'Cut', |
| 'Delete': 'Delete', |
| 'indent': 'Indent', |
| 'inserthorizontalrule': 'Horizental Rule', |
| 'insertorderedlist': 'Numbered List', |
| 'insertunorderedlist': 'Bullet List', |
| 'italic': 'Italic', |
| 'justifycenter': 'Align Center', |
| 'justifyfull': 'Justify', |
| 'justifyleft': 'Align Left', |
| 'justifyright': 'Align Right', |
| 'outdent': 'Outdent', |
| 'paste': 'Paste', |
| 'redo': 'Redo', |
| 'removeformat': 'Remove Format', |
| 'selectall': 'Select All', |
| 'strikethrough': 'Strikethrough', |
| 'subscript': 'Subscript', |
| 'superscript': 'Superscript', |
| 'underline': 'Underline', |
| 'undo': 'Undo', |
| 'unlink': 'Remove Link', |
| 'createlink': 'Create Link', |
| 'insertimage': 'Insert Image', |
| 'htmltoggle': 'HTML Source', |
| 'forecolor': 'Foreground Color', |
| 'hilitecolor': 'Background Color', |
| 'plainformatblock': 'Paragraph Style', |
| 'formatblock': 'Paragraph Style', |
| 'fontsize': 'Font Size', |
| 'fontname': 'Font Name'//, |
| // 'inserttable': 'Insert Table', |
| // 'insertcell': |
| // 'insertcol': |
| // 'insertrow': |
| // 'deletecells': |
| // 'deletecols': |
| // 'deleterows': |
| // 'mergecells': |
| // 'splitcell': |
| // 'inserthtml': |
| // 'blockdirltr': |
| // 'blockdirrtl': |
| // 'dirltr': |
| // 'dirrtl': |
| // 'inlinedirltr': |
| // 'inlinedirrtl': |
| } |
| |
| dojo.lang.declare("dojo.widget.Editor2BrowserCommand", dojo.widget.Editor2Command, |
| function(editor,name){ |
| // summary: |
| // dojo.widget.Editor2BrowserCommand is the base class for all the browser built |
| // in commands |
| |
| var text = dojo.widget.Editor2BrowserCommandNames[name.toLowerCase()]; |
| if(text){ |
| this._text = text; |
| } |
| }, |
| { |
| execute: function(para){ |
| this._editor.execCommand(this._name, para); |
| }, |
| getState: function(){ |
| if(this._editor._lastStateTimestamp > this._updateTime || this._state == undefined){ |
| this._updateTime = this._editor._lastStateTimestamp; |
| try{ |
| if(this._editor.queryCommandEnabled(this._name)){ |
| if(this._editor.queryCommandState(this._name)){ |
| this._state = dojo.widget.Editor2Manager.commandState.Latched; |
| }else{ |
| this._state = dojo.widget.Editor2Manager.commandState.Enabled; |
| } |
| }else{ |
| this._state = dojo.widget.Editor2Manager.commandState.Disabled; |
| } |
| }catch (e) { |
| //dojo.debug("exception when getting state for command "+this._name+": "+e); |
| this._state = dojo.widget.Editor2Manager.commandState.Enabled; |
| } |
| } |
| return this._state; |
| }, |
| getValue: function(){ |
| try{ |
| return this._editor.queryCommandValue(this._name); |
| }catch(e){} |
| } |
| } |
| ); |
| |
| dojo.lang.declare("dojo.widget.Editor2FormatBlockCommand", dojo.widget.Editor2BrowserCommand, { |
| /* In none-ActiveX mode under IE, <p> and no <p> text can not be distinguished |
| getCurrentValue: function(){ |
| var curInst = dojo.widget.Editor2Manager.getCurrentInstance(); |
| if(!curInst){ return ''; } |
| |
| var h = dojo.render.html; |
| |
| // safari f's us for selection primitives |
| if(h.safari){ return ''; } |
| |
| var selectedNode = (h.ie) ? curInst.document.selection.createRange().parentElement() : curInst.window.getSelection().anchorNode; |
| // make sure we actuall have an element |
| while((selectedNode)&&(selectedNode.nodeType != 1)){ |
| selectedNode = selectedNode.parentNode; |
| } |
| if(!selectedNode){ return ''; } |
| |
| var formats = ["p", "pre", "h1", "h2", "h3", "h4", "h5", "h6", "address"]; |
| // gotta run some specialized updates for the various |
| // formatting options |
| var type = formats[dojo.lang.find(formats, selectedNode.nodeName.toLowerCase())]; |
| while((selectedNode!=curInst.editNode)&&(!type)){ |
| selectedNode = selectedNode.parentNode; |
| if(!selectedNode){ break; } |
| type = formats[dojo.lang.find(formats, selectedNode.nodeName.toLowerCase())]; |
| } |
| if(!type){ |
| type = ""; |
| } |
| return type; |
| }*/ |
| } |
| ); |
| |
| dojo.require("dojo.widget.FloatingPane"); |
| dojo.widget.defineWidget( |
| "dojo.widget.Editor2Dialog", |
| [dojo.widget.HtmlWidget, dojo.widget.FloatingPaneBase, dojo.widget.ModalDialogBase], |
| { |
| // summary: |
| // Provides a Dialog which can be modal or normal for the Editor2. |
| |
| templatePath: dojo.uri.dojoUri("src/widget/templates/Editor2/EditorDialog.html"), |
| |
| // modal: Boolean: Whether this is a modal dialog. True by default. |
| modal: true, |
| |
| // refreshOnShow: true, //for debug for now |
| |
| // width: String: Width of the dialog. None by default. |
| width: "", |
| |
| // height: String: Height of the dialog. None by default. |
| height: "", |
| |
| // windowState: String: startup state of the dialog |
| windowState: "minimized", |
| |
| displayCloseAction: true, |
| |
| // contentFile: String |
| // TODO |
| contentFile: "", |
| |
| // contentClass: String |
| // TODO |
| contentClass: "", |
| |
| fillInTemplate: function(args, frag){ |
| this.fillInFloatingPaneTemplate(args, frag); |
| dojo.widget.Editor2Dialog.superclass.fillInTemplate.call(this, args, frag); |
| }, |
| postCreate: function(){ |
| if(this.contentFile){ |
| dojo.require(this.contentFile); |
| } |
| if(this.modal){ |
| dojo.widget.ModalDialogBase.prototype.postCreate.call(this); |
| }else{ |
| with(this.domNode.style) { |
| zIndex = 999; |
| display = "none"; |
| } |
| } |
| dojo.widget.FloatingPaneBase.prototype.postCreate.apply(this, arguments); |
| dojo.widget.Editor2Dialog.superclass.postCreate.call(this); |
| if(this.width && this.height){ |
| with(this.domNode.style){ |
| width = this.width; |
| height = this.height; |
| } |
| } |
| }, |
| createContent: function(){ |
| if(!this.contentWidget && this.contentClass){ |
| this.contentWidget = dojo.widget.createWidget(this.contentClass); |
| this.addChild(this.contentWidget); |
| } |
| }, |
| show: function(){ |
| if(!this.contentWidget){ |
| //buggy IE: if the dialog is hidden, the button widgets |
| //in the dialog can not be shown, so show it temporary (as the |
| //dialog may decide not to show it in loadContent() later) |
| dojo.widget.Editor2Dialog.superclass.show.apply(this, arguments); |
| this.createContent(); |
| dojo.widget.Editor2Dialog.superclass.hide.call(this); |
| } |
| |
| if(!this.contentWidget || !this.contentWidget.loadContent()){ |
| return; |
| } |
| this.showFloatingPane(); |
| dojo.widget.Editor2Dialog.superclass.show.apply(this, arguments); |
| if(this.modal){ |
| this.showModalDialog(); |
| } |
| if(this.modal){ |
| //place the background div under this modal pane |
| this.bg.style.zIndex = this.domNode.style.zIndex-1; |
| } |
| }, |
| onShow: function(){ |
| dojo.widget.Editor2Dialog.superclass.onShow.call(this); |
| this.onFloatingPaneShow(); |
| }, |
| closeWindow: function(){ |
| this.hide(); |
| dojo.widget.Editor2Dialog.superclass.closeWindow.apply(this, arguments); |
| }, |
| hide: function(){ |
| if(this.modal){ |
| this.hideModalDialog(); |
| } |
| dojo.widget.Editor2Dialog.superclass.hide.call(this); |
| }, |
| //modified from ModalDialogBase.checkSize to call _sizeBackground conditionally |
| checkSize: function(){ |
| if(this.isShowing()){ |
| if(this.modal){ |
| this._sizeBackground(); |
| } |
| this.placeModalDialog(); |
| this.onResized(); |
| } |
| } |
| } |
| ); |
| |
| dojo.widget.defineWidget( |
| "dojo.widget.Editor2DialogContent", |
| dojo.widget.HtmlWidget, |
| { |
| // summary: |
| // dojo.widget.Editor2DialogContent is the actual content of a Editor2Dialog. |
| // This class should be subclassed to provide the content. |
| |
| widgetsInTemplate: true, |
| |
| loadContent:function(){ |
| // summary: Load the content. Called by Editor2Dialog when first shown |
| return true; |
| }, |
| cancel: function(){ |
| // summary: Default handler when cancel button is clicked. |
| this.parent.hide(); |
| } |
| }); |
| |
| dojo.lang.declare("dojo.widget.Editor2DialogCommand", dojo.widget.Editor2BrowserCommand, |
| function(editor, name, dialogParas){ |
| // summary: |
| // Provides an easy way to popup a dialog when |
| // the command is executed. |
| this.dialogParas = dialogParas; |
| }, |
| { |
| execute: function(){ |
| if(!this.dialog){ |
| if(!this.dialogParas.contentFile || !this.dialogParas.contentClass){ |
| alert("contentFile and contentClass should be set for dojo.widget.Editor2DialogCommand.dialogParas!"); |
| return; |
| } |
| this.dialog = dojo.widget.createWidget("Editor2Dialog", this.dialogParas); |
| |
| dojo.body().appendChild(this.dialog.domNode); |
| |
| dojo.event.connect(this, "destroy", this.dialog, "destroy"); |
| } |
| this.dialog.show(); |
| }, |
| getText: function(){ |
| return this.dialogParas.title || dojo.widget.Editor2DialogCommand.superclass.getText.call(this); |
| } |
| }); |
| |
| dojo.widget.Editor2ToolbarGroups = { |
| // summary: keeping track of all available share toolbar groups |
| }; |
| |
| dojo.widget.defineWidget( |
| "dojo.widget.Editor2", |
| dojo.widget.RichText, |
| function(){ |
| this._loadedCommands={}; |
| }, |
| { |
| // summary: |
| // dojo.widget.Editor2 is the WYSIWYG editor in dojo with toolbar. It supports a plugin |
| // framework which can be used to extend the functionalities of the editor, such as |
| // adding a context menu, table operation etc. |
| // description: |
| // Plugins are available using dojo's require syntax. Please find available built-in plugins |
| // under src/widget/Editor2Plugin. |
| |
| // // saveUrl: String: url to which save action should send content to |
| // saveUrl: "", |
| // // saveMethod: String: HTTP method for save (post or get) |
| // saveMethod: "post", |
| // saveArgName: "editorContent", |
| // closeOnSave: false, |
| |
| // toolbarAlwaysVisible: Boolean: Whether the toolbar should scroll to keep it in the view |
| toolbarAlwaysVisible: false, |
| |
| // htmlEditing: false, |
| |
| toolbarWidget: null, |
| scrollInterval: null, |
| |
| // toolbarTemplatePath: dojo.uri.Uri |
| // to specify the template file for the toolbar |
| toolbarTemplatePath: dojo.uri.dojoUri("src/widget/templates/EditorToolbarOneline.html"), |
| |
| // toolbarTemplateCssPath: dojo.uri.Uri |
| // to specify the css file for the toolbar |
| toolbarTemplateCssPath: null, |
| |
| // toolbarPlaceHolder: String |
| // element id to specify where to attach the toolbar |
| toolbarPlaceHolder: '', |
| |
| // toolbarTemplatePath: dojo.uri.dojoUri("src/widget/templates/Editor2/EditorToolbarFCKStyle.html"), |
| // toolbarTemplateCssPath: dojo.uri.dojoUri("src/widget/templates/Editor2/FCKDefault/EditorToolbarFCKStyle.css"), |
| |
| _inSourceMode: false, |
| _htmlEditNode: null, |
| |
| // toolbarGroup: String: |
| // This instance of editor will share the same toolbar with other editor with the same toolbarGroup. |
| // By default, toolbarGroup is empty and standalone toolbar is used for this instance. |
| toolbarGroup: '', |
| |
| // shareToolbar: Boolean: Whether to share toolbar with other instances of Editor2. Deprecated in favor of toolbarGroup |
| shareToolbar: false, |
| |
| // contextMenuGroupSet: String: specify which context menu set should be used for this instance. Include ContextMenu plugin to use this |
| contextMenuGroupSet: '', |
| |
| editorOnLoad: function(){ |
| // summary: |
| // Create toolbar and other initialization routines. This is called after |
| // the finish of the loading of document in the editing element |
| // dojo.profile.start("dojo.widget.Editor2::editorOnLoad"); |
| |
| dojo.event.topic.publish("dojo.widget.Editor2::preLoadingToolbar", this); |
| if(this.toolbarAlwaysVisible){ |
| dojo.require("dojo.widget.Editor2Plugin.AlwaysShowToolbar"); |
| } |
| |
| if(this.toolbarWidget){ |
| this.toolbarWidget.show(); |
| //re-add the toolbar to the new domNode (caused by open() on another element) |
| dojo.html.insertBefore(this.toolbarWidget.domNode, this.domNode.firstChild); |
| }else{ |
| if(this.shareToolbar){ |
| dojo.deprecated("Editor2:shareToolbar is deprecated in favor of toolbarGroup", "0.5"); |
| this.toolbarGroup = 'defaultDojoToolbarGroup'; |
| } |
| if(this.toolbarGroup){ |
| if(dojo.widget.Editor2ToolbarGroups[this.toolbarGroup]){ |
| this.toolbarWidget = dojo.widget.Editor2ToolbarGroups[this.toolbarGroup]; |
| } |
| } |
| if(!this.toolbarWidget){ |
| var tbOpts = {shareGroup: this.toolbarGroup, parent: this}; |
| tbOpts.templatePath = this.toolbarTemplatePath; |
| if(this.toolbarTemplateCssPath){ |
| tbOpts.templateCssPath = this.toolbarTemplateCssPath; |
| } |
| if(this.toolbarPlaceHolder){ |
| this.toolbarWidget = dojo.widget.createWidget("Editor2Toolbar", tbOpts, dojo.byId(this.toolbarPlaceHolder), "after"); |
| }else{ |
| this.toolbarWidget = dojo.widget.createWidget("Editor2Toolbar", tbOpts, this.domNode.firstChild, "before"); |
| } |
| if(this.toolbarGroup){ |
| dojo.widget.Editor2ToolbarGroups[this.toolbarGroup] = this.toolbarWidget; |
| } |
| dojo.event.connect(this, "close", this.toolbarWidget, "hide"); |
| |
| this.toolbarLoaded(); |
| } |
| } |
| |
| dojo.event.topic.registerPublisher("Editor2.clobberFocus", this, "clobberFocus"); |
| dojo.event.topic.subscribe("Editor2.clobberFocus", this, "setBlur"); |
| |
| dojo.event.topic.publish("dojo.widget.Editor2::onLoad", this); |
| // dojo.profile.end("dojo.widget.Editor2::editorOnLoad"); |
| }, |
| |
| //event for plugins to use |
| toolbarLoaded: function(){ |
| // summary: |
| // Fired when the toolbar for this editor is created. |
| // This event is for plugins to use |
| }, |
| |
| //TODO: provide a query mechanism about loaded plugins? |
| registerLoadedPlugin: function(/*Object*/obj){ |
| // summary: Register a plugin which is loaded for this instance |
| if(!this.loadedPlugins){ |
| this.loadedPlugins = []; |
| } |
| this.loadedPlugins.push(obj); |
| }, |
| unregisterLoadedPlugin: function(/*Object*/obj){ |
| // summary: Delete a loaded plugin for this instance |
| for(var i in this.loadedPlugins){ |
| if(this.loadedPlugins[i] === obj){ |
| delete this.loadedPlugins[i]; |
| return; |
| } |
| } |
| dojo.debug("dojo.widget.Editor2.unregisterLoadedPlugin: unknow plugin object: "+obj); |
| }, |
| |
| //overload the original ones to provide extra commands |
| execCommand: function(/*String*/command, argument){ |
| switch(command.toLowerCase()){ |
| case 'htmltoggle': |
| this.toggleHtmlEditing(); |
| break; |
| default: |
| dojo.widget.Editor2.superclass.execCommand.apply(this, arguments); |
| } |
| }, |
| queryCommandEnabled: function(/*String*/command, argument){ |
| switch(command.toLowerCase()){ |
| case 'htmltoggle': |
| return true; |
| default: |
| if(this._inSourceMode){ return false;} |
| return dojo.widget.Editor2.superclass.queryCommandEnabled.apply(this, arguments); |
| } |
| }, |
| queryCommandState: function(/*String*/command, argument){ |
| switch(command.toLowerCase()){ |
| case 'htmltoggle': |
| return this._inSourceMode; |
| default: |
| return dojo.widget.Editor2.superclass.queryCommandState.apply(this, arguments); |
| } |
| }, |
| |
| onClick: function(/*Event*/e){ |
| dojo.widget.Editor2.superclass.onClick.call(this, e); |
| //if Popup is used, call dojo.widget.PopupManager.onClick |
| //manually when click in the editing area to close all |
| //open popups (dropdowns) |
| if(dojo.widget.PopupManager){ |
| if(!e){ //IE |
| e = this.window.event; |
| } |
| dojo.widget.PopupManager.onClick(e); |
| } |
| }, |
| |
| clobberFocus: function(){ |
| // summary: stub to signal other instances to clobber focus |
| }, |
| toggleHtmlEditing: function(){ |
| // summary: toggle between WYSIWYG mode and HTML source mode |
| if(this===dojo.widget.Editor2Manager.getCurrentInstance()){ |
| if(!this._inSourceMode){ |
| var html = this.getEditorContent(); |
| this._inSourceMode = true; |
| |
| if(!this._htmlEditNode){ |
| this._htmlEditNode = dojo.doc().createElement("textarea"); |
| dojo.html.insertAfter(this._htmlEditNode, this.editorObject); |
| } |
| |
| this._htmlEditNode.style.display = ""; |
| this._htmlEditNode.style.width = "100%"; |
| this._htmlEditNode.style.height = dojo.html.getBorderBox(this.editNode).height+"px"; |
| this._htmlEditNode.value = html; |
| |
| //activeX object (IE) doesn't like to be hidden, so move it outside of screen instead |
| with(this.editorObject.style){ |
| position = "absolute"; |
| left = "-2000px"; |
| top = "-2000px"; |
| } |
| }else{ |
| this._inSourceMode = false; |
| |
| //In IE activeX mode, if _htmlEditNode is focused, |
| //when toggling, an error would occur, so unfocus it |
| this._htmlEditNode.blur(); |
| |
| with(this.editorObject.style){ |
| position = ""; |
| left = ""; |
| top = ""; |
| } |
| var html = this._htmlEditNode.value; |
| |
| dojo.lang.setTimeout(this, "replaceEditorContent", 1, html); |
| this._htmlEditNode.style.display = "none"; |
| this.focus(); |
| } |
| this.onDisplayChanged(null, true); |
| } |
| }, |
| |
| setFocus: function(){ |
| // summary: focus is set on this instance |
| // dojo.debug("setFocus: start "+this.widgetId); |
| if(dojo.widget.Editor2Manager.getCurrentInstance() === this){ return; } |
| |
| this.clobberFocus(); |
| // dojo.debug("setFocus:", this); |
| dojo.widget.Editor2Manager.setCurrentInstance(this); |
| }, |
| |
| setBlur: function(){ |
| // summary: focus on this instance is lost |
| // dojo.debug("setBlur:", this); |
| //dojo.event.disconnect(this.toolbarWidget, "exec", this, "execCommand"); |
| }, |
| |
| saveSelection: function(){ |
| // summary: save the current selection for restoring it |
| this._bookmark = null; |
| this._bookmark = dojo.withGlobal(this.window, dojo.html.selection.getBookmark); |
| }, |
| restoreSelection: function(){ |
| // summary: restore the last saved selection |
| if(this._bookmark){ |
| this.focus(); //require for none-activeX IE |
| dojo.withGlobal(this.window, "moveToBookmark", dojo.html.selection, [this._bookmark]); |
| this._bookmark = null; |
| }else{ |
| dojo.debug("restoreSelection: no saved selection is found!"); |
| } |
| }, |
| |
| _updateToolbarLastRan: null, |
| _updateToolbarTimer: null, |
| _updateToolbarFrequency: 500, |
| |
| updateToolbar: function(/*Boolean*/force){ |
| // summary: update the associated toolbar of this Editor2 |
| if((!this.isLoaded)||(!this.toolbarWidget)){ return; } |
| |
| // keeps the toolbar from updating too frequently |
| // TODO: generalize this functionality? |
| var diff = new Date() - this._updateToolbarLastRan; |
| if( (!force)&&(this._updateToolbarLastRan)&& |
| ((diff < this._updateToolbarFrequency)) ){ |
| |
| clearTimeout(this._updateToolbarTimer); |
| var _this = this; |
| this._updateToolbarTimer = setTimeout(function() { |
| _this.updateToolbar(); |
| }, this._updateToolbarFrequency/2); |
| return; |
| |
| }else{ |
| this._updateToolbarLastRan = new Date(); |
| } |
| // end frequency checker |
| |
| //IE has the habit of generating events even when this editor is blurred, prevent this |
| if(dojo.widget.Editor2Manager.getCurrentInstance() !== this){ return; } |
| |
| this.toolbarWidget.update(); |
| }, |
| |
| destroy: function(/*Boolean*/finalize){ |
| this._htmlEditNode = null; |
| dojo.event.disconnect(this, "close", this.toolbarWidget, "hide"); |
| if(!finalize){ |
| this.toolbarWidget.destroy(); |
| } |
| dojo.widget.Editor2.superclass.destroy.call(this); |
| }, |
| |
| _lastStateTimestamp: 0, |
| onDisplayChanged: function(/*Object*/e, /*Boolean*/forceUpdate){ |
| this._lastStateTimestamp = (new Date()).getTime(); |
| dojo.widget.Editor2.superclass.onDisplayChanged.call(this,e); |
| this.updateToolbar(forceUpdate); |
| }, |
| |
| onLoad: function(){ |
| try{ |
| dojo.widget.Editor2.superclass.onLoad.call(this); |
| }catch(e){ // FIXME: debug why this is throwing errors in IE! |
| dojo.debug(e); |
| } |
| this.editorOnLoad(); |
| }, |
| |
| onFocus: function(){ |
| dojo.widget.Editor2.superclass.onFocus.call(this); |
| this.setFocus(); |
| }, |
| |
| //overload to support source editing mode |
| getEditorContent: function(){ |
| if(this._inSourceMode){ |
| return this._htmlEditNode.value; |
| } |
| return dojo.widget.Editor2.superclass.getEditorContent.call(this); |
| }, |
| |
| replaceEditorContent: function(html){ |
| if(this._inSourceMode){ |
| this._htmlEditNode.value = html; |
| return; |
| } |
| dojo.widget.Editor2.superclass.replaceEditorContent.apply(this,arguments); |
| }, |
| getCommand: function(/*String*/name){ |
| // summary: return a command associated with this instance of editor |
| if(this._loadedCommands[name]){ |
| return this._loadedCommands[name]; |
| } |
| var cmd = dojo.widget.Editor2Manager.getCommand(this, name); |
| this._loadedCommands[name] = cmd; |
| return cmd; |
| }, |
| // Array: Commands shortcuts. Each element can has up to 3 fields: |
| // 1. String: the name of the command |
| // 2. String Optional: the char for shortcut key, by default the first char from the command name is used |
| // 3. Int Optional: specify the modifier of the shortcut, by default ctrl is used |
| shortcuts: [['bold'],['italic'],['underline'],['selectall','a'],['insertunorderedlist','\\']], |
| setupDefaultShortcuts: function(){ |
| // summary: setup default shortcuts using Editor2 commands |
| var exec = function(cmd){ return function(){ cmd.execute(); } }; |
| // if(!dojo.render.html.ie){ |
| // this.shortcuts.push(['redo','Z']); |
| // } |
| var self = this; |
| dojo.lang.forEach(this.shortcuts, function(item){ |
| var cmd = self.getCommand(item[0]); |
| if(cmd){ |
| self.addKeyHandler(item[1]?item[1]:item[0].charAt(0), item[2]==undefined?self.KEY_CTRL:item[2], exec(cmd)); |
| } |
| }); |
| // this.addKeyHandler("s", ctrl, function () { this.save(true); }); |
| } |
| /*, |
| // FIXME: probably not needed any more with new design, but need to verify |
| _save: function(e){ |
| // FIXME: how should this behave when there's a larger form in play? |
| if(!this.isClosed){ |
| dojo.debug("save attempt"); |
| if(this.saveUrl.length){ |
| var content = {}; |
| content[this.saveArgName] = this.getEditorContent(); |
| dojo.io.bind({ |
| method: this.saveMethod, |
| url: this.saveUrl, |
| content: content |
| }); |
| }else{ |
| dojo.debug("please set a saveUrl for the editor"); |
| } |
| if(this.closeOnSave){ |
| this.close(e.getName().toLowerCase() == "save"); |
| } |
| } |
| }*/ |
| } |
| ); |