New file |
0,0 → 1,1446 |
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("dojo.i18n"); |
dojo.requireLocalization("dijit", "Textarea", null, "ROOT"); |
|
// used to restore content when user leaves this page then comes back |
// but do not try doing document.write if we are using xd loading. |
// document.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 djConfig.allowXdRichTextSave = true. |
if(!djConfig["useXDomain"] || djConfig["allowXdRichTextSave"]){ |
if(dojo._postLoad){ |
(function(){ |
var savetextarea = dojo.doc.createElement('textarea'); |
savetextarea.id = "dijit._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._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.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._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 ctrl = this.KEY_CTRL; |
var exec = function(cmd, arg){ |
return arguments.length == 1 ? function(){ this.execCommand(cmd); } : |
function(){ this.execCommand(cmd, arg); } |
} |
this.addKeyHandler("b", ctrl, exec("bold")); |
this.addKeyHandler("i", ctrl, exec("italic")); |
this.addKeyHandler("u", ctrl, exec("underline")); |
this.addKeyHandler("a", ctrl, exec("selectall")); |
this.addKeyHandler("s", ctrl, function () { this.save(true); }); |
|
this.addKeyHandler("1", ctrl, exec("formatblock", "h1")); |
this.addKeyHandler("2", ctrl, exec("formatblock", "h2")); |
this.addKeyHandler("3", ctrl, exec("formatblock", "h3")); |
this.addKeyHandler("4", ctrl, exec("formatblock", "h4")); |
|
this.addKeyHandler("\\", ctrl, exec("insertunorderedlist")); |
if(!dojo.isIE){ |
this.addKeyHandler("Z", ctrl, exec("redo")); |
} |
}, |
|
// 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=document.createElement('div'); |
div.style.position = "absolute"; |
div.style.left = "-2000px"; |
div.style.top = "-2000px"; |
document.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] = document.queryCommandValue("formatblock");//this.queryCommandValue("formatblock"); |
this._native2LocalFormatNames[this._local2NativeFormatNames[nativename]] = nativename; |
node = node.nextSibling; |
} |
document.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._editor.RichText::open", [ this ]); |
|
this._content = ""; |
if((arguments.length == 1)&&(element["nodeName"])){ this.domNode = element; } // else unchanged |
|
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; |
var 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 |
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{ |
var html = this._preFilterContent(this.getNodeChildrenHtml(this.domNode)); |
this.domNode.innerHTML = ''; |
} |
if(html == ""){ html = " "; } |
|
var content = dojo.contentBox(this.domNode); |
// var content = dojo.contentBox(this.srcNodeRef); |
this._oldHeight = content.h; |
this._oldWidth = content.w; |
|
this.savedContent = html; |
|
// 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 != "" && (!djConfig["useXDomain"] || djConfig["allowXdRichTextSave"])){ |
var saveTextarea = dojo.byId("dijit._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 |
dojo.connect(window, "onbeforeunload", this, "_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 document.body.contentEditable != "undefined") { |
if(dojo.isIE || dojo.isSafari || dojo.isOpera){ // contentEditable, easy |
var ifr = this.iframe = dojo.doc.createElement('iframe'); |
ifr.src = 'javascript:void(0)'; |
this.editorObject = ifr; |
ifr.style.border = "none"; |
ifr.style.width = "100%"; |
ifr.frameBorder = 0; |
// ifr.style.scrolling = this.height ? "auto" : "vertical"; |
this.editingArea.appendChild(ifr); |
this.window = ifr.contentWindow; |
this.document = this.window.document; |
this.document.open(); |
this.document.write(this._getIframeDocTxt(html)); |
this.document.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(); |
}else{ // designMode in iframe |
this._drawIframe(html); |
} |
|
// 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(!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;", |
" padding: 0;", |
" margin: 0;", |
"}", |
// 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;"), |
" font:", font, ";", |
// FIXME: IE 6 won't understand min-height? |
" min-height:", this.minHeight, ";", |
" line-height:", lineHeight, |
"}", |
"p{ margin: 1em 0 !important; }", |
(this.height ? |
"" : "body,html{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"); |
// this.iframe.src = "about:blank"; |
// document.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", "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; |
} |
|
if(this.textarea){ |
var tmpContent = this.srcNodeRef; |
}else{ |
var 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(); |
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.document.designMode = "on"; |
// try{ |
// this.document.designMode = "on"; |
// }catch(e){ |
// this._tryDesignModeOnClick=true; |
// } |
|
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 to the editing area!"); |
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+" is not applied to the editing area so it can not be removed!"); |
return; |
} |
delete this.editingAreaStyleSheets[index]; |
dojo.withGlobal(this.window,'query', dojo, ['link:[href="'+url+'"]']).orphan() |
}, |
|
disabled: false, |
_mozSettingProps: ['styleWithCSS','insertBrOnReturn'], |
setDisabled: function(/*Boolean*/ disabled){ |
if(dojo.isIE || dojo.isSafari || dojo.isOpera){ |
this.editNode.contentEditable=!disabled; |
}else{ //moz |
if(disabled){ |
this._mozSettings=[false,this.blockNodeForEnter==='BR']; |
} |
this.document.designMode=(disabled?'off':'on'); |
if(!disabled){ |
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.height || dojo.isMoz){ |
this.editNode=this.document.body; |
}else{ |
this.editNode=this.document.body.firstChild; |
} |
this.editNode.contentEditable = true; //should do no harm in FF |
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 |
// 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.editNode.style.zoom = 1.0; |
} |
|
if(this.focusOnLoad){ |
this.focus(); |
} |
|
this.onDisplayChanged(e); |
if(this.onLoadDeferred){ |
this.onLoadDeferred.callback(true); |
} |
}, |
|
onKeyDown: function(/* Event */ e){ |
// summary: Fired on keydown |
|
// console.info("onkeydown:", e.keyCode); |
|
// 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.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 |
|
// console.info("onkeypress:", e.keyCode); |
|
// handle the various key events |
var modifiers = e.ctrlKey ? 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.debug('onClick',this._tryDesignModeOnClick); |
// if(this._tryDesignModeOnClick){ |
// try{ |
// this.document.designMode='on'; |
// this._tryDesignModeOnClick=false; |
// }catch(e){} |
// } |
this.onDisplayChanged(e); }, |
_onBlur: function(e){ |
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; |
} |
// console.info('_onBlur') |
}, |
_initialFocus: true, |
_onFocus: function(/*Event*/e){ |
// console.info('_onFocus') |
// summary: Fired on focus |
if( (dojo.isMoz)&&(this._initialFocus) ){ |
this._initialFocus = false; |
if(this.editNode.innerHTML.replace(/^\s+|\s+$/g, "") == " "){ |
this.placeCursorAtStart(); |
// this.execCommand("selectall"); |
// this.window.getSelection().collapseToStart(); |
} |
} |
}, |
|
blur: function(){ |
// summary: remove focus from this instance |
if(this.iframe){ |
this.window.blur(); |
}else if(this.editNode){ |
this.editNode.blur(); |
} |
}, |
|
focus: function(){ |
// summary: move focus to this instance |
if(this.iframe && !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 |
dijit.focus(this.editNode); |
}else{ |
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 == "formatblock"){ |
if(dojo.isSafari){ command = "heading"; } |
}else 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": |
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"){ |
//TODO: we shall probably call _preDomFilterContent here as well |
argument=this._preFilterContent(argument); |
if(dojo.isIE){ |
var insertRange = this.document.selection.createRange(); |
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); // FIXME |
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 |
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 |
command = this._normalizeCommand(command); |
return this.document.queryCommandState(command); |
}, |
|
queryCommandValue: function(command){ |
// summary: check the value of a given command |
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.textarea && (this.isClosed || !this.isLoaded)){ |
this.textarea.value=html; |
}else{ |
html = this._preFilterContent(html); |
if(this.isClosed){ |
this.domNode.innerHTML = html; |
this._preDomFilterContent(this.domNode); |
}else{ |
this.editNode.innerHTML = html; |
this._preDomFilterContent(this.editNode); |
} |
} |
}, |
|
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 = " " } |
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[]?*/dom,/*Boolean?*/nonDestructive){ |
// summary: |
// filter the output after getting the content of the editing area |
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); |
}); |
} |
var ec = this.getNodeChildrenHtml(dom); |
if(!ec.replace(/^(?:\s|\xA0)+/g, "").replace(/(?:\s|\xA0)+$/g,"").length){ ec = ""; } |
|
// if(dojo.isIE){ |
// //removing appended <P> </P> for IE |
// ec = ec.replace(/(?:<p> </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._editor.RichText.savedContent"); |
saveTextarea.value += this._SEPARATOR + this.name + ":" + this.getValue(); |
}, |
|
|
escapeXml: function(/*String*/str, /*Boolean*/noSingleQuotes){ |
//summary: |
// Adds escape sequences for special characters in XML: &<>"' |
// Optionally skips escapes for single quotes |
str = str.replace(/&/gm, "&").replace(/</gm, "<").replace(/>/gm, ">").replace(/"/gm, """); |
if(!noSingleQuotes){ |
str = str.replace(/'/gm, "'"); |
} |
return str; // string |
}, |
|
getNodeHtml: function(/* DomNode */node){ |
switch(node.nodeType){ |
case 1: //element node |
var output = '<'+node.tagName.toLowerCase(); |
if(dojo.isMoz){ |
if(node.getAttribute('type')=='_moz'){ |
node.removeAttribute('type'); |
} |
if(node.getAttribute('_moz_dirty') != undefined){ |
node.removeAttribute('_moz_dirty'); |
} |
} |
//store the list of attributes and sort it to have the |
//attributes appear in the dictionary order |
var attrarray = []; |
if(dojo.isIE){ |
var s = node.outerHTML; |
s = s.substr(0,s.indexOf('>')); |
s = s.replace(/(?:['"])[^"']*\1/g, '');//to make the following regexp safe |
var reg = /([^\s=]+)=/g; |
var m, key; |
while((m = reg.exec(s)) != undefined){ |
key=m[1]; |
if(key.substr(0,3) != '_dj'){ |
if(key == 'src' || key == 'href'){ |
if(node.getAttribute('_djrealurl')){ |
attrarray.push([key,node.getAttribute('_djrealurl')]); |
continue; |
} |
} |
if(key == 'class'){ |
attrarray.push([key,node.className]); |
}else{ |
attrarray.push([key,node.getAttribute(key)]); |
} |
} |
} |
}else{ |
var attr, i=0, attrs = node.attributes; |
while((attr=attrs[i++])){ |
//ignore all attributes starting with _dj which are |
//internal temporary attributes used by the editor |
if(attr.name.substr(0,3) != '_dj' /*&& |
(attr.specified == undefined || attr.specified)*/){ |
var v = attr.value; |
if(attr.name == 'src' || attr.name == 'href'){ |
if(node.getAttribute('_djrealurl')){ |
v = node.getAttribute('_djrealurl'); |
} |
} |
attrarray.push([attr.name,v]); |
} |
} |
} |
attrarray.sort(function(a,b){ |
return a[0]<b[0]?-1:(a[0]==b[0]?0:1); |
}); |
i=0; |
while((attr=attrarray[i++])){ |
output += ' '+attr[0]+'="'+attr[1]+'"'; |
} |
if(node.childNodes.length){ |
output += '>' + this.getNodeChildrenHtml(node)+'</'+node.tagName.toLowerCase()+'>'; |
}else{ |
output += ' />'; |
} |
break; |
case 3: //text |
// FIXME: |
var output = this.escapeXml(node.nodeValue,true); |
break; |
case 8: //comment |
// FIXME: |
var output = '<!--'+this.escapeXml(node.nodeValue,true)+'-->'; |
break; |
default: |
var output = "Element not recognized - Type: " + node.nodeType + " Name: " + node.nodeName; |
} |
return output; |
}, |
|
getNodeChildrenHtml: function(/* DomNode */dom){ |
// summary: Returns the html content of a DomNode and children |
var out = ""; |
if(!dom){ return out; } |
var nodes = dom["childNodes"]||dom; |
var i=0; |
var node; |
while((node=nodes[i++])){ |
out += this.getNodeHtml(node); |
} |
return out; // String |
}, |
|
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; |
} |
} |
if(save){ |
this.textarea.value = this._content; |
}else{ |
this.textarea.value = 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 = this._content; |
}else{ |
this.domNode.innerHTML = 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); |
}, |
|
_fixContentForMoz: function(/* String */ html){ |
// summary: |
// Moz can not handle strong/em tags correctly, convert them to b/i |
html = html.replace(/<(\/)?strong([ \>])/gi, '<$1b$2' ); |
html = html.replace(/<(\/)?em([ \>])/gi, '<$1i$2' ); |
return html; // String |
}, |
|
_srcInImgRegex : /(?:(<img(?=\s).*?\ssrc=)("|')(.*?)\2)|(?:(<img\s.*?src=)([^"'][^ >]+))/gi , |
_hrefInARegex : /(?:(<a(?=\s).*?\shref=)("|')(.*?)\2)|(?:(<a\s.*?href=)([^"'][^ >]+))/gi , |
|
_preFixUrlAttributes: function(/* String */ html){ |
html = html.replace(this._hrefInARegex, '$1$4$2$3$5$2 _djrealurl=$2$3$5$2') ; |
html = html.replace(this._srcInImgRegex, '$1$4$2$3$5$2 _djrealurl=$2$3$5$2') ; |
return html; // String |
} |
}); |
|
} |