Page Menu
Home
Code
Search
Configure Global Search
Log In
Files
F947470
RichText.js
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
45 KB
Subscribers
None
RichText.js
View Options
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
}
});
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Apr 26, 12:01 (1 d, 21 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
24698
Default Alt Text
RichText.js (45 KB)
Attached To
rZEDHG ZedLegacy
Event Timeline
Log In to Comment