]> git.pond.sub.org Git - eow/blobdiff - static/dojo-release-1.1.1/dijit/_editor/RichText.js
add Dojo 1.1.1
[eow] / static / dojo-release-1.1.1 / dijit / _editor / RichText.js
diff --git a/static/dojo-release-1.1.1/dijit/_editor/RichText.js b/static/dojo-release-1.1.1/dijit/_editor/RichText.js
new file mode 100644 (file)
index 0000000..9ece365
--- /dev/null
@@ -0,0 +1,1449 @@
+if(!dojo._hasResource["dijit._editor.RichText"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit._editor.RichText"] = true;
+dojo.provide("dijit._editor.RichText");
+
+dojo.require("dijit._Widget");
+dojo.require("dijit._editor.selection");
+dojo.require("dijit._editor.html");
+dojo.require("dojo.i18n");
+dojo.requireLocalization("dijit.form", "Textarea", null, "zh,pt,da,tr,ru,de,ROOT,sv,ja,he,fi,nb,el,ar,pt-pt,cs,fr,es,ko,nl,zh-tw,pl,it,hu");
+
+// used to restore content when user leaves this page then comes back
+// but do not try doing dojo.doc.write if we are using xd loading.
+// dojo.doc.write will only work if RichText.js is included in the dojo.js
+// file. If it is included in dojo.js and you want to allow rich text saving
+// for back/forward actions, then set dojo.config.allowXdRichTextSave = true.
+if(!dojo.config["useXDomain"] || dojo.config["allowXdRichTextSave"]){
+       if(dojo._postLoad){
+               (function(){
+                       var savetextarea = dojo.doc.createElement('textarea');
+                       savetextarea.id = dijit._scopeName + "._editor.RichText.savedContent";
+                       var s = savetextarea.style;
+                       s.display='none';
+                       s.position='absolute';
+                       s.top="-100px";
+                       s.left="-100px";
+                       s.height="3px";
+                       s.width="3px";
+                       dojo.body().appendChild(savetextarea);
+               })();
+       }else{
+               //dojo.body() is not available before onLoad is fired
+               try{
+                       dojo.doc.write('<textarea id="' + dijit._scopeName + '._editor.RichText.savedContent" ' +
+                               'style="display:none;position:absolute;top:-100px;left:-100px;height:3px;width:3px;overflow:hidden;"></textarea>');
+               }catch(e){ }
+       }
+}
+dojo.declare("dijit._editor.RichText", dijit._Widget, {
+       constructor: function(){
+               // summary:
+               //              dijit._editor.RichText is the core of the WYSIWYG editor in dojo, which
+               //              provides the basic editing features. It also encapsulates the differences
+               //              of different js engines for various browsers
+               //
+               // contentPreFilters: Array
+               //              pre content filter function register array.
+               //              these filters will be executed before the actual
+               //              editing area get the html content
+               this.contentPreFilters = [];
+
+               // contentPostFilters: Array
+               //              post content filter function register array.
+               //              these will be used on the resulting html
+               //              from contentDomPostFilters. The resuling
+               //              content is the final html (returned by getValue())
+               this.contentPostFilters = [];
+
+               // contentDomPreFilters: Array
+               //              pre content dom filter function register array.
+               //              these filters are applied after the result from
+               //              contentPreFilters are set to the editing area
+               this.contentDomPreFilters = [];
+
+               // contentDomPostFilters: Array
+               //              post content dom filter function register array.
+               //              these filters are executed on the editing area dom
+               //              the result from these will be passed to contentPostFilters
+               this.contentDomPostFilters = [];
+
+               // editingAreaStyleSheets: Array
+               //              array to store all the stylesheets applied to the editing area
+               this.editingAreaStyleSheets=[];
+
+               this._keyHandlers = {};
+               this.contentPreFilters.push(dojo.hitch(this, "_preFixUrlAttributes"));
+               if(dojo.isMoz){
+                       this.contentPreFilters.push(this._fixContentForMoz);
+                       this.contentPostFilters.push(this._removeMozBogus);
+               }else if(dojo.isSafari){
+                       this.contentPostFilters.push(this._removeSafariBogus);
+               }
+               //this.contentDomPostFilters.push(this._postDomFixUrlAttributes);
+
+               this.onLoadDeferred = new dojo.Deferred();
+       },
+
+       // inheritWidth: Boolean
+       //              whether to inherit the parent's width or simply use 100%
+       inheritWidth: false,
+
+       // focusOnLoad: Boolean
+       //              whether focusing into this instance of richtext when page onload
+       focusOnLoad: false,
+
+       // name: String
+       //              If a save name is specified the content is saved and restored when the user
+       //              leave this page can come back, or if the editor is not properly closed after
+       //              editing has started.
+       name: "",
+
+       // styleSheets: String
+       //              semicolon (";") separated list of css files for the editing area
+       styleSheets: "",
+
+       // _content: String
+       //              temporary content storage
+       _content: "",
+
+       // height: String
+       //              set height to fix the editor at a specific height, with scrolling.
+       //              By default, this is 300px. If you want to have the editor always
+       //              resizes to accommodate the content, use AlwaysShowToolbar plugin
+       //              and set height=""
+       height: "300px",
+
+       // minHeight: String
+       //              The minimum height that the editor should have
+       minHeight: "1em",
+       
+       // isClosed: Boolean
+       isClosed: true,
+
+       // isLoaded: Boolean
+       isLoaded: false,
+
+       // _SEPARATOR: String
+       //              used to concat contents from multiple textareas into a single string
+       _SEPARATOR: "@@**%%__RICHTEXTBOUNDRY__%%**@@",
+
+       // onLoadDeferred: dojo.Deferred
+       //              deferred which is fired when the editor finishes loading
+       onLoadDeferred: null,
+
+       postCreate: function(){
+               // summary: init
+               dojo.publish(dijit._scopeName + "._editor.RichText::init", [this]);
+               this.open();
+               this.setupDefaultShortcuts();
+       },
+
+       setupDefaultShortcuts: function(){
+               // summary: add some default key handlers
+               // description:
+               //              Overwrite this to setup your own handlers. The default
+               //              implementation does not use Editor commands, but directly
+               //              executes the builtin commands within the underlying browser
+               //              support.
+               var exec = function(cmd, arg){
+                       return arguments.length == 1 ? function(){ this.execCommand(cmd); } :
+                               function(){ this.execCommand(cmd, arg); };
+               };
+
+               var ctrlKeyHandlers = { b: exec("bold"),
+                       i: exec("italic"),
+                       u: exec("underline"),
+                       a: exec("selectall"),
+                       s: function(){ this.save(true); },
+
+                       "1": exec("formatblock", "h1"),
+                       "2": exec("formatblock", "h2"),
+                       "3": exec("formatblock", "h3"),
+                       "4": exec("formatblock", "h4"),
+
+                       "\\": exec("insertunorderedlist") };
+
+               if(!dojo.isIE){
+                       ctrlKeyHandlers.Z = exec("redo"); //FIXME: undo?
+               }
+
+               for(var key in ctrlKeyHandlers){
+                       this.addKeyHandler(key, this.KEY_CTRL, ctrlKeyHandlers[key]);
+               }
+       },
+
+       // events: Array
+       //               events which should be connected to the underlying editing area
+       events: ["onKeyPress", "onKeyDown", "onKeyUp", "onClick"],
+
+       // events: Array
+       //               events which should be connected to the underlying editing
+       //               area, events in this array will be addListener with
+       //               capture=true
+       captureEvents: [],
+
+       _editorCommandsLocalized: false,
+       _localizeEditorCommands: function(){
+               if(this._editorCommandsLocalized){
+                       return;
+               }
+               this._editorCommandsLocalized = true;
+
+               //in IE, names for blockformat is locale dependent, so we cache the values here
+
+               //if the normal way fails, we try the hard way to get the list
+
+               //do not use _cacheLocalBlockFormatNames here, as it will
+               //trigger security warning in IE7
+
+               //in the array below, ul can not come directly after ol,
+               //otherwise the queryCommandValue returns Normal for it
+               var formats = ['p', 'pre', 'address', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'ol', 'div', 'ul'];
+               var localhtml = "", format, i=0;
+               while((format=formats[i++])){
+                       if(format.charAt(1) != 'l'){
+                               localhtml += "<"+format+"><span>content</span></"+format+">";
+                       }else{
+                               localhtml += "<"+format+"><li>content</li></"+format+">";
+                       }
+               }
+               //queryCommandValue returns empty if we hide editNode, so move it out of screen temporary
+               var div=dojo.doc.createElement('div');
+               div.style.position = "absolute";
+               div.style.left = "-2000px";
+               div.style.top = "-2000px";
+               dojo.doc.body.appendChild(div);
+               div.innerHTML = localhtml;
+               var node = div.firstChild;
+               while(node){
+                       dijit._editor.selection.selectElement(node.firstChild);
+                       dojo.withGlobal(this.window, "selectElement", dijit._editor.selection, [node.firstChild]);
+                       var nativename = node.tagName.toLowerCase();
+                       this._local2NativeFormatNames[nativename] = dojo.doc.queryCommandValue("formatblock");//this.queryCommandValue("formatblock");
+                       this._native2LocalFormatNames[this._local2NativeFormatNames[nativename]] = nativename;
+                       node = node.nextSibling;
+               }
+               dojo.doc.body.removeChild(div);
+       },
+
+       open: function(/*DomNode?*/element){
+               // summary:
+               //              Transforms the node referenced in this.domNode into a rich text editing
+               //              node. This will result in the creation and replacement with an <iframe>
+               //              if designMode(FF)/contentEditable(IE) is used.
+
+               if((!this.onLoadDeferred)||(this.onLoadDeferred.fired >= 0)){
+                       this.onLoadDeferred = new dojo.Deferred();
+               }
+
+               if(!this.isClosed){ this.close(); }
+               dojo.publish(dijit._scopeName + "._editor.RichText::open", [ this ]);
+
+               this._content = "";
+               if((arguments.length == 1)&&(element["nodeName"])){ this.domNode = element; } // else unchanged
+
+               var html;
+               if(     (this.domNode["nodeName"])&&
+                       (this.domNode.nodeName.toLowerCase() == "textarea")){
+                       // if we were created from a textarea, then we need to create a
+                       // new editing harness node.
+                       this.textarea = this.domNode;
+                       this.name=this.textarea.name;
+                       html = this._preFilterContent(this.textarea.value);
+                       this.domNode = dojo.doc.createElement("div");
+                       this.domNode.setAttribute('widgetId',this.id);
+                       this.textarea.removeAttribute('widgetId');
+                       this.domNode.cssText = this.textarea.cssText;
+                       this.domNode.className += " "+this.textarea.className;
+                       dojo.place(this.domNode, this.textarea, "before");
+                       var tmpFunc = dojo.hitch(this, function(){
+                               //some browsers refuse to submit display=none textarea, so
+                               //move the textarea out of screen instead
+                               dojo.attr(this.textarea, 'tabIndex', '-1');
+                               with(this.textarea.style){
+                                       display = "block";
+                                       position = "absolute";
+                                       left = top = "-1000px";
+
+                                       if(dojo.isIE){ //nasty IE bug: abnormal formatting if overflow is not hidden
+                                               this.__overflow = overflow;
+                                               overflow = "hidden";
+                                       }
+                               }
+                       });
+                       if(dojo.isIE){
+                               setTimeout(tmpFunc, 10);
+                       }else{
+                               tmpFunc();
+                       }
+
+                       // this.domNode.innerHTML = html;
+
+//                             if(this.textarea.form){
+//                                     // FIXME: port: this used to be before advice!!!
+//                                     dojo.connect(this.textarea.form, "onsubmit", this, function(){
+//                                             // FIXME: should we be calling close() here instead?
+//                                             this.textarea.value = this.getValue();
+//                                     });
+//                             }
+               }else{
+                       html = this._preFilterContent(dijit._editor.getChildrenHtml(this.domNode));
+                       this.domNode.innerHTML = '';
+               }
+               if(html == ""){ html = "&nbsp;"; }
+
+               var content = dojo.contentBox(this.domNode);
+               // var content = dojo.contentBox(this.srcNodeRef);
+               this._oldHeight = content.h;
+               this._oldWidth = content.w;
+
+               // If we're a list item we have to put in a blank line to force the
+               // bullet to nicely align at the top of text
+               if(     (this.domNode["nodeName"]) &&
+                       (this.domNode.nodeName == "LI") ){
+                       this.domNode.innerHTML = " <br>";
+               }
+
+               this.editingArea = dojo.doc.createElement("div");
+               this.domNode.appendChild(this.editingArea);
+
+               if(this.name != "" && (!dojo.config["useXDomain"] || dojo.config["allowXdRichTextSave"])){
+                       var saveTextarea = dojo.byId(dijit._scopeName + "._editor.RichText.savedContent");
+                       if(saveTextarea.value != ""){
+                               var datas = saveTextarea.value.split(this._SEPARATOR), i=0, dat;
+                               while((dat=datas[i++])){
+                                       var data = dat.split(":");
+                                       if(data[0] == this.name){
+                                               html = data[1];
+                                               datas.splice(i, 1);
+                                               break;
+                                       }
+                               }
+                       }
+
+                       // FIXME: need to do something different for Opera/Safari
+                       this.connect(window, "onbeforeunload", "_saveContent");
+                       // dojo.connect(window, "onunload", this, "_saveContent");
+               }
+
+               this.isClosed = false;
+               // Safari's selections go all out of whack if we do it inline,
+               // so for now IE is our only hero
+               //if(typeof dojo.doc.body.contentEditable != "undefined"){
+               if(dojo.isIE || dojo.isSafari || dojo.isOpera){ // contentEditable, easy                
+
+                       if(dojo.config["useXDomain"] && !dojo.config["dojoBlankHtmlUrl"]){
+                               console.debug("dijit._editor.RichText: When using cross-domain Dojo builds,"
+                               + " please save dojo/resources/blank.html to your domain and set djConfig.dojoBlankHtmlUrl"
+                               + " to the path on your domain to blank.html");
+                       }
+
+                       var burl = dojo.config["dojoBlankHtmlUrl"] || (dojo.moduleUrl("dojo", "resources/blank.html")+"");
+                       var ifr = this.editorObject = this.iframe = dojo.doc.createElement('iframe');
+                       ifr.id = this.id+"_iframe";
+                       ifr.src = burl;
+                       ifr.style.border = "none";
+                       ifr.style.width = "100%";
+                       ifr.frameBorder = 0;
+                       // ifr.style.scrolling = this.height ? "auto" : "vertical";
+                       this.editingArea.appendChild(ifr);
+                       var h = null; // set later in non-ie6 branch
+                       var loadFunc = dojo.hitch( this, function(){
+                               if(h){ dojo.disconnect(h); h = null; }
+                               this.window = ifr.contentWindow;
+                               var d = this.document = this.window.document;
+                               d.open();
+                               d.write(this._getIframeDocTxt(html));
+                               d.close();
+
+                               if(dojo.isIE >= 7){
+                                       if(this.height){
+                                               ifr.style.height = this.height;
+                                       }
+                                       if(this.minHeight){
+                                               ifr.style.minHeight = this.minHeight;
+                                       }
+                               }else{
+                                       ifr.style.height = this.height ? this.height : this.minHeight;
+                               }
+
+                               if(dojo.isIE){
+                                       this._localizeEditorCommands();
+                               }
+
+                               this.onLoad();
+                               this.savedContent = this.getValue(true);
+                       });
+                       if(dojo.isIE && dojo.isIE < 7){ // IE 6 is a steaming pile...
+                               var t = setInterval(function(){
+                                       if(ifr.contentWindow.isLoaded){
+                                               clearInterval(t);
+                                               loadFunc();
+                                       }
+                               }, 100);
+                       }else{ // blissful sanity!
+                               h = dojo.connect(
+                                       ((dojo.isIE) ? ifr.contentWindow : ifr), "onload", loadFunc
+                               );
+                       }
+               }else{ // designMode in iframe
+                       this._drawIframe(html);
+                       this.savedContent = this.getValue(true);
+               }
+
+               // TODO: this is a guess at the default line-height, kinda works
+               if(this.domNode.nodeName == "LI"){ this.domNode.lastChild.style.marginTop = "-1.2em"; }
+               this.domNode.className += " RichTextEditable";
+       },
+
+       //static cache variables shared among all instance of this class
+       _local2NativeFormatNames: {},
+       _native2LocalFormatNames: {},
+       _localizedIframeTitles: null,
+
+       _getIframeDocTxt: function(/* String */ html){
+               var _cs = dojo.getComputedStyle(this.domNode);
+               if(dojo.isIE || (!this.height && !dojo.isMoz)){
+                       html="<div>"+html+"</div>";
+               }
+               var font = [ _cs.fontWeight, _cs.fontSize, _cs.fontFamily ].join(" ");
+
+               // line height is tricky - applying a units value will mess things up.
+               // if we can't get a non-units value, bail out.
+               var lineHeight = _cs.lineHeight;
+               if(lineHeight.indexOf("px") >= 0){
+                       lineHeight = parseFloat(lineHeight)/parseFloat(_cs.fontSize);
+                       // console.debug(lineHeight);
+               }else if(lineHeight.indexOf("em")>=0){
+                       lineHeight = parseFloat(lineHeight);
+               }else{
+                       lineHeight = "1.0";
+               }
+               return [
+                       this.isLeftToRight() ? "<html><head>" : "<html dir='rtl'><head>",
+                       (dojo.isMoz ? "<title>" + this._localizedIframeTitles.iframeEditTitle + "</title>" : ""),
+                       "<style>",
+                       "body,html {",
+                       "       background:transparent;",
+                       "       font:", font, ";",
+                       "       padding: 1em 0 0 0;",
+                       "       margin: -1em 0 0 0;", // remove extraneous vertical scrollbar on safari and firefox
+                       "       height: 100%;",
+                       "}",
+                       // TODO: left positioning will cause contents to disappear out of view
+                       //         if it gets too wide for the visible area
+                       "body{",
+                       "       top:0px; left:0px; right:0px;",
+                               ((this.height||dojo.isOpera) ? "" : "position: fixed;"),
+                       // FIXME: IE 6 won't understand min-height?
+                       "       min-height:", this.minHeight, ";",
+                       "       line-height:", lineHeight,
+                       "}",
+                       "p{ margin: 1em 0 !important; }",
+                       (this.height ? // height:auto undoes the height:100%
+                               "" : "body,html{height:auto;overflow-y:hidden;/*for IE*/} body > div {overflow-x:auto;/*for FF to show vertical scrollbar*/}"
+                       ),
+                       "li > ul:-moz-first-node, li > ol:-moz-first-node{ padding-top: 1.2em; } ",
+                       "li{ min-height:1.2em; }",
+                       "</style>",
+                       this._applyEditingAreaStyleSheets(),
+                       "</head><body>"+html+"</body></html>"
+               ].join(""); // String
+       },
+
+       _drawIframe: function(/*String*/html){
+               // summary:
+               //              Draws an iFrame using the existing one if one exists.
+               //              Used by Mozilla, Safari, and Opera
+
+               if(!this.iframe){
+                       var ifr = this.iframe = dojo.doc.createElement("iframe");
+                       ifr.id=this.id;
+                       // this.iframe.src = "about:blank";
+                       // dojo.doc.body.appendChild(this.iframe);
+                       // console.debug(this.iframe.contentDocument.open());
+                       // dojo.body().appendChild(this.iframe);
+                       var ifrs = ifr.style;
+                       // ifrs.border = "1px solid black";
+                       ifrs.border = "none";
+                       ifrs.lineHeight = "0"; // squash line height
+                       ifrs.verticalAlign = "bottom";
+//                     ifrs.scrolling = this.height ? "auto" : "vertical";
+                       this.editorObject = this.iframe;
+                       // get screen reader text for mozilla here, too
+                       this._localizedIframeTitles = dojo.i18n.getLocalization("dijit.form", "Textarea");
+                       // need to find any associated label element and update iframe document title
+                       var label=dojo.query('label[for="'+this.id+'"]');
+                       if(label.length){
+                               this._localizedIframeTitles.iframeEditTitle = label[0].innerHTML + " " + this._localizedIframeTitles.iframeEditTitle;
+                       }
+               }
+               // opera likes this to be outside the with block
+               //      this.iframe.src = "javascript:void(0)";//dojo.uri.dojoUri("src/widget/templates/richtextframe.html") + ((dojo.doc.domain != currentDomain) ? ("#"+dojo.doc.domain) : "");
+               this.iframe.style.width = this.inheritWidth ? this._oldWidth : "100%";
+
+               if(this.height){
+                       this.iframe.style.height = this.height;
+               }else{
+                       this.iframe.height = this._oldHeight;
+               }
+
+               var tmpContent;
+               if(this.textarea){
+                       tmpContent = this.srcNodeRef;
+               }else{
+                       tmpContent = dojo.doc.createElement('div');
+                       tmpContent.style.display="none";
+                       tmpContent.innerHTML = html;
+                       //append tmpContent to under the current domNode so that the margin
+                       //calculation below is correct
+                       this.editingArea.appendChild(tmpContent);
+               }
+
+               this.editingArea.appendChild(this.iframe);
+
+               //do we want to show the content before the editing area finish loading here?
+               //if external style sheets are used for the editing area, the appearance now
+               //and after loading of the editing area won't be the same (and padding/margin
+               //calculation above may not be accurate)
+               //      tmpContent.style.display = "none";
+               //      this.editingArea.appendChild(this.iframe);
+
+               var _iframeInitialized = false;
+               // console.debug(this.iframe);
+               // var contentDoc = this.iframe.contentWindow.document;
+
+
+               // note that on Safari lower than 420+, we have to get the iframe
+               // by ID in order to get something w/ a contentDocument property
+
+               var contentDoc = this.iframe.contentDocument;
+               contentDoc.open();
+               if(dojo.isAIR){
+                       contentDoc.body.innerHTML = html;
+               }else{
+                       contentDoc.write(this._getIframeDocTxt(html));
+               }
+               contentDoc.close();
+
+               // now we wait for onload. Janky hack!
+               var ifrFunc = dojo.hitch(this, function(){
+                       if(!_iframeInitialized){
+                               _iframeInitialized = true;
+                       }else{ return; }
+                       if(!this.editNode){
+                               try{
+                                       if(this.iframe.contentWindow){
+                                               this.window = this.iframe.contentWindow;
+                                               this.document = this.iframe.contentWindow.document
+                                       }else if(this.iframe.contentDocument){
+                                               // for opera
+                                               this.window = this.iframe.contentDocument.window;
+                                               this.document = this.iframe.contentDocument;
+                                       }
+                                       if(!this.document.body){
+                                               throw 'Error';
+                                       }
+                               }catch(e){
+                                       setTimeout(ifrFunc,500);
+                                       _iframeInitialized = false;
+                                       return;
+                               }
+
+                               dojo._destroyElement(tmpContent);
+                               this.onLoad();
+                       }else{
+                               dojo._destroyElement(tmpContent);
+                               this.editNode.innerHTML = html;
+                               this.onDisplayChanged();
+                       }
+                       this._preDomFilterContent(this.editNode);
+               });
+
+               ifrFunc();
+       },
+
+       _applyEditingAreaStyleSheets: function(){
+               // summary:
+               //              apply the specified css files in styleSheets
+               var files = [];
+               if(this.styleSheets){
+                       files = this.styleSheets.split(';');
+                       this.styleSheets = '';
+               }
+
+               //empty this.editingAreaStyleSheets here, as it will be filled in addStyleSheet
+               files = files.concat(this.editingAreaStyleSheets);
+               this.editingAreaStyleSheets = [];
+
+               var text='', i=0, url;
+               while((url=files[i++])){
+                       var abstring = (new dojo._Url(dojo.global.location, url)).toString();
+                       this.editingAreaStyleSheets.push(abstring);
+                       text += '<link rel="stylesheet" type="text/css" href="'+abstring+'"/>'
+               }
+               return text;
+       },
+
+       addStyleSheet: function(/*dojo._Url*/uri){
+               // summary:
+               //              add an external stylesheet for the editing area
+               // uri: a dojo.uri.Uri pointing to the url of the external css file
+               var url=uri.toString();
+
+               //if uri is relative, then convert it to absolute so that it can be resolved correctly in iframe
+               if(url.charAt(0) == '.' || (url.charAt(0) != '/' && !uri.host)){
+                       url = (new dojo._Url(dojo.global.location, url)).toString();
+               }
+
+               if(dojo.indexOf(this.editingAreaStyleSheets, url) > -1){
+//                     console.debug("dijit._editor.RichText.addStyleSheet: Style sheet "+url+" is already applied");
+                       return;
+               }
+
+               this.editingAreaStyleSheets.push(url);
+               if(this.document.createStyleSheet){ //IE
+                       this.document.createStyleSheet(url);
+               }else{ //other browser
+                       var head = this.document.getElementsByTagName("head")[0];
+                       var stylesheet = this.document.createElement("link");
+                       with(stylesheet){
+                               rel="stylesheet";
+                               type="text/css";
+                               href=url;
+                       }
+                       head.appendChild(stylesheet);
+               }
+       },
+
+       removeStyleSheet: function(/*dojo._Url*/uri){
+               // summary:
+               //              remove an external stylesheet for the editing area
+               var url=uri.toString();
+               //if uri is relative, then convert it to absolute so that it can be resolved correctly in iframe
+               if(url.charAt(0) == '.' || (url.charAt(0) != '/' && !uri.host)){
+                       url = (new dojo._Url(dojo.global.location, url)).toString();
+               }
+               var index = dojo.indexOf(this.editingAreaStyleSheets, url);
+               if(index == -1){
+//                     console.debug("dijit._editor.RichText.removeStyleSheet: Style sheet "+url+" has not been applied");
+                       return;
+               }
+               delete this.editingAreaStyleSheets[index];
+               dojo.withGlobal(this.window,'query', dojo, ['link:[href="'+url+'"]']).orphan()
+       },
+
+       disabled: true,
+       _mozSettingProps: ['styleWithCSS','insertBrOnReturn'],
+       setDisabled: function(/*Boolean*/ disabled){
+               if(dojo.isIE || dojo.isSafari || dojo.isOpera){
+                       if(dojo.isIE){ this.editNode.unselectable = "on"; } // prevent IE from setting focus
+                       this.editNode.contentEditable = !disabled;
+                       if(dojo.isIE){
+                               var _this = this;
+                               setTimeout(function(){ _this.editNode.unselectable = "off"; }, 0);
+                       }
+               }else{ //moz
+                       if(disabled){
+                               //AP: why isn't this set in the constructor, or put in mozSettingProps as a hash?
+                               this._mozSettings=[false,this.blockNodeForEnter==='BR'];
+                       }
+                       this.document.designMode=(disabled?'off':'on');
+                       if(!disabled && this._mozSettings){
+                               dojo.forEach(this._mozSettingProps, function(s,i){
+                                       this.document.execCommand(s,false,this._mozSettings[i]);
+                               },this);
+                       }
+//                     this.document.execCommand('contentReadOnly', false, disabled);
+//                             if(disabled){
+//                                     this.blur(); //to remove the blinking caret
+//                             }
+               }
+               this.disabled = disabled;
+       },
+
+/* Event handlers
+ *****************/
+
+       _isResized: function(){ return false; },
+
+       onLoad: function(/* Event */ e){
+               // summary: handler after the content of the document finishes loading
+               this.isLoaded = true;
+               if(!this.window.__registeredWindow){
+                       this.window.__registeredWindow=true;
+                       dijit.registerWin(this.window);
+               }
+               if(!dojo.isIE && (this.height || dojo.isMoz)){
+                       this.editNode=this.document.body;
+               }else{
+                       this.editNode=this.document.body.firstChild;
+                       var _this = this;
+                       if(dojo.isIE){ // #4996 IE wants to focus the BODY tag
+                               var tabStop = this.tabStop = dojo.doc.createElement('<div tabIndex=-1>');
+                               this.editingArea.appendChild(tabStop);
+                               this.iframe.onfocus = function(){ _this.editNode.setActive(); }
+                       }
+               }
+
+               try{
+                       this.setDisabled(false);
+               }catch(e){
+                       // Firefox throws an exception if the editor is initially hidden
+                       // so, if this fails, try again onClick by adding "once" advice
+                       var handle = dojo.connect(this, "onClick", this, function(){
+                               this.setDisabled(false);
+                               dojo.disconnect(handle);
+                       });
+               }
+
+               this._preDomFilterContent(this.editNode);
+
+               var events=this.events.concat(this.captureEvents),i=0,et;
+               while((et=events[i++])){
+                       this.connect(this.document, et.toLowerCase(), et);
+               }
+               if(!dojo.isIE){
+                       try{ // sanity check for Mozilla
+                       //AP: what's the point of this?
+//                                     this.document.execCommand("useCSS", false, true); // old moz call
+                               this.document.execCommand("styleWithCSS", false, false); // new moz call
+                               //this.document.execCommand("insertBrOnReturn", false, false); // new moz call
+                       }catch(e2){ }
+                       // FIXME: when scrollbars appear/disappear this needs to be fired
+               }else{ // IE contentEditable
+                       // give the node Layout on IE
+                       this.connect(this.document, "onmousedown", "_onMouseDown"); // #4996 fix focus
+                       this.editNode.style.zoom = 1.0;
+               }
+
+               if(this.focusOnLoad){
+                       setTimeout(dojo.hitch(this, "focus"), 0); // have to wait for IE to set unselectable=off
+               }
+
+               this.onDisplayChanged(e);
+               if(this.onLoadDeferred){
+                       this.onLoadDeferred.callback(true);
+               }
+       },
+
+       onKeyDown: function(/* Event */ e){
+               // summary: Fired on keydown
+
+               // we need this event at the moment to get the events from control keys
+               // such as the backspace. It might be possible to add this to Dojo, so that
+               // keyPress events can be emulated by the keyDown and keyUp detection.
+               if(dojo.isIE){
+                       if(e.keyCode == dojo.keys.TAB && e.shiftKey && !e.ctrlKey && !e.altKey){
+                               // focus the BODY so the browser will tab away from it instead
+                               this.iframe.focus();
+                       }else if(e.keyCode == dojo.keys.TAB && !e.shiftKey && !e.ctrlKey && !e.altKey){
+                               // focus the BODY so the browser will tab away from it instead
+                               this.tabStop.focus();
+                       }else if(e.keyCode === dojo.keys.BACKSPACE && this.document.selection.type === "Control"){
+                               // IE has a bug where if a non-text object is selected in the editor,
+                 // hitting backspace would act as if the browser's back button was
+                 // clicked instead of deleting the object. see #1069
+                               dojo.stopEvent(e);
+                               this.execCommand("delete");
+                       }else if((65 <= e.keyCode&&e.keyCode <= 90) ||
+                               (e.keyCode>=37&&e.keyCode<=40) // FIXME: get this from connect() instead!
+                       ){ //arrow keys
+                               e.charCode = e.keyCode;
+                               this.onKeyPress(e);
+                       }
+               }else if(dojo.isMoz){
+                       if(e.keyCode == dojo.keys.TAB && !e.shiftKey && !e.ctrlKey && !e.altKey && this.iframe){
+                               // update iframe document title for screen reader
+                               this.iframe.contentDocument.title = this._localizedIframeTitles.iframeFocusTitle;
+                               
+                               // Place focus on the iframe. A subsequent tab or shift tab will put focus
+                               // on the correct control.
+                               this.iframe.focus();  // this.focus(); won't work
+                               dojo.stopEvent(e);
+                       }else if(e.keyCode == dojo.keys.TAB && e.shiftKey){
+                               // if there is a toolbar, set focus to it, otherwise ignore
+                               if(this.toolbar){
+                                       this.toolbar.focus();
+                               }
+                               dojo.stopEvent(e);
+                       }
+               }
+       },
+
+       onKeyUp: function(e){
+               // summary: Fired on keyup
+               return;
+       },
+
+       KEY_CTRL: 1,
+       KEY_SHIFT: 2,
+
+       onKeyPress: function(e){
+               // summary: Fired on keypress
+
+               // handle the various key events
+               var modifiers = (e.ctrlKey && !e.altKey) ? this.KEY_CTRL : 0 | e.shiftKey ? this.KEY_SHIFT : 0;
+
+               var key = e.keyChar || e.keyCode;
+               if(this._keyHandlers[key]){
+                       // console.debug("char:", e.key);
+                       var handlers = this._keyHandlers[key], i = 0, h;
+                       while((h = handlers[i++])){
+                               if(modifiers == h.modifiers){
+                                       if(!h.handler.apply(this,arguments)){
+                                               e.preventDefault();
+                                       }
+                                       break;
+                               }
+                       }
+               }
+
+               // function call after the character has been inserted
+               setTimeout(dojo.hitch(this, function(){
+                       this.onKeyPressed(e);
+               }), 1);
+       },
+
+       addKeyHandler: function(/*String*/key, /*Int*/modifiers, /*Function*/handler){
+               // summary: add a handler for a keyboard shortcut
+               if(!dojo.isArray(this._keyHandlers[key])){ this._keyHandlers[key] = []; }
+               this._keyHandlers[key].push({
+                       modifiers: modifiers || 0,
+                       handler: handler
+               });
+       },
+
+       onKeyPressed: function(/*Event*/e){
+               this.onDisplayChanged(/*e*/); // can't pass in e
+       },
+
+       onClick: function(/*Event*/e){
+//             console.info('onClick',this._tryDesignModeOn);
+               this.onDisplayChanged(e);
+       },
+
+       _onMouseDown: function(/*Event*/e){ // IE only to prevent 2 clicks to focus
+               if(!this._focused && !this.disabled){
+                       this.focus();
+               }
+       },
+
+       _onBlur: function(e){
+               this.inherited(arguments);
+               var _c=this.getValue(true);
+               if(_c!=this.savedContent){
+                       this.onChange(_c);
+                       this.savedContent=_c;
+               }
+               if(dojo.isMoz && this.iframe){
+                       this.iframe.contentDocument.title = this._localizedIframeTitles.iframeEditTitle;
+               } 
+       },
+       _initialFocus: true,
+       _onFocus: function(/*Event*/e){
+               // summary: Fired on focus
+               this.inherited(arguments);
+               if(dojo.isMoz && this._initialFocus){
+                       this._initialFocus = false;
+                       if(this.editNode.innerHTML.replace(/^\s+|\s+$/g, "") == "&nbsp;"){
+                               this.placeCursorAtStart();
+//                                     this.execCommand("selectall");
+//                                     this.window.getSelection().collapseToStart();
+                       }
+               }
+       },
+
+       // TODO: why is this needed - should we deprecate this ?
+       blur: function(){
+               // summary: remove focus from this instance
+               if(!dojo.isIE && this.window.document.documentElement && this.window.document.documentElement.focus){
+                       this.window.document.documentElement.focus();
+               }else if(dojo.doc.body.focus){
+                       dojo.doc.body.focus();
+               }
+       },
+
+       focus: function(){
+               // summary: move focus to this instance
+               if(!dojo.isIE){
+                       dijit.focus(this.iframe);
+               }else if(this.editNode && this.editNode.focus){
+                       // editNode may be hidden in display:none div, lets just punt in this case
+                       //this.editNode.focus(); -> causes IE to scroll always (strict and quirks mode) to the top the Iframe 
+                       // if we fire the event manually and let the browser handle the focusing, the latest  
+                       // cursor position is focused like in FF                         
+                       this.iframe.fireEvent('onfocus', document.createEventObject()); // createEventObject only in IE 
+//             }else{
+// TODO: should we throw here?
+//                     console.debug("Have no idea how to focus into the editor!");
+               }
+       },
+
+//             _lastUpdate: 0,
+       updateInterval: 200,
+       _updateTimer: null,
+       onDisplayChanged: function(/*Event*/e){
+               // summary:
+               //              This event will be fired everytime the display context
+               //              changes and the result needs to be reflected in the UI.
+               // description:
+               //              If you don't want to have update too often,
+               //              onNormalizedDisplayChanged should be used instead
+
+//                     var _t=new Date();
+               if(!this._updateTimer){
+//                             this._lastUpdate=_t;
+                       if(this._updateTimer){
+                               clearTimeout(this._updateTimer);
+                       }
+                       this._updateTimer=setTimeout(dojo.hitch(this,this.onNormalizedDisplayChanged),this.updateInterval);
+               }
+       },
+       onNormalizedDisplayChanged: function(){
+               // summary:
+               //              This event is fired every updateInterval ms or more
+               // description:
+               //              If something needs to happen immidiately after a
+               //              user change, please use onDisplayChanged instead
+               this._updateTimer=null;
+       },
+       onChange: function(newContent){
+               // summary:
+               //              this is fired if and only if the editor loses focus and
+               //              the content is changed
+
+//                     console.log('onChange',newContent);
+       },
+       _normalizeCommand: function(/*String*/cmd){
+               // summary:
+               //              Used as the advice function by dojo.connect to map our
+               //              normalized set of commands to those supported by the target
+               //              browser
+
+               var command = cmd.toLowerCase();
+               if(command == "hilitecolor" && !dojo.isMoz){
+                       command = "backcolor";
+               }
+
+               return command;
+       },
+
+       queryCommandAvailable: function(/*String*/command){
+               // summary:
+               //              Tests whether a command is supported by the host. Clients SHOULD check
+               //              whether a command is supported before attempting to use it, behaviour
+               //              for unsupported commands is undefined.
+               // command: The command to test for
+               var ie = 1;
+               var mozilla = 1 << 1;
+               var safari = 1 << 2;
+               var opera = 1 << 3;
+               var safari420 = 1 << 4;
+
+               var gt420 = dojo.isSafari;
+
+               function isSupportedBy(browsers){
+                       return {
+                               ie: Boolean(browsers & ie),
+                               mozilla: Boolean(browsers & mozilla),
+                               safari: Boolean(browsers & safari),
+                               safari420: Boolean(browsers & safari420),
+                               opera: Boolean(browsers & opera)
+                       }
+               }
+
+               var supportedBy = null;
+
+               switch(command.toLowerCase()){
+                       case "bold": case "italic": case "underline":
+                       case "subscript": case "superscript":
+                       case "fontname": case "fontsize":
+                       case "forecolor": case "hilitecolor":
+                       case "justifycenter": case "justifyfull": case "justifyleft":
+                       case "justifyright": case "delete": case "selectall": case "toggledir":
+                               supportedBy = isSupportedBy(mozilla | ie | safari | opera);
+                               break;
+
+                       case "createlink": case "unlink": case "removeformat":
+                       case "inserthorizontalrule": case "insertimage":
+                       case "insertorderedlist": case "insertunorderedlist":
+                       case "indent": case "outdent": case "formatblock":
+                       case "inserthtml": case "undo": case "redo": case "strikethrough":
+                               supportedBy = isSupportedBy(mozilla | ie | opera | safari420);
+                               break;
+
+                       case "blockdirltr": case "blockdirrtl":
+                       case "dirltr": case "dirrtl":
+                       case "inlinedirltr": case "inlinedirrtl":
+                               supportedBy = isSupportedBy(ie);
+                               break;
+                       case "cut": case "copy": case "paste":
+                               supportedBy = isSupportedBy( ie | mozilla | safari420);
+                               break;
+
+                       case "inserttable":
+                               supportedBy = isSupportedBy(mozilla | ie);
+                               break;
+
+                       case "insertcell": case "insertcol": case "insertrow":
+                       case "deletecells": case "deletecols": case "deleterows":
+                       case "mergecells": case "splitcell":
+                               supportedBy = isSupportedBy(ie | mozilla);
+                               break;
+
+                       default: return false;
+               }
+
+               return (dojo.isIE && supportedBy.ie) ||
+                       (dojo.isMoz && supportedBy.mozilla) ||
+                       (dojo.isSafari && supportedBy.safari) ||
+                       (gt420 && supportedBy.safari420) ||
+                       (dojo.isOpera && supportedBy.opera);  // Boolean return true if the command is supported, false otherwise
+       },
+
+       execCommand: function(/*String*/command, argument){
+               // summary: Executes a command in the Rich Text area
+               // command: The command to execute
+               // argument: An optional argument to the command
+               var returnValue;
+
+               //focus() is required for IE to work
+               //In addition, focus() makes sure after the execution of
+               //the command, the editor receives the focus as expected
+               this.focus();
+
+               command = this._normalizeCommand(command);
+               if(argument != undefined){
+                       if(command == "heading"){
+                               throw new Error("unimplemented");
+                       }else if((command == "formatblock") && dojo.isIE){
+                               argument = '<'+argument+'>';
+                       }
+               }
+               if(command == "inserthtml"){
+                       argument=this._preFilterContent(argument);
+                       if(dojo.isIE){
+                               var insertRange = this.document.selection.createRange();
+                               if(this.document.selection.type.toUpperCase()=='CONTROL'){
+                                       var n=insertRange.item(0);
+                                       while(insertRange.length){
+                                               insertRange.remove(insertRange.item(0));
+                                       }
+                                       n.outerHTML=argument;
+                               }else{
+                                       insertRange.pasteHTML(argument);
+                               }
+                               insertRange.select();
+                               //insertRange.collapse(true);
+                               returnValue=true;
+                       }else if(dojo.isMoz && !argument.length){
+                               //mozilla can not inserthtml an empty html to delete current selection
+                               //so we delete the selection instead in this case
+                               dojo.withGlobal(this.window,'remove',dijit._editor.selection);
+                               returnValue=true;
+                       }else{
+                               returnValue=this.document.execCommand(command, false, argument);
+                       }
+               }else if(
+                       (command == "unlink")&&
+                       (this.queryCommandEnabled("unlink"))&&
+                       (dojo.isMoz || dojo.isSafari)
+               ){
+                       // fix up unlink in Mozilla to unlink the link and not just the selection
+
+                       // grab selection
+                       // Mozilla gets upset if we just store the range so we have to
+                       // get the basic properties and recreate to save the selection
+                       var selection = this.window.getSelection();
+                       //      var selectionRange = selection.getRangeAt(0);
+                       //      var selectionStartContainer = selectionRange.startContainer;
+                       //      var selectionStartOffset = selectionRange.startOffset;
+                       //      var selectionEndContainer = selectionRange.endContainer;
+                       //      var selectionEndOffset = selectionRange.endOffset;
+
+                       // select our link and unlink
+                       var a = dojo.withGlobal(this.window, "getAncestorElement",dijit._editor.selection, ['a']);
+                       dojo.withGlobal(this.window, "selectElement", dijit._editor.selection, [a]);
+
+                       returnValue=this.document.execCommand("unlink", false, null);
+               }else if((command == "hilitecolor")&&(dojo.isMoz)){
+//                             // mozilla doesn't support hilitecolor properly when useCSS is
+//                             // set to false (bugzilla #279330)
+
+                       this.document.execCommand("styleWithCSS", false, true);
+                       returnValue = this.document.execCommand(command, false, argument);
+                       this.document.execCommand("styleWithCSS", false, false);
+
+               }else if((dojo.isIE)&&( (command == "backcolor")||(command == "forecolor") )){
+                       // Tested under IE 6 XP2, no problem here, comment out
+                       // IE weirdly collapses ranges when we exec these commands, so prevent it
+//                             var tr = this.document.selection.createRange();
+                       argument = arguments.length > 1 ? argument : null;
+                       returnValue = this.document.execCommand(command, false, argument);
+
+                       // timeout is workaround for weird IE behavior were the text
+                       // selection gets correctly re-created, but subsequent input
+                       // apparently isn't bound to it
+//                             setTimeout(function(){tr.select();}, 1);
+               }else{
+                       argument = arguments.length > 1 ? argument : null;
+//                             if(dojo.isMoz){
+//                                     this.document = this.iframe.contentWindow.document
+//                             }
+
+                       if(argument || command!="createlink"){
+                               returnValue = this.document.execCommand(command, false, argument);
+                       }
+               }
+
+               this.onDisplayChanged();
+               return returnValue;
+       },
+
+       queryCommandEnabled: function(/*String*/command){
+               // summary: check whether a command is enabled or not
+
+               if(this.disabled){ return false; }
+               command = this._normalizeCommand(command);
+               if(dojo.isMoz || dojo.isSafari){
+                       if(command == "unlink"){ // mozilla returns true always
+                               // console.debug(dojo.withGlobal(this.window, "hasAncestorElement",dijit._editor.selection, ['a']));
+                               return dojo.withGlobal(this.window, "hasAncestorElement",dijit._editor.selection, ['a']);
+                       }else if(command == "inserttable"){
+                               return true;
+                       }
+               }
+               //see #4109
+               if(dojo.isSafari){
+                       if(command == "copy"){
+                               command = "cut";
+                       }else if(command == "paste"){
+                               return true;
+                       }
+               }
+
+               // return this.document.queryCommandEnabled(command);
+               var elem = dojo.isIE ? this.document.selection.createRange() : this.document;
+               return elem.queryCommandEnabled(command);
+       },
+
+       queryCommandState: function(command){
+               // summary: check the state of a given command
+
+               if(this.disabled){ return false; }
+               command = this._normalizeCommand(command);
+               return this.document.queryCommandState(command);
+       },
+
+       queryCommandValue: function(command){
+               // summary: check the value of a given command
+
+               if(this.disabled){ return false; }
+               command = this._normalizeCommand(command);
+               if(dojo.isIE && command == "formatblock"){
+                       return this._local2NativeFormatNames[this.document.queryCommandValue(command)];
+               }
+               return this.document.queryCommandValue(command);
+       },
+
+       // Misc.
+
+       placeCursorAtStart: function(){
+               // summary:
+               //              place the cursor at the start of the editing area
+               this.focus();
+
+               //see comments in placeCursorAtEnd
+               var isvalid=false;
+               if(dojo.isMoz){
+                       var first=this.editNode.firstChild;
+                       while(first){
+                               if(first.nodeType == 3){
+                                       if(first.nodeValue.replace(/^\s+|\s+$/g, "").length>0){
+                                               isvalid=true;
+                                               dojo.withGlobal(this.window, "selectElement", dijit._editor.selection, [first]);
+                                               break;
+                                       }
+                               }else if(first.nodeType == 1){
+                                       isvalid=true;
+                                       dojo.withGlobal(this.window, "selectElementChildren",dijit._editor.selection, [first]);
+                                       break;
+                               }
+                               first = first.nextSibling;
+                       }
+               }else{
+                       isvalid=true;
+                       dojo.withGlobal(this.window, "selectElementChildren",dijit._editor.selection, [this.editNode]);
+               }
+               if(isvalid){
+                       dojo.withGlobal(this.window, "collapse", dijit._editor.selection, [true]);
+               }
+       },
+
+       placeCursorAtEnd: function(){
+               // summary:
+               //              place the cursor at the end of the editing area
+               this.focus();
+
+               //In mozilla, if last child is not a text node, we have to use selectElementChildren on this.editNode.lastChild
+               //otherwise the cursor would be placed at the end of the closing tag of this.editNode.lastChild
+               var isvalid=false;
+               if(dojo.isMoz){
+                       var last=this.editNode.lastChild;
+                       while(last){
+                               if(last.nodeType == 3){
+                                       if(last.nodeValue.replace(/^\s+|\s+$/g, "").length>0){
+                                               isvalid=true;
+                                               dojo.withGlobal(this.window, "selectElement",dijit._editor.selection, [last]);
+                                               break;
+                                       }
+                               }else if(last.nodeType == 1){
+                                       isvalid=true;
+                                       if(last.lastChild){
+                                               dojo.withGlobal(this.window, "selectElement",dijit._editor.selection, [last.lastChild]);
+                                       }else{
+                                               dojo.withGlobal(this.window, "selectElement",dijit._editor.selection, [last]);
+                                       }
+                                       break;
+                               }
+                               last = last.previousSibling;
+                       }
+               }else{
+                       isvalid=true;
+                       dojo.withGlobal(this.window, "selectElementChildren",dijit._editor.selection, [this.editNode]);
+               }
+               if(isvalid){
+                       dojo.withGlobal(this.window, "collapse", dijit._editor.selection, [false]);
+               }
+       },
+
+       getValue: function(/*Boolean?*/nonDestructive){
+               // summary:
+               //              return the current content of the editing area (post filters are applied)
+               if(this.textarea){
+                       if(this.isClosed || !this.isLoaded){
+                               return this.textarea.value;
+                       }
+               }
+
+               return this._postFilterContent(null, nonDestructive);
+       },
+
+       setValue: function(/*String*/html){
+               // summary:
+               //              this function set the content. No undo history is preserved
+
+               if(!this.isLoaded){
+                       // try again after the editor is finished loading
+                       this.onLoadDeferred.addCallback(dojo.hitch(this, function(){
+                               this.setValue(html);
+                       }));
+                       return;
+               }
+
+               if(this.textarea && (this.isClosed || !this.isLoaded)){
+                       this.textarea.value=html;
+               }else{
+                       html = this._preFilterContent(html);
+                       var node = this.isClosed ? this.domNode : this.editNode;
+                       node.innerHTML = html;
+                       this._preDomFilterContent(node);
+               }
+
+               this.onDisplayChanged();
+       },
+
+       replaceValue: function(/*String*/html){
+               // summary:
+               //              this function set the content while trying to maintain the undo stack
+               //              (now only works fine with Moz, this is identical to setValue in all
+               //              other browsers)
+               if(this.isClosed){
+                       this.setValue(html);
+               }else if(this.window && this.window.getSelection && !dojo.isMoz){ // Safari
+                       // look ma! it's a totally f'd browser!
+                       this.setValue(html);
+               }else if(this.window && this.window.getSelection){ // Moz
+                       html = this._preFilterContent(html);
+                       this.execCommand("selectall");
+                       if(dojo.isMoz && !html){ html = "&nbsp;" }
+                       this.execCommand("inserthtml", html);
+                       this._preDomFilterContent(this.editNode);
+               }else if(this.document && this.document.selection){//IE
+                       //In IE, when the first element is not a text node, say
+                       //an <a> tag, when replacing the content of the editing
+                       //area, the <a> tag will be around all the content
+                       //so for now, use setValue for IE too
+                       this.setValue(html);
+               }
+       },
+
+       _preFilterContent: function(/*String*/html){
+               // summary:
+               //              filter the input before setting the content of the editing area
+               var ec = html;
+               dojo.forEach(this.contentPreFilters, function(ef){ if(ef){ ec = ef(ec); } });
+               return ec;
+       },
+       _preDomFilterContent: function(/*DomNode*/dom){
+               // summary:
+               //              filter the input
+               dom = dom || this.editNode;
+               dojo.forEach(this.contentDomPreFilters, function(ef){
+                       if(ef && dojo.isFunction(ef)){
+                               ef(dom);
+                       }
+               }, this);
+       },
+
+       _postFilterContent: function(/*DomNode|DomNode[]|String?*/dom,/*Boolean?*/nonDestructive){
+               // summary:
+               //              filter the output after getting the content of the editing area
+               var ec;
+               if(!dojo.isString(dom)){
+                       dom = dom || this.editNode;
+                       if(this.contentDomPostFilters.length){
+                               if(nonDestructive && dom['cloneNode']){
+                                       dom = dom.cloneNode(true);
+                               }
+                               dojo.forEach(this.contentDomPostFilters, function(ef){
+                                       dom = ef(dom);
+                               });
+                       }
+                       ec = dijit._editor.getChildrenHtml(dom);
+               }else{
+                       ec = dom;
+               }
+               
+               if(!ec.replace(/^(?:\s|\xA0)+/g, "").replace(/(?:\s|\xA0)+$/g,"").length){ ec = ""; }
+
+               //      if(dojo.isIE){
+               //              //removing appended <P>&nbsp;</P> for IE
+               //              ec = ec.replace(/(?:<p>&nbsp;</p>[\n\r]*)+$/i,"");
+               //      }
+               dojo.forEach(this.contentPostFilters, function(ef){
+                       ec = ef(ec);
+               });
+
+               return ec;
+       },
+
+       _saveContent: function(/*Event*/e){
+               // summary:
+               //              Saves the content in an onunload event if the editor has not been closed
+               var saveTextarea = dojo.byId(dijit._scopeName + "._editor.RichText.savedContent");
+               saveTextarea.value += this._SEPARATOR + this.name + ":" + this.getValue();
+       },
+
+       escapeXml: function(/*String*/str, /*Boolean*/noSingleQuotes){
+               dojo.deprecated('dijit.Editor::escapeXml is deprecated','use dijit._editor.escapeXml instead', 2);
+               return dijit._editor.escapeXml(str,noSingleQuotes);
+       },
+
+       getNodeHtml: function(/* DomNode */node){
+               dojo.deprecated('dijit.Editor::getNodeHtml is deprecated','use dijit._editor.getNodeHtml instead', 2);
+               return dijit._editor.getNodeHtml(node);
+       },
+
+       getNodeChildrenHtml: function(/* DomNode */dom){
+               dojo.deprecated('dijit.Editor::getNodeChildrenHtml is deprecated','use dijit._editor.getChildrenHtml instead', 2);
+               return dijit._editor.getChildrenHtml(dom);
+       },
+
+       close: function(/*Boolean*/save, /*Boolean*/force){
+               // summary:
+               //              Kills the editor and optionally writes back the modified contents to the
+               //              element from which it originated.
+               // save:
+               //              Whether or not to save the changes. If false, the changes are discarded.
+               // force:
+               if(this.isClosed){return false; }
+
+               if(!arguments.length){ save = true; }
+               this._content = this.getValue();
+               var changed = (this.savedContent != this._content);
+
+               // line height is squashed for iframes
+               // FIXME: why was this here? if(this.iframe){ this.domNode.style.lineHeight = null; }
+
+               if(this.interval){ clearInterval(this.interval); }
+
+               if(this.textarea){
+                       with(this.textarea.style){
+                               position = "";
+                               left = top = "";
+                               if(dojo.isIE){
+                                       overflow = this.__overflow;
+                                       this.__overflow = null;
+                               }
+                       }
+                       this.textarea.value = save ? this._content : this.savedContent;
+                       dojo._destroyElement(this.domNode);
+                       this.domNode = this.textarea;
+               }else{
+//                     if(save){
+                               //why we treat moz differently? comment out to fix #1061
+//                                     if(dojo.isMoz){
+//                                             var nc = dojo.doc.createElement("span");
+//                                             this.domNode.appendChild(nc);
+//                                             nc.innerHTML = this.editNode.innerHTML;
+//                                     }else{
+//                                             this.domNode.innerHTML = this._content;
+//                                     }
+//                     }
+                       this.domNode.innerHTML = save ? this._content : this.savedContent;
+               }
+
+               dojo.removeClass(this.domNode, "RichTextEditable");
+               this.isClosed = true;
+               this.isLoaded = false;
+               // FIXME: is this always the right thing to do?
+               delete this.editNode;
+
+               if(this.window && this.window._frameElement){
+                       this.window._frameElement = null;
+               }
+
+               this.window = null;
+               this.document = null;
+               this.editingArea = null;
+               this.editorObject = null;
+
+               return changed; // Boolean: whether the content has been modified
+       },
+
+       destroyRendering: function(){
+               // summary: stub        
+       }, 
+
+       destroy: function(){
+               this.destroyRendering();
+               if(!this.isClosed){ this.close(false); }
+               this.inherited("destroy",arguments);
+               //dijit._editor.RichText.superclass.destroy.call(this);
+       },
+
+       _removeMozBogus: function(/* String */ html){
+               return html.replace(/\stype="_moz"/gi, '').replace(/\s_moz_dirty=""/gi, ''); // String
+       },
+       _removeSafariBogus: function(/* String */ html){
+               return html.replace(/\sclass="webkit-block-placeholder"/gi, ''); // String
+       },
+       _fixContentForMoz: function(/* String */ html){
+               // summary:
+               //              Moz can not handle strong/em tags correctly, convert them to b/i
+               return html.replace(/<(\/)?strong([ \>])/gi, '<$1b$2')
+                       .replace(/<(\/)?em([ \>])/gi, '<$1i$2' ); // String
+       },
+
+       _srcInImgRegex  : /(?:(<img(?=\s).*?\ssrc=)("|')(.*?)\2)|(?:(<img\s.*?src=)([^"'][^ >]+))/gi ,
+       _hrefInARegex   : /(?:(<a(?=\s).*?\shref=)("|')(.*?)\2)|(?:(<a\s.*?href=)([^"'][^ >]+))/gi ,
+
+       _preFixUrlAttributes: function(/* String */ html){
+               return html.replace(this._hrefInARegex, '$1$4$2$3$5$2 _djrealurl=$2$3$5$2')
+                       .replace(this._srcInImgRegex, '$1$4$2$3$5$2 _djrealurl=$2$3$5$2'); // String
+       }
+});
+
+}