mirror of
https://git.tt-rss.org/git/tt-rss.git
synced 2025-12-19 04:21:30 +00:00
dojo: remove uncompressed files
This commit is contained in:
@@ -1,199 +0,0 @@
|
||||
define("dijit/_editor/plugins/AlwaysShowToolbar", [
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom-class", // domClass.add domClass.remove
|
||||
"dojo/dom-construct", // domConstruct.place
|
||||
"dojo/dom-geometry",
|
||||
"dojo/_base/lang", // lang.hitch
|
||||
"dojo/_base/sniff", // has("ie") has("opera")
|
||||
"dojo/_base/window", // win.body
|
||||
"../_Plugin"
|
||||
], function(declare, domClass, domConstruct, domGeometry, lang, has, win, _Plugin){
|
||||
|
||||
/*=====
|
||||
var _Plugin = dijit._editor._Plugin;
|
||||
=====*/
|
||||
|
||||
// module:
|
||||
// dijit/_editor/plugins/AlwaysShowToolbar
|
||||
// summary:
|
||||
// This plugin is required for Editors in auto-expand mode.
|
||||
// It handles the auto-expansion as the user adds/deletes text,
|
||||
// and keeps the editor's toolbar visible even when the top of the editor
|
||||
// has scrolled off the top of the viewport (usually when editing a long
|
||||
// document).
|
||||
|
||||
|
||||
return declare("dijit._editor.plugins.AlwaysShowToolbar", _Plugin, {
|
||||
// summary:
|
||||
// This plugin is required for Editors in auto-expand mode.
|
||||
// It handles the auto-expansion as the user adds/deletes text,
|
||||
// and keeps the editor's toolbar visible even when the top of the editor
|
||||
// has scrolled off the top of the viewport (usually when editing a long
|
||||
// document).
|
||||
// description:
|
||||
// Specify this in extraPlugins (or plugins) parameter and also set
|
||||
// height to "".
|
||||
// example:
|
||||
// | <div data-dojo-type="dijit.Editor" height=""
|
||||
// | data-dojo-props="extraPlugins: [dijit._editor.plugins.AlwaysShowToolbar]">
|
||||
|
||||
// _handleScroll: Boolean
|
||||
// Enables/disables the handler for scroll events
|
||||
_handleScroll: true,
|
||||
|
||||
setEditor: function(e){
|
||||
// Overrides _Plugin.setEditor().
|
||||
if(!e.iframe){
|
||||
console.log('Port AlwaysShowToolbar plugin to work with Editor without iframe');
|
||||
return;
|
||||
}
|
||||
|
||||
this.editor = e;
|
||||
|
||||
e.onLoadDeferred.addCallback(lang.hitch(this, this.enable));
|
||||
},
|
||||
|
||||
enable: function(d){
|
||||
// summary:
|
||||
// Enable plugin. Called when Editor has finished initializing.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
this._updateHeight();
|
||||
this.connect(window, 'onscroll', "globalOnScrollHandler");
|
||||
this.connect(this.editor, 'onNormalizedDisplayChanged', "_updateHeight");
|
||||
return d;
|
||||
},
|
||||
|
||||
_updateHeight: function(){
|
||||
// summary:
|
||||
// Updates the height of the editor area to fit the contents.
|
||||
var e = this.editor;
|
||||
if(!e.isLoaded){ return; }
|
||||
if(e.height){ return; }
|
||||
|
||||
var height = domGeometry.getMarginSize(e.editNode).h;
|
||||
if(has("opera")){
|
||||
height = e.editNode.scrollHeight;
|
||||
}
|
||||
// console.debug('height',height);
|
||||
// alert(this.editNode);
|
||||
|
||||
//height maybe zero in some cases even though the content is not empty,
|
||||
//we try the height of body instead
|
||||
if(!height){
|
||||
height = domGeometry.getMarginSize(e.document.body).h;
|
||||
}
|
||||
|
||||
if(height == 0){
|
||||
console.debug("Can not figure out the height of the editing area!");
|
||||
return; //prevent setting height to 0
|
||||
}
|
||||
if(has("ie") <= 7 && this.editor.minHeight){
|
||||
var min = parseInt(this.editor.minHeight);
|
||||
if(height < min){ height = min; }
|
||||
}
|
||||
if(height != this._lastHeight){
|
||||
this._lastHeight = height;
|
||||
// this.editorObject.style.height = this._lastHeight + "px";
|
||||
domGeometry.setMarginBox(e.iframe, { h: this._lastHeight });
|
||||
}
|
||||
},
|
||||
|
||||
// _lastHeight: Integer
|
||||
// Height in px of the editor at the last time we did sizing
|
||||
_lastHeight: 0,
|
||||
|
||||
globalOnScrollHandler: function(){
|
||||
// summary:
|
||||
// Handler for scroll events that bubbled up to <html>
|
||||
// tags:
|
||||
// private
|
||||
|
||||
var isIE6 = has("ie") < 7;
|
||||
if(!this._handleScroll){ return; }
|
||||
var tdn = this.editor.header;
|
||||
if(!this._scrollSetUp){
|
||||
this._scrollSetUp = true;
|
||||
this._scrollThreshold = domGeometry.position(tdn, true).y;
|
||||
// var db = win.body;
|
||||
// console.log("threshold:", this._scrollThreshold);
|
||||
//what's this for?? comment out for now
|
||||
// if((isIE6)&&(db)&&(domStyle.set or get TODO(db, "backgroundIimage")=="none")){
|
||||
// db.style.backgroundImage = "url(" + dojo.uri.moduleUri("dijit", "templates/blank.gif") + ")";
|
||||
// db.style.backgroundAttachment = "fixed";
|
||||
// }
|
||||
}
|
||||
|
||||
var scrollPos = domGeometry.docScroll().y;
|
||||
var s = tdn.style;
|
||||
|
||||
if(scrollPos > this._scrollThreshold && scrollPos < this._scrollThreshold+this._lastHeight){
|
||||
// dojo.debug(scrollPos);
|
||||
if(!this._fixEnabled){
|
||||
var tdnbox = domGeometry.getMarginSize(tdn);
|
||||
this.editor.iframe.style.marginTop = tdnbox.h+"px";
|
||||
|
||||
if(isIE6){
|
||||
s.left = domGeometry.position(tdn).x;
|
||||
if(tdn.previousSibling){
|
||||
this._IEOriginalPos = ['after',tdn.previousSibling];
|
||||
}else if(tdn.nextSibling){
|
||||
this._IEOriginalPos = ['before',tdn.nextSibling];
|
||||
}else{
|
||||
this._IEOriginalPos = ['last',tdn.parentNode];
|
||||
}
|
||||
win.body().appendChild(tdn);
|
||||
domClass.add(tdn,'dijitIEFixedToolbar');
|
||||
}else{
|
||||
s.position = "fixed";
|
||||
s.top = "0px";
|
||||
}
|
||||
|
||||
domGeometry.setMarginBox(tdn, { w: tdnbox.w });
|
||||
s.zIndex = 2000;
|
||||
this._fixEnabled = true;
|
||||
}
|
||||
// if we're showing the floating toolbar, make sure that if
|
||||
// we've scrolled past the bottom of the editor that we hide
|
||||
// the toolbar for this instance of the editor.
|
||||
|
||||
// TODO: when we get multiple editor toolbar support working
|
||||
// correctly, ensure that we check this against the scroll
|
||||
// position of the bottom-most editor instance.
|
||||
var eHeight = (this.height) ? parseInt(this.editor.height) : this.editor._lastHeight;
|
||||
s.display = (scrollPos > this._scrollThreshold+eHeight) ? "none" : "";
|
||||
}else if(this._fixEnabled){
|
||||
this.editor.iframe.style.marginTop = '';
|
||||
s.position = "";
|
||||
s.top = "";
|
||||
s.zIndex = "";
|
||||
s.display = "";
|
||||
if(isIE6){
|
||||
s.left = "";
|
||||
domClass.remove(tdn,'dijitIEFixedToolbar');
|
||||
if(this._IEOriginalPos){
|
||||
domConstruct.place(tdn, this._IEOriginalPos[1], this._IEOriginalPos[0]);
|
||||
this._IEOriginalPos = null;
|
||||
}else{
|
||||
domConstruct.place(tdn, this.editor.iframe, 'before');
|
||||
}
|
||||
}
|
||||
s.width = "";
|
||||
this._fixEnabled = false;
|
||||
}
|
||||
},
|
||||
|
||||
destroy: function(){
|
||||
// Overrides _Plugin.destroy(). TODO: call this.inherited() rather than repeating code.
|
||||
this._IEOriginalPos = null;
|
||||
this._handleScroll = false;
|
||||
this.inherited(arguments);
|
||||
|
||||
if(has("ie") < 7){
|
||||
domClass.remove(this.editor.header, 'dijitIEFixedToolbar');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1,638 +0,0 @@
|
||||
define("dijit/_editor/plugins/EnterKeyHandling", [
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom-construct", // domConstruct.destroy domConstruct.place
|
||||
"dojo/_base/event", // event.stop
|
||||
"dojo/keys", // keys.ENTER
|
||||
"dojo/_base/lang",
|
||||
"dojo/_base/sniff", // has("ie") has("mozilla") has("webkit")
|
||||
"dojo/_base/window", // win.global win.withGlobal
|
||||
"dojo/window", // winUtils.scrollIntoView
|
||||
"../_Plugin",
|
||||
"../RichText",
|
||||
"../range",
|
||||
"../selection"
|
||||
], function(declare, domConstruct, event, keys, lang, has, win, winUtils, _Plugin, RichText, rangeapi, selectionapi){
|
||||
|
||||
/*=====
|
||||
var _Plugin = dijit._editor._Plugin;
|
||||
=====*/
|
||||
|
||||
// module:
|
||||
// dijit/_editor/plugins/EnterKeyHandling
|
||||
// summary:
|
||||
// This plugin tries to make all browsers behave consistently with regard to
|
||||
// how ENTER behaves in the editor window. It traps the ENTER key and alters
|
||||
// the way DOM is constructed in certain cases to try to commonize the generated
|
||||
// DOM and behaviors across browsers.
|
||||
|
||||
|
||||
return declare("dijit._editor.plugins.EnterKeyHandling", _Plugin, {
|
||||
// summary:
|
||||
// This plugin tries to make all browsers behave consistently with regard to
|
||||
// how ENTER behaves in the editor window. It traps the ENTER key and alters
|
||||
// the way DOM is constructed in certain cases to try to commonize the generated
|
||||
// DOM and behaviors across browsers.
|
||||
//
|
||||
// description:
|
||||
// This plugin has three modes:
|
||||
//
|
||||
// * blockNodeForEnter=BR
|
||||
// * blockNodeForEnter=DIV
|
||||
// * blockNodeForEnter=P
|
||||
//
|
||||
// In blockNodeForEnter=P, the ENTER key starts a new
|
||||
// paragraph, and shift-ENTER starts a new line in the current paragraph.
|
||||
// For example, the input:
|
||||
//
|
||||
// | first paragraph <shift-ENTER>
|
||||
// | second line of first paragraph <ENTER>
|
||||
// | second paragraph
|
||||
//
|
||||
// will generate:
|
||||
//
|
||||
// | <p>
|
||||
// | first paragraph
|
||||
// | <br/>
|
||||
// | second line of first paragraph
|
||||
// | </p>
|
||||
// | <p>
|
||||
// | second paragraph
|
||||
// | </p>
|
||||
//
|
||||
// In BR and DIV mode, the ENTER key conceptually goes to a new line in the
|
||||
// current paragraph, and users conceptually create a new paragraph by pressing ENTER twice.
|
||||
// For example, if the user enters text into an editor like this:
|
||||
//
|
||||
// | one <ENTER>
|
||||
// | two <ENTER>
|
||||
// | three <ENTER>
|
||||
// | <ENTER>
|
||||
// | four <ENTER>
|
||||
// | five <ENTER>
|
||||
// | six <ENTER>
|
||||
//
|
||||
// It will appear on the screen as two 'paragraphs' of three lines each. Markupwise, this generates:
|
||||
//
|
||||
// BR:
|
||||
// | one<br/>
|
||||
// | two<br/>
|
||||
// | three<br/>
|
||||
// | <br/>
|
||||
// | four<br/>
|
||||
// | five<br/>
|
||||
// | six<br/>
|
||||
//
|
||||
// DIV:
|
||||
// | <div>one</div>
|
||||
// | <div>two</div>
|
||||
// | <div>three</div>
|
||||
// | <div> </div>
|
||||
// | <div>four</div>
|
||||
// | <div>five</div>
|
||||
// | <div>six</div>
|
||||
|
||||
// blockNodeForEnter: String
|
||||
// This property decides the behavior of Enter key. It can be either P,
|
||||
// DIV, BR, or empty (which means disable this feature). Anything else
|
||||
// will trigger errors. The default is 'BR'
|
||||
//
|
||||
// See class description for more details.
|
||||
blockNodeForEnter: 'BR',
|
||||
|
||||
constructor: function(args){
|
||||
if(args){
|
||||
if("blockNodeForEnter" in args){
|
||||
args.blockNodeForEnter = args.blockNodeForEnter.toUpperCase();
|
||||
}
|
||||
lang.mixin(this,args);
|
||||
}
|
||||
},
|
||||
|
||||
setEditor: function(editor){
|
||||
// Overrides _Plugin.setEditor().
|
||||
if(this.editor === editor){ return; }
|
||||
this.editor = editor;
|
||||
if(this.blockNodeForEnter == 'BR'){
|
||||
// While Moz has a mode tht mostly works, it's still a little different,
|
||||
// So, try to just have a common mode and be consistent. Which means
|
||||
// we need to enable customUndo, if not already enabled.
|
||||
this.editor.customUndo = true;
|
||||
editor.onLoadDeferred.then(lang.hitch(this,function(d){
|
||||
this.connect(editor.document, "onkeypress", function(e){
|
||||
if(e.charOrCode == keys.ENTER){
|
||||
// Just do it manually. The handleEnterKey has a shift mode that
|
||||
// Always acts like <br>, so just use it.
|
||||
var ne = lang.mixin({},e);
|
||||
ne.shiftKey = true;
|
||||
if(!this.handleEnterKey(ne)){
|
||||
event.stop(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
if(has("ie") == 9){
|
||||
this.connect(editor.document, "onpaste", function(e){
|
||||
setTimeout(dojo.hitch(this, function(){
|
||||
// Use the old range/selection code to kick IE 9 into updating
|
||||
// its range by moving it back, then forward, one 'character'.
|
||||
var r = this.editor.document.selection.createRange();
|
||||
r.move('character',-1);
|
||||
r.select();
|
||||
r.move('character',1);
|
||||
r.select();
|
||||
}),0);
|
||||
});
|
||||
}
|
||||
return d;
|
||||
}));
|
||||
}else if(this.blockNodeForEnter){
|
||||
// add enter key handler
|
||||
// FIXME: need to port to the new event code!!
|
||||
var h = lang.hitch(this,this.handleEnterKey);
|
||||
editor.addKeyHandler(13, 0, 0, h); //enter
|
||||
editor.addKeyHandler(13, 0, 1, h); //shift+enter
|
||||
this.connect(this.editor,'onKeyPressed','onKeyPressed');
|
||||
}
|
||||
},
|
||||
onKeyPressed: function(){
|
||||
// summary:
|
||||
// Handler for keypress events.
|
||||
// tags:
|
||||
// private
|
||||
if(this._checkListLater){
|
||||
if(win.withGlobal(this.editor.window, 'isCollapsed', dijit)){
|
||||
var liparent=win.withGlobal(this.editor.window, 'getAncestorElement', selectionapi, ['LI']);
|
||||
if(!liparent){
|
||||
// circulate the undo detection code by calling RichText::execCommand directly
|
||||
RichText.prototype.execCommand.call(this.editor, 'formatblock',this.blockNodeForEnter);
|
||||
// set the innerHTML of the new block node
|
||||
var block = win.withGlobal(this.editor.window, 'getAncestorElement', selectionapi, [this.blockNodeForEnter]);
|
||||
if(block){
|
||||
block.innerHTML=this.bogusHtmlContent;
|
||||
if(has("ie")){
|
||||
// move to the start by moving backwards one char
|
||||
var r = this.editor.document.selection.createRange();
|
||||
r.move('character',-1);
|
||||
r.select();
|
||||
}
|
||||
}else{
|
||||
console.error('onKeyPressed: Cannot find the new block node'); // FIXME
|
||||
}
|
||||
}else{
|
||||
if(has("mozilla")){
|
||||
if(liparent.parentNode.parentNode.nodeName == 'LI'){
|
||||
liparent=liparent.parentNode.parentNode;
|
||||
}
|
||||
}
|
||||
var fc=liparent.firstChild;
|
||||
if(fc && fc.nodeType == 1 && (fc.nodeName == 'UL' || fc.nodeName == 'OL')){
|
||||
liparent.insertBefore(fc.ownerDocument.createTextNode('\xA0'),fc);
|
||||
var newrange = rangeapi.create(this.editor.window);
|
||||
newrange.setStart(liparent.firstChild,0);
|
||||
var selection = rangeapi.getSelection(this.editor.window, true);
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(newrange);
|
||||
}
|
||||
}
|
||||
}
|
||||
this._checkListLater = false;
|
||||
}
|
||||
if(this._pressedEnterInBlock){
|
||||
// the new created is the original current P, so we have previousSibling below
|
||||
if(this._pressedEnterInBlock.previousSibling){
|
||||
this.removeTrailingBr(this._pressedEnterInBlock.previousSibling);
|
||||
}
|
||||
delete this._pressedEnterInBlock;
|
||||
}
|
||||
},
|
||||
|
||||
// bogusHtmlContent: [private] String
|
||||
// HTML to stick into a new empty block
|
||||
bogusHtmlContent: ' ', //
|
||||
|
||||
// blockNodes: [private] Regex
|
||||
// Regex for testing if a given tag is a block level (display:block) tag
|
||||
blockNodes: /^(?:P|H1|H2|H3|H4|H5|H6|LI)$/,
|
||||
|
||||
handleEnterKey: function(e){
|
||||
// summary:
|
||||
// Handler for enter key events when blockNodeForEnter is DIV or P.
|
||||
// description:
|
||||
// Manually handle enter key event to make the behavior consistent across
|
||||
// all supported browsers. See class description for details.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
var selection, range, newrange, startNode, endNode, brNode, doc=this.editor.document,br,rs,txt;
|
||||
if(e.shiftKey){ // shift+enter always generates <br>
|
||||
var parent = win.withGlobal(this.editor.window, "getParentElement", selectionapi);
|
||||
var header = rangeapi.getAncestor(parent,this.blockNodes);
|
||||
if(header){
|
||||
if(header.tagName == 'LI'){
|
||||
return true; // let browser handle
|
||||
}
|
||||
selection = rangeapi.getSelection(this.editor.window);
|
||||
range = selection.getRangeAt(0);
|
||||
if(!range.collapsed){
|
||||
range.deleteContents();
|
||||
selection = rangeapi.getSelection(this.editor.window);
|
||||
range = selection.getRangeAt(0);
|
||||
}
|
||||
if(rangeapi.atBeginningOfContainer(header, range.startContainer, range.startOffset)){
|
||||
br=doc.createElement('br');
|
||||
newrange = rangeapi.create(this.editor.window);
|
||||
header.insertBefore(br,header.firstChild);
|
||||
newrange.setStartAfter(br);
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(newrange);
|
||||
}else if(rangeapi.atEndOfContainer(header, range.startContainer, range.startOffset)){
|
||||
newrange = rangeapi.create(this.editor.window);
|
||||
br=doc.createElement('br');
|
||||
header.appendChild(br);
|
||||
header.appendChild(doc.createTextNode('\xA0'));
|
||||
newrange.setStart(header.lastChild,0);
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(newrange);
|
||||
}else{
|
||||
rs = range.startContainer;
|
||||
if(rs && rs.nodeType == 3){
|
||||
// Text node, we have to split it.
|
||||
txt = rs.nodeValue;
|
||||
win.withGlobal(this.editor.window, function(){
|
||||
startNode = doc.createTextNode(txt.substring(0, range.startOffset));
|
||||
endNode = doc.createTextNode(txt.substring(range.startOffset));
|
||||
brNode = doc.createElement("br");
|
||||
|
||||
if(endNode.nodeValue == "" && has("webkit")){
|
||||
endNode = doc.createTextNode('\xA0')
|
||||
}
|
||||
domConstruct.place(startNode, rs, "after");
|
||||
domConstruct.place(brNode, startNode, "after");
|
||||
domConstruct.place(endNode, brNode, "after");
|
||||
domConstruct.destroy(rs);
|
||||
newrange = rangeapi.create();
|
||||
newrange.setStart(endNode,0);
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(newrange);
|
||||
});
|
||||
return false;
|
||||
}
|
||||
return true; // let browser handle
|
||||
}
|
||||
}else{
|
||||
selection = rangeapi.getSelection(this.editor.window);
|
||||
if(selection.rangeCount){
|
||||
range = selection.getRangeAt(0);
|
||||
if(range && range.startContainer){
|
||||
if(!range.collapsed){
|
||||
range.deleteContents();
|
||||
selection = rangeapi.getSelection(this.editor.window);
|
||||
range = selection.getRangeAt(0);
|
||||
}
|
||||
rs = range.startContainer;
|
||||
if(rs && rs.nodeType == 3){
|
||||
// Text node, we have to split it.
|
||||
win.withGlobal(this.editor.window, lang.hitch(this, function(){
|
||||
var endEmpty = false;
|
||||
|
||||
var offset = range.startOffset;
|
||||
if(rs.length < offset){
|
||||
//We are not splitting the right node, try to locate the correct one
|
||||
ret = this._adjustNodeAndOffset(rs, offset);
|
||||
rs = ret.node;
|
||||
offset = ret.offset;
|
||||
}
|
||||
txt = rs.nodeValue;
|
||||
|
||||
startNode = doc.createTextNode(txt.substring(0, offset));
|
||||
endNode = doc.createTextNode(txt.substring(offset));
|
||||
brNode = doc.createElement("br");
|
||||
|
||||
if(!endNode.length){
|
||||
endNode = doc.createTextNode('\xA0');
|
||||
endEmpty = true;
|
||||
}
|
||||
|
||||
if(startNode.length){
|
||||
domConstruct.place(startNode, rs, "after");
|
||||
}else{
|
||||
startNode = rs;
|
||||
}
|
||||
domConstruct.place(brNode, startNode, "after");
|
||||
domConstruct.place(endNode, brNode, "after");
|
||||
domConstruct.destroy(rs);
|
||||
newrange = rangeapi.create();
|
||||
newrange.setStart(endNode,0);
|
||||
newrange.setEnd(endNode, endNode.length);
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(newrange);
|
||||
if(endEmpty && !has("webkit")){
|
||||
selectionapi.remove();
|
||||
}else{
|
||||
selectionapi.collapse(true);
|
||||
}
|
||||
}));
|
||||
}else{
|
||||
var targetNode;
|
||||
if(range.startOffset >= 0){
|
||||
targetNode = rs.childNodes[range.startOffset];
|
||||
}
|
||||
win.withGlobal(this.editor.window, lang.hitch(this, function(){
|
||||
var brNode = doc.createElement("br");
|
||||
var endNode = doc.createTextNode('\xA0');
|
||||
if(!targetNode){
|
||||
rs.appendChild(brNode);
|
||||
rs.appendChild(endNode);
|
||||
}else{
|
||||
domConstruct.place(brNode, targetNode, "before");
|
||||
domConstruct.place(endNode, brNode, "after");
|
||||
}
|
||||
newrange = rangeapi.create(win.global);
|
||||
newrange.setStart(endNode,0);
|
||||
newrange.setEnd(endNode, endNode.length);
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(newrange);
|
||||
selectionapi.collapse(true);
|
||||
}));
|
||||
}
|
||||
}
|
||||
}else{
|
||||
// don't change this: do not call this.execCommand, as that may have other logic in subclass
|
||||
RichText.prototype.execCommand.call(this.editor, 'inserthtml', '<br>');
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
var _letBrowserHandle = true;
|
||||
|
||||
// first remove selection
|
||||
selection = rangeapi.getSelection(this.editor.window);
|
||||
range = selection.getRangeAt(0);
|
||||
if(!range.collapsed){
|
||||
range.deleteContents();
|
||||
selection = rangeapi.getSelection(this.editor.window);
|
||||
range = selection.getRangeAt(0);
|
||||
}
|
||||
|
||||
var block = rangeapi.getBlockAncestor(range.endContainer, null, this.editor.editNode);
|
||||
var blockNode = block.blockNode;
|
||||
|
||||
// if this is under a LI or the parent of the blockNode is LI, just let browser to handle it
|
||||
if((this._checkListLater = (blockNode && (blockNode.nodeName == 'LI' || blockNode.parentNode.nodeName == 'LI')))){
|
||||
if(has("mozilla")){
|
||||
// press enter in middle of P may leave a trailing <br/>, let's remove it later
|
||||
this._pressedEnterInBlock = blockNode;
|
||||
}
|
||||
// if this li only contains spaces, set the content to empty so the browser will outdent this item
|
||||
if(/^(\s| | |\xA0|<span\b[^>]*\bclass=['"]Apple-style-span['"][^>]*>(\s| | |\xA0)<\/span>)?(<br>)?$/.test(blockNode.innerHTML)){
|
||||
// empty LI node
|
||||
blockNode.innerHTML = '';
|
||||
if(has("webkit")){ // WebKit tosses the range when innerHTML is reset
|
||||
newrange = rangeapi.create(this.editor.window);
|
||||
newrange.setStart(blockNode, 0);
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(newrange);
|
||||
}
|
||||
this._checkListLater = false; // nothing to check since the browser handles outdent
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// text node directly under body, let's wrap them in a node
|
||||
if(!block.blockNode || block.blockNode===this.editor.editNode){
|
||||
try{
|
||||
RichText.prototype.execCommand.call(this.editor, 'formatblock',this.blockNodeForEnter);
|
||||
}catch(e2){ /*squelch FF3 exception bug when editor content is a single BR*/ }
|
||||
// get the newly created block node
|
||||
// FIXME
|
||||
block = {blockNode:win.withGlobal(this.editor.window, "getAncestorElement", selectionapi, [this.blockNodeForEnter]),
|
||||
blockContainer: this.editor.editNode};
|
||||
if(block.blockNode){
|
||||
if(block.blockNode != this.editor.editNode &&
|
||||
(!(block.blockNode.textContent || block.blockNode.innerHTML).replace(/^\s+|\s+$/g, "").length)){
|
||||
this.removeTrailingBr(block.blockNode);
|
||||
return false;
|
||||
}
|
||||
}else{ // we shouldn't be here if formatblock worked
|
||||
block.blockNode = this.editor.editNode;
|
||||
}
|
||||
selection = rangeapi.getSelection(this.editor.window);
|
||||
range = selection.getRangeAt(0);
|
||||
}
|
||||
|
||||
var newblock = doc.createElement(this.blockNodeForEnter);
|
||||
newblock.innerHTML=this.bogusHtmlContent;
|
||||
this.removeTrailingBr(block.blockNode);
|
||||
var endOffset = range.endOffset;
|
||||
var node = range.endContainer;
|
||||
if(node.length < endOffset){
|
||||
//We are not checking the right node, try to locate the correct one
|
||||
var ret = this._adjustNodeAndOffset(node, endOffset);
|
||||
node = ret.node;
|
||||
endOffset = ret.offset;
|
||||
}
|
||||
if(rangeapi.atEndOfContainer(block.blockNode, node, endOffset)){
|
||||
if(block.blockNode === block.blockContainer){
|
||||
block.blockNode.appendChild(newblock);
|
||||
}else{
|
||||
domConstruct.place(newblock, block.blockNode, "after");
|
||||
}
|
||||
_letBrowserHandle = false;
|
||||
// lets move caret to the newly created block
|
||||
newrange = rangeapi.create(this.editor.window);
|
||||
newrange.setStart(newblock, 0);
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(newrange);
|
||||
if(this.editor.height){
|
||||
winUtils.scrollIntoView(newblock);
|
||||
}
|
||||
}else if(rangeapi.atBeginningOfContainer(block.blockNode,
|
||||
range.startContainer, range.startOffset)){
|
||||
domConstruct.place(newblock, block.blockNode, block.blockNode === block.blockContainer ? "first" : "before");
|
||||
if(newblock.nextSibling && this.editor.height){
|
||||
// position input caret - mostly WebKit needs this
|
||||
newrange = rangeapi.create(this.editor.window);
|
||||
newrange.setStart(newblock.nextSibling, 0);
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(newrange);
|
||||
// browser does not scroll the caret position into view, do it manually
|
||||
winUtils.scrollIntoView(newblock.nextSibling);
|
||||
}
|
||||
_letBrowserHandle = false;
|
||||
}else{ //press enter in the middle of P/DIV/Whatever/
|
||||
if(block.blockNode === block.blockContainer){
|
||||
block.blockNode.appendChild(newblock);
|
||||
}else{
|
||||
domConstruct.place(newblock, block.blockNode, "after");
|
||||
}
|
||||
_letBrowserHandle = false;
|
||||
|
||||
// Clone any block level styles.
|
||||
if(block.blockNode.style){
|
||||
if(newblock.style){
|
||||
if(block.blockNode.style.cssText){
|
||||
newblock.style.cssText = block.blockNode.style.cssText;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Okay, we probably have to split.
|
||||
rs = range.startContainer;
|
||||
var firstNodeMoved;
|
||||
if(rs && rs.nodeType == 3){
|
||||
// Text node, we have to split it.
|
||||
var nodeToMove, tNode;
|
||||
endOffset = range.endOffset;
|
||||
if(rs.length < endOffset){
|
||||
//We are not splitting the right node, try to locate the correct one
|
||||
ret = this._adjustNodeAndOffset(rs, endOffset);
|
||||
rs = ret.node;
|
||||
endOffset = ret.offset;
|
||||
}
|
||||
|
||||
txt = rs.nodeValue;
|
||||
startNode = doc.createTextNode(txt.substring(0, endOffset));
|
||||
endNode = doc.createTextNode(txt.substring(endOffset, txt.length));
|
||||
|
||||
// Place the split, then remove original nodes.
|
||||
domConstruct.place(startNode, rs, "before");
|
||||
domConstruct.place(endNode, rs, "after");
|
||||
domConstruct.destroy(rs);
|
||||
|
||||
// Okay, we split the text. Now we need to see if we're
|
||||
// parented to the block element we're splitting and if
|
||||
// not, we have to split all the way up. Ugh.
|
||||
var parentC = startNode.parentNode;
|
||||
while(parentC !== block.blockNode){
|
||||
var tg = parentC.tagName;
|
||||
var newTg = doc.createElement(tg);
|
||||
// Clone over any 'style' data.
|
||||
if(parentC.style){
|
||||
if(newTg.style){
|
||||
if(parentC.style.cssText){
|
||||
newTg.style.cssText = parentC.style.cssText;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If font also need to clone over any font data.
|
||||
if(parentC.tagName === "FONT"){
|
||||
if(parentC.color){
|
||||
newTg.color = parentC.color;
|
||||
}
|
||||
if(parentC.face){
|
||||
newTg.face = parentC.face;
|
||||
}
|
||||
if(parentC.size){ // this check was necessary on IE
|
||||
newTg.size = parentC.size;
|
||||
}
|
||||
}
|
||||
|
||||
nodeToMove = endNode;
|
||||
while(nodeToMove){
|
||||
tNode = nodeToMove.nextSibling;
|
||||
newTg.appendChild(nodeToMove);
|
||||
nodeToMove = tNode;
|
||||
}
|
||||
domConstruct.place(newTg, parentC, "after");
|
||||
startNode = parentC;
|
||||
endNode = newTg;
|
||||
parentC = parentC.parentNode;
|
||||
}
|
||||
|
||||
// Lastly, move the split out tags to the new block.
|
||||
// as they should now be split properly.
|
||||
nodeToMove = endNode;
|
||||
if(nodeToMove.nodeType == 1 || (nodeToMove.nodeType == 3 && nodeToMove.nodeValue)){
|
||||
// Non-blank text and non-text nodes need to clear out that blank space
|
||||
// before moving the contents.
|
||||
newblock.innerHTML = "";
|
||||
}
|
||||
firstNodeMoved = nodeToMove;
|
||||
while(nodeToMove){
|
||||
tNode = nodeToMove.nextSibling;
|
||||
newblock.appendChild(nodeToMove);
|
||||
nodeToMove = tNode;
|
||||
}
|
||||
}
|
||||
|
||||
//lets move caret to the newly created block
|
||||
newrange = rangeapi.create(this.editor.window);
|
||||
var nodeForCursor;
|
||||
var innerMostFirstNodeMoved = firstNodeMoved;
|
||||
if(this.blockNodeForEnter !== 'BR'){
|
||||
while(innerMostFirstNodeMoved){
|
||||
nodeForCursor = innerMostFirstNodeMoved;
|
||||
tNode = innerMostFirstNodeMoved.firstChild;
|
||||
innerMostFirstNodeMoved = tNode;
|
||||
}
|
||||
if(nodeForCursor && nodeForCursor.parentNode){
|
||||
newblock = nodeForCursor.parentNode;
|
||||
newrange.setStart(newblock, 0);
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(newrange);
|
||||
if(this.editor.height){
|
||||
winUtils.scrollIntoView(newblock);
|
||||
}
|
||||
if(has("mozilla")){
|
||||
// press enter in middle of P may leave a trailing <br/>, let's remove it later
|
||||
this._pressedEnterInBlock = block.blockNode;
|
||||
}
|
||||
}else{
|
||||
_letBrowserHandle = true;
|
||||
}
|
||||
}else{
|
||||
newrange.setStart(newblock, 0);
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(newrange);
|
||||
if(this.editor.height){
|
||||
winUtils.scrollIntoView(newblock);
|
||||
}
|
||||
if(has("mozilla")){
|
||||
// press enter in middle of P may leave a trailing <br/>, let's remove it later
|
||||
this._pressedEnterInBlock = block.blockNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
return _letBrowserHandle;
|
||||
},
|
||||
|
||||
_adjustNodeAndOffset: function(/*DomNode*/node, /*Int*/offset){
|
||||
// summary:
|
||||
// In the case there are multiple text nodes in a row the offset may not be within the node. If the offset is larger than the node length, it will attempt to find
|
||||
// the next text sibling until it locates the text node in which the offset refers to
|
||||
// node:
|
||||
// The node to check.
|
||||
// offset:
|
||||
// The position to find within the text node
|
||||
// tags:
|
||||
// private.
|
||||
while(node.length < offset && node.nextSibling && node.nextSibling.nodeType==3){
|
||||
//Adjust the offset and node in the case of multiple text nodes in a row
|
||||
offset = offset - node.length;
|
||||
node = node.nextSibling;
|
||||
}
|
||||
return {"node": node, "offset": offset};
|
||||
},
|
||||
|
||||
removeTrailingBr: function(container){
|
||||
// summary:
|
||||
// If last child of container is a <br>, then remove it.
|
||||
// tags:
|
||||
// private
|
||||
var para = /P|DIV|LI/i.test(container.tagName) ?
|
||||
container : selectionapi.getParentOfType(container,['P','DIV','LI']);
|
||||
|
||||
if(!para){ return; }
|
||||
if(para.lastChild){
|
||||
if((para.childNodes.length > 1 && para.lastChild.nodeType == 3 && /^[\s\xAD]*$/.test(para.lastChild.nodeValue)) ||
|
||||
para.lastChild.tagName=='BR'){
|
||||
|
||||
domConstruct.destroy(para.lastChild);
|
||||
}
|
||||
}
|
||||
if(!para.childNodes.length){
|
||||
para.innerHTML=this.bogusHtmlContent;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1,591 +0,0 @@
|
||||
define("dijit/_editor/plugins/FontChoice", [
|
||||
"dojo/_base/array", // array.indexOf array.map
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom-construct", // domConstruct.place
|
||||
"dojo/i18n", // i18n.getLocalization
|
||||
"dojo/_base/lang", // lang.delegate lang.hitch lang.isString
|
||||
"dojo/store/Memory", // MemoryStore
|
||||
"dojo/_base/window", // win.withGlobal
|
||||
"../../registry", // registry.getUniqueId
|
||||
"../../_Widget",
|
||||
"../../_TemplatedMixin",
|
||||
"../../_WidgetsInTemplateMixin",
|
||||
"../../form/FilteringSelect",
|
||||
"../_Plugin",
|
||||
"../range",
|
||||
"../selection",
|
||||
"dojo/i18n!../nls/FontChoice"
|
||||
], function(array, declare, domConstruct, i18n, lang, MemoryStore, win,
|
||||
registry, _Widget, _TemplatedMixin, _WidgetsInTemplateMixin, FilteringSelect, _Plugin, rangeapi, selectionapi){
|
||||
|
||||
/*=====
|
||||
var _Plugin = dijit._editor._Plugin;
|
||||
var _Widget = dijit._Widget;
|
||||
var _TemplatedMixin = dijit._TemplatedMixin;
|
||||
var _WidgetsInTemplateMixin = dijit._WidgetsInTemplateMixin;
|
||||
var FilteringSelect = dijit.form.FilteringSelect;
|
||||
=====*/
|
||||
|
||||
|
||||
// module:
|
||||
// dijit/_editor/plugins/FontChoice
|
||||
// summary:
|
||||
// fontchoice, fontsize, and formatblock editor plugins
|
||||
|
||||
|
||||
var _FontDropDown = declare("dijit._editor.plugins._FontDropDown",
|
||||
[_Widget, _TemplatedMixin, _WidgetsInTemplateMixin], {
|
||||
// summary:
|
||||
// Base class for widgets that contains a label (like "Font:")
|
||||
// and a FilteringSelect drop down to pick a value.
|
||||
// Used as Toolbar entry.
|
||||
|
||||
// label: [public] String
|
||||
// The label to apply to this particular FontDropDown.
|
||||
label: "",
|
||||
|
||||
// plainText: [public] boolean
|
||||
// Flag to indicate that the returned label should be plain text
|
||||
// instead of an example.
|
||||
plainText: false,
|
||||
|
||||
// templateString: [public] String
|
||||
// The template used to construct the labeled dropdown.
|
||||
templateString:
|
||||
"<span style='white-space: nowrap' class='dijit dijitReset dijitInline'>" +
|
||||
"<label class='dijitLeft dijitInline' for='${selectId}'>${label}</label>" +
|
||||
"<input data-dojo-type='dijit.form.FilteringSelect' required='false' " +
|
||||
"data-dojo-props='labelType:\"html\", labelAttr:\"label\", searchAttr:\"name\"' " +
|
||||
"tabIndex='-1' id='${selectId}' data-dojo-attach-point='select' value=''/>" +
|
||||
"</span>",
|
||||
|
||||
postMixInProperties: function(){
|
||||
// summary:
|
||||
// Over-ride to set specific properties.
|
||||
this.inherited(arguments);
|
||||
|
||||
this.strings = i18n.getLocalization("dijit._editor", "FontChoice");
|
||||
|
||||
// Set some substitution variables used in the template
|
||||
this.label = this.strings[this.command];
|
||||
this.id = registry.getUniqueId(this.declaredClass.replace(/\./g,"_")); // TODO: unneeded??
|
||||
this.selectId = this.id + "_select"; // used in template
|
||||
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
postCreate: function(){
|
||||
// summary:
|
||||
// Over-ride for the default postCreate action
|
||||
// This establishes the filtering selects and the like.
|
||||
|
||||
// Initialize the list of items in the drop down by creating data store with items like:
|
||||
// {value: 1, name: "xx-small", label: "<font size=1>xx-small</font-size>" }
|
||||
this.select.set("store", new MemoryStore({
|
||||
idProperty: "value",
|
||||
data: array.map(this.values, function(value){
|
||||
var name = this.strings[value] || value;
|
||||
return {
|
||||
label: this.getLabel(value, name),
|
||||
name: name,
|
||||
value: value
|
||||
};
|
||||
}, this)
|
||||
}));
|
||||
|
||||
this.select.set("value", "", false);
|
||||
this.disabled = this.select.get("disabled");
|
||||
},
|
||||
|
||||
_setValueAttr: function(value, priorityChange){
|
||||
// summary:
|
||||
// Over-ride for the default action of setting the
|
||||
// widget value, maps the input to known values
|
||||
// value: Object|String
|
||||
// The value to set in the select.
|
||||
// priorityChange:
|
||||
// Optional parameter used to tell the select whether or not to fire
|
||||
// onChange event.
|
||||
|
||||
// if the value is not a permitted value, just set empty string to prevent showing the warning icon
|
||||
priorityChange = priorityChange !== false;
|
||||
this.select.set('value', array.indexOf(this.values,value) < 0 ? "" : value, priorityChange);
|
||||
if(!priorityChange){
|
||||
// Clear the last state in case of updateState calls. Ref: #10466
|
||||
this.select._lastValueReported=null;
|
||||
}
|
||||
},
|
||||
|
||||
_getValueAttr: function(){
|
||||
// summary:
|
||||
// Allow retrieving the value from the composite select on
|
||||
// call to button.get("value");
|
||||
return this.select.get('value');
|
||||
},
|
||||
|
||||
focus: function(){
|
||||
// summary:
|
||||
// Over-ride for focus control of this widget. Delegates focus down to the
|
||||
// filtering select.
|
||||
this.select.focus();
|
||||
},
|
||||
|
||||
_setDisabledAttr: function(value){
|
||||
// summary:
|
||||
// Over-ride for the button's 'disabled' attribute so that it can be
|
||||
// disabled programmatically.
|
||||
|
||||
// Save off ths disabled state so the get retrieves it correctly
|
||||
//without needing to have a function proxy it.
|
||||
this.disabled = value;
|
||||
this.select.set("disabled", value);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
var _FontNameDropDown = declare("dijit._editor.plugins._FontNameDropDown", _FontDropDown, {
|
||||
// summary:
|
||||
// Dropdown to select a font; goes in editor toolbar.
|
||||
|
||||
// generic: Boolean
|
||||
// Use generic (web standard) font names
|
||||
generic: false,
|
||||
|
||||
// command: [public] String
|
||||
// The editor 'command' implemented by this plugin.
|
||||
command: "fontName",
|
||||
|
||||
postMixInProperties: function(){
|
||||
// summary:
|
||||
// Over-ride for the default posr mixin control
|
||||
if(!this.values){
|
||||
this.values = this.generic ?
|
||||
["serif", "sans-serif", "monospace", "cursive", "fantasy"] : // CSS font-family generics
|
||||
["Arial", "Times New Roman", "Comic Sans MS", "Courier New"];
|
||||
}
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
getLabel: function(value, name){
|
||||
// summary:
|
||||
// Function used to generate the labels of the format dropdown
|
||||
// will return a formatted, or plain label based on the value
|
||||
// of the plainText option.
|
||||
// value: String
|
||||
// The 'insert value' associated with a name
|
||||
// name: String
|
||||
// The text name of the value
|
||||
if(this.plainText){
|
||||
return name;
|
||||
}else{
|
||||
return "<div style='font-family: "+value+"'>" + name + "</div>";
|
||||
}
|
||||
},
|
||||
|
||||
_setValueAttr: function(value, priorityChange){
|
||||
// summary:
|
||||
// Over-ride for the default action of setting the
|
||||
// widget value, maps the input to known values
|
||||
|
||||
priorityChange = priorityChange !== false;
|
||||
if(this.generic){
|
||||
var map = {
|
||||
"Arial": "sans-serif",
|
||||
"Helvetica": "sans-serif",
|
||||
"Myriad": "sans-serif",
|
||||
"Times": "serif",
|
||||
"Times New Roman": "serif",
|
||||
"Comic Sans MS": "cursive",
|
||||
"Apple Chancery": "cursive",
|
||||
"Courier": "monospace",
|
||||
"Courier New": "monospace",
|
||||
"Papyrus": "fantasy",
|
||||
"Estrangelo Edessa": "cursive", // Windows 7
|
||||
"Gabriola": "fantasy" // Windows 7
|
||||
};
|
||||
value = map[value] || value;
|
||||
}
|
||||
this.inherited(arguments, [value, priorityChange]);
|
||||
}
|
||||
});
|
||||
|
||||
var _FontSizeDropDown = declare("dijit._editor.plugins._FontSizeDropDown", _FontDropDown, {
|
||||
// summary:
|
||||
// Dropdown to select a font size; goes in editor toolbar.
|
||||
|
||||
// command: [public] String
|
||||
// The editor 'command' implemented by this plugin.
|
||||
command: "fontSize",
|
||||
|
||||
// values: [public] Number[]
|
||||
// The HTML font size values supported by this plugin
|
||||
values: [1,2,3,4,5,6,7], // sizes according to the old HTML FONT SIZE
|
||||
|
||||
getLabel: function(value, name){
|
||||
// summary:
|
||||
// Function used to generate the labels of the format dropdown
|
||||
// will return a formatted, or plain label based on the value
|
||||
// of the plainText option.
|
||||
// We're stuck using the deprecated FONT tag to correspond
|
||||
// with the size measurements used by the editor
|
||||
// value: String
|
||||
// The 'insert value' associated with a name
|
||||
// name: String
|
||||
// The text name of the value
|
||||
if(this.plainText){
|
||||
return name;
|
||||
}else{
|
||||
return "<font size=" + value + "'>" + name + "</font>";
|
||||
}
|
||||
},
|
||||
|
||||
_setValueAttr: function(value, priorityChange){
|
||||
// summary:
|
||||
// Over-ride for the default action of setting the
|
||||
// widget value, maps the input to known values
|
||||
priorityChange = priorityChange !== false;
|
||||
if(value.indexOf && value.indexOf("px") != -1){
|
||||
var pixels = parseInt(value, 10);
|
||||
value = {10:1, 13:2, 16:3, 18:4, 24:5, 32:6, 48:7}[pixels] || value;
|
||||
}
|
||||
|
||||
this.inherited(arguments, [value, priorityChange]);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
var _FormatBlockDropDown = declare("dijit._editor.plugins._FormatBlockDropDown", _FontDropDown, {
|
||||
// summary:
|
||||
// Dropdown to select a format (like paragraph or heading); goes in editor toolbar.
|
||||
|
||||
// command: [public] String
|
||||
// The editor 'command' implemented by this plugin.
|
||||
command: "formatBlock",
|
||||
|
||||
// values: [public] Array
|
||||
// The HTML format tags supported by this plugin
|
||||
values: ["noFormat", "p", "h1", "h2", "h3", "pre"],
|
||||
|
||||
postCreate: function(){
|
||||
// Init and set the default value to no formatting. Update state will adjust it
|
||||
// as needed.
|
||||
this.inherited(arguments);
|
||||
this.set("value", "noFormat", false);
|
||||
},
|
||||
|
||||
getLabel: function(value, name){
|
||||
// summary:
|
||||
// Function used to generate the labels of the format dropdown
|
||||
// will return a formatted, or plain label based on the value
|
||||
// of the plainText option.
|
||||
// value: String
|
||||
// The 'insert value' associated with a name
|
||||
// name: String
|
||||
// The text name of the value
|
||||
if(this.plainText || value == "noFormat"){
|
||||
return name;
|
||||
}else{
|
||||
return "<" + value + ">" + name + "</" + value + ">";
|
||||
}
|
||||
},
|
||||
|
||||
_execCommand: function(editor, command, choice){
|
||||
// summary:
|
||||
// Over-ride for default exec-command label.
|
||||
// Allows us to treat 'none' as special.
|
||||
if(choice === "noFormat"){
|
||||
var start;
|
||||
var end;
|
||||
var sel = rangeapi.getSelection(editor.window);
|
||||
if(sel && sel.rangeCount > 0){
|
||||
var range = sel.getRangeAt(0);
|
||||
var node, tag;
|
||||
if(range){
|
||||
start = range.startContainer;
|
||||
end = range.endContainer;
|
||||
|
||||
// find containing nodes of start/end.
|
||||
while(start && start !== editor.editNode &&
|
||||
start !== editor.document.body &&
|
||||
start.nodeType !== 1){
|
||||
start = start.parentNode;
|
||||
}
|
||||
|
||||
while(end && end !== editor.editNode &&
|
||||
end !== editor.document.body &&
|
||||
end.nodeType !== 1){
|
||||
end = end.parentNode;
|
||||
}
|
||||
|
||||
var processChildren = lang.hitch(this, function(node, ary){
|
||||
if(node.childNodes && node.childNodes.length){
|
||||
var i;
|
||||
for(i = 0; i < node.childNodes.length; i++){
|
||||
var c = node.childNodes[i];
|
||||
if(c.nodeType == 1){
|
||||
if(win.withGlobal(editor.window, "inSelection", selectionapi, [c])){
|
||||
var tag = c.tagName? c.tagName.toLowerCase(): "";
|
||||
if(array.indexOf(this.values, tag) !== -1){
|
||||
ary.push(c);
|
||||
}
|
||||
processChildren(c, ary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var unformatNodes = lang.hitch(this, function(nodes){
|
||||
// summary:
|
||||
// Internal function to clear format nodes.
|
||||
// nodes:
|
||||
// The array of nodes to strip formatting from.
|
||||
if(nodes && nodes.length){
|
||||
editor.beginEditing();
|
||||
while(nodes.length){
|
||||
this._removeFormat(editor, nodes.pop());
|
||||
}
|
||||
editor.endEditing();
|
||||
}
|
||||
});
|
||||
|
||||
var clearNodes = [];
|
||||
if(start == end){
|
||||
//Contained within the same block, may be collapsed, but who cares, see if we
|
||||
// have a block element to remove.
|
||||
var block;
|
||||
node = start;
|
||||
while(node && node !== editor.editNode && node !== editor.document.body){
|
||||
if(node.nodeType == 1){
|
||||
tag = node.tagName? node.tagName.toLowerCase(): "";
|
||||
if(array.indexOf(this.values, tag) !== -1){
|
||||
block = node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
node = node.parentNode;
|
||||
}
|
||||
|
||||
//Also look for all child nodes in the selection that may need to be
|
||||
//cleared of formatting
|
||||
processChildren(start, clearNodes);
|
||||
if(block){ clearNodes = [block].concat(clearNodes); }
|
||||
unformatNodes(clearNodes);
|
||||
}else{
|
||||
// Probably a multi select, so we have to process it. Whee.
|
||||
node = start;
|
||||
while(win.withGlobal(editor.window, "inSelection", selectionapi, [node])){
|
||||
if(node.nodeType == 1){
|
||||
tag = node.tagName? node.tagName.toLowerCase(): "";
|
||||
if(array.indexOf(this.values, tag) !== -1){
|
||||
clearNodes.push(node);
|
||||
}
|
||||
processChildren(node,clearNodes);
|
||||
}
|
||||
node = node.nextSibling;
|
||||
}
|
||||
unformatNodes(clearNodes);
|
||||
}
|
||||
editor.onDisplayChanged();
|
||||
}
|
||||
}
|
||||
}else{
|
||||
editor.execCommand(command, choice);
|
||||
}
|
||||
},
|
||||
|
||||
_removeFormat: function(editor, node){
|
||||
// summary:
|
||||
// function to remove the block format node.
|
||||
// node:
|
||||
// The block format node to remove (and leave the contents behind)
|
||||
if(editor.customUndo){
|
||||
// So of course IE doesn't work right with paste-overs.
|
||||
// We have to do this manually, which is okay since IE already uses
|
||||
// customUndo and we turned it on for WebKit. WebKit pasted funny,
|
||||
// so couldn't use the execCommand approach
|
||||
while(node.firstChild){
|
||||
domConstruct.place(node.firstChild, node, "before");
|
||||
}
|
||||
node.parentNode.removeChild(node);
|
||||
}else{
|
||||
// Everyone else works fine this way, a paste-over and is native
|
||||
// undo friendly.
|
||||
win.withGlobal(editor.window,
|
||||
"selectElementChildren", selectionapi, [node]);
|
||||
var html = win.withGlobal(editor.window,
|
||||
"getSelectedHtml", selectionapi, [null]);
|
||||
win.withGlobal(editor.window,
|
||||
"selectElement", selectionapi, [node]);
|
||||
editor.execCommand("inserthtml", html||"");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// TODO: for 2.0, split into FontChoice plugin into three separate classes,
|
||||
// one for each command (and change registry below)
|
||||
var FontChoice = declare("dijit._editor.plugins.FontChoice", _Plugin,{
|
||||
// summary:
|
||||
// This plugin provides three drop downs for setting style in the editor
|
||||
// (font, font size, and format block), as controlled by command.
|
||||
//
|
||||
// description:
|
||||
// The commands provided by this plugin are:
|
||||
//
|
||||
// * fontName
|
||||
// | Provides a drop down to select from a list of font names
|
||||
// * fontSize
|
||||
// | Provides a drop down to select from a list of font sizes
|
||||
// * formatBlock
|
||||
// | Provides a drop down to select from a list of block styles
|
||||
// |
|
||||
//
|
||||
// which can easily be added to an editor by including one or more of the above commands
|
||||
// in the `plugins` attribute as follows:
|
||||
//
|
||||
// | plugins="['fontName','fontSize',...]"
|
||||
//
|
||||
// It is possible to override the default dropdown list by providing an Array for the `custom` property when
|
||||
// instantiating this plugin, e.g.
|
||||
//
|
||||
// | plugins="[{name:'dijit._editor.plugins.FontChoice', command:'fontName', custom:['Verdana','Myriad','Garamond']},...]"
|
||||
//
|
||||
// Alternatively, for `fontName` only, `generic:true` may be specified to provide a dropdown with
|
||||
// [CSS generic font families](http://www.w3.org/TR/REC-CSS2/fonts.html#generic-font-families)
|
||||
//
|
||||
// Note that the editor is often unable to properly handle font styling information defined outside
|
||||
// the context of the current editor instance, such as pre-populated HTML.
|
||||
|
||||
// useDefaultCommand: [protected] Boolean
|
||||
// Override _Plugin.useDefaultCommand...
|
||||
// processing is handled by this plugin, not by dijit.Editor.
|
||||
useDefaultCommand: false,
|
||||
|
||||
_initButton: function(){
|
||||
// summary:
|
||||
// Overrides _Plugin._initButton(), to initialize the FilteringSelect+label in toolbar,
|
||||
// rather than a simple button.
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
// Create the widget to go into the toolbar (the so-called "button")
|
||||
var clazz = {
|
||||
fontName: _FontNameDropDown,
|
||||
fontSize: _FontSizeDropDown,
|
||||
formatBlock: _FormatBlockDropDown
|
||||
}[this.command],
|
||||
params = this.params;
|
||||
|
||||
// For back-compat reasons support setting custom values via "custom" parameter
|
||||
// rather than "values" parameter
|
||||
if(this.params.custom){
|
||||
params.values = this.params.custom;
|
||||
}
|
||||
|
||||
var editor = this.editor;
|
||||
this.button = new clazz(lang.delegate({dir: editor.dir, lang: editor.lang}, params));
|
||||
|
||||
// Reflect changes to the drop down in the editor
|
||||
this.connect(this.button.select, "onChange", function(choice){
|
||||
// User invoked change, since all internal updates set priorityChange to false and will
|
||||
// not trigger an onChange event.
|
||||
this.editor.focus();
|
||||
|
||||
if(this.command == "fontName" && choice.indexOf(" ") != -1){ choice = "'" + choice + "'"; }
|
||||
|
||||
// Invoke, the editor already normalizes commands called through its
|
||||
// execCommand.
|
||||
if(this.button._execCommand){
|
||||
this.button._execCommand(this.editor, this.command, choice);
|
||||
}else{
|
||||
this.editor.execCommand(this.command, choice);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
updateState: function(){
|
||||
// summary:
|
||||
// Overrides _Plugin.updateState(). This controls updating the menu
|
||||
// options to the right values on state changes in the document (that trigger a
|
||||
// test of the actions.)
|
||||
// It set value of drop down in toolbar to reflect font/font size/format block
|
||||
// of text at current caret position.
|
||||
// tags:
|
||||
// protected
|
||||
var _e = this.editor;
|
||||
var _c = this.command;
|
||||
if(!_e || !_e.isLoaded || !_c.length){ return; }
|
||||
|
||||
if(this.button){
|
||||
var disabled = this.get("disabled");
|
||||
this.button.set("disabled", disabled);
|
||||
if(disabled){ return; }
|
||||
var value;
|
||||
try{
|
||||
value = _e.queryCommandValue(_c) || "";
|
||||
}catch(e){
|
||||
//Firefox may throw error above if the editor is just loaded, ignore it
|
||||
value = "";
|
||||
}
|
||||
|
||||
// strip off single quotes, if any
|
||||
var quoted = lang.isString(value) && value.match(/'([^']*)'/);
|
||||
if(quoted){ value = quoted[1]; }
|
||||
|
||||
if(_c === "formatBlock"){
|
||||
if(!value || value == "p"){
|
||||
// Some browsers (WebKit) doesn't actually get the tag info right.
|
||||
// and IE returns paragraph when in a DIV!, so incorrect a lot,
|
||||
// so we have double-check it.
|
||||
value = null;
|
||||
var elem;
|
||||
// Try to find the current element where the caret is.
|
||||
var sel = rangeapi.getSelection(this.editor.window);
|
||||
if(sel && sel.rangeCount > 0){
|
||||
var range = sel.getRangeAt(0);
|
||||
if(range){
|
||||
elem = range.endContainer;
|
||||
}
|
||||
}
|
||||
|
||||
// Okay, now see if we can find one of the formatting types we're in.
|
||||
while(elem && elem !== _e.editNode && elem !== _e.document){
|
||||
var tg = elem.tagName?elem.tagName.toLowerCase():"";
|
||||
if(tg && array.indexOf(this.button.values, tg) > -1){
|
||||
value = tg;
|
||||
break;
|
||||
}
|
||||
elem = elem.parentNode;
|
||||
}
|
||||
if(!value){
|
||||
// Still no value, so lets select 'none'.
|
||||
value = "noFormat";
|
||||
}
|
||||
}else{
|
||||
// Check that the block format is one allowed, if not,
|
||||
// null it so that it gets set to empty.
|
||||
if(array.indexOf(this.button.values, value) < 0){
|
||||
value = "noFormat";
|
||||
}
|
||||
}
|
||||
}
|
||||
if(value !== this.button.get("value")){
|
||||
// Set the value, but denote it is not a priority change, so no
|
||||
// onchange fires.
|
||||
this.button.set('value', value, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Register these plugins
|
||||
array.forEach(["fontName", "fontSize", "formatBlock"], function(name){
|
||||
_Plugin.registry[name] = function(args){
|
||||
return new FontChoice({
|
||||
command: name,
|
||||
plainText: args.plainText
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1,457 +0,0 @@
|
||||
define("dijit/_editor/plugins/FullScreen", [
|
||||
"dojo/aspect",
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom-class", // domClass.add domClass.remove
|
||||
"dojo/dom-geometry",
|
||||
"dojo/dom-style",
|
||||
"dojo/_base/event", // event.stop
|
||||
"dojo/i18n", // i18n.getLocalization
|
||||
"dojo/keys", // keys.F11 keys.TAB
|
||||
"dojo/_base/lang", // lang.hitch
|
||||
"dojo/on", // on()
|
||||
"dojo/_base/sniff", // has("ie"), has("quirks")
|
||||
"dojo/_base/window", // win.body
|
||||
"dojo/window", // winUtils.getBox winUtils.scrollIntoView
|
||||
"../../focus", // focus.focus(), focus.curNode
|
||||
"../_Plugin",
|
||||
"../../form/ToggleButton",
|
||||
"../../registry", // registry.getEnclosingWidget()
|
||||
"dojo/i18n!../nls/commands"
|
||||
], function(aspect, declare, domClass, domGeometry, domStyle, event, i18n, keys, lang, on, has, win, winUtils,
|
||||
focus, _Plugin, ToggleButton, registry){
|
||||
|
||||
/*=====
|
||||
var _Plugin = dijit._editor._Plugin;
|
||||
=====*/
|
||||
|
||||
|
||||
// module:
|
||||
// dijit/_editor/plugins/FullScreen
|
||||
// summary:
|
||||
// This plugin provides FullScreen capability to the editor. When
|
||||
// toggled on, it will render the editor into the full window and
|
||||
// overlay everything. It also binds to the hotkey: CTRL-SHIFT-F11
|
||||
// for toggling fullscreen mode.
|
||||
|
||||
|
||||
var FullScreen = declare("dijit._editor.plugins.FullScreen",_Plugin,{
|
||||
// summary:
|
||||
// This plugin provides FullScreen capability to the editor. When
|
||||
// toggled on, it will render the editor into the full window and
|
||||
// overlay everything. It also binds to the hotkey: CTRL-SHIFT-F11
|
||||
// for toggling fullscreen mode.
|
||||
|
||||
// zIndex: [public] Number
|
||||
// zIndex value used for overlaying the full page.
|
||||
// default is 500.
|
||||
zIndex: 500,
|
||||
|
||||
// _origState: [private] Object
|
||||
// The original view state of the editor.
|
||||
_origState: null,
|
||||
|
||||
// _origiFrameState: [private] Object
|
||||
// The original view state of the iframe of the editor.
|
||||
_origiFrameState: null,
|
||||
|
||||
// _resizeHandle: [private] Object
|
||||
// Connection point used for handling resize when window resizes.
|
||||
_resizeHandle: null,
|
||||
|
||||
// isFullscreen: [const] boolean
|
||||
// Read-Only variable used to denote of the editor is in fullscreen mode or not.
|
||||
isFullscreen: false,
|
||||
|
||||
toggle: function(){
|
||||
// summary:
|
||||
// Function to allow programmatic toggling of the view.
|
||||
this.button.set("checked", !this.button.get("checked"));
|
||||
},
|
||||
|
||||
_initButton: function(){
|
||||
// summary:
|
||||
// Over-ride for creation of the resize button.
|
||||
var strings = i18n.getLocalization("dijit._editor", "commands"),
|
||||
editor = this.editor;
|
||||
this.button = new ToggleButton({
|
||||
label: strings["fullScreen"],
|
||||
dir: editor.dir,
|
||||
lang: editor.lang,
|
||||
showLabel: false,
|
||||
iconClass: this.iconClassPrefix + " " + this.iconClassPrefix + "FullScreen",
|
||||
tabIndex: "-1",
|
||||
onChange: lang.hitch(this, "_setFullScreen")
|
||||
});
|
||||
},
|
||||
|
||||
setEditor: function(editor){
|
||||
// summary:
|
||||
// Over-ride for the setting of the editor.
|
||||
// editor: Object
|
||||
// The editor to configure for this plugin to use.
|
||||
this.editor = editor;
|
||||
this._initButton();
|
||||
|
||||
this.editor.addKeyHandler(keys.F11, true, true, lang.hitch(this, function(e){
|
||||
// Enable the CTRL-SHIFT-F11 hotkey for fullscreen mode.
|
||||
this.toggle();
|
||||
event.stop(e);
|
||||
setTimeout(lang.hitch(this, function(){this.editor.focus();}), 250);
|
||||
return true;
|
||||
}));
|
||||
this.connect(this.editor.domNode, "onkeydown", "_containFocus");
|
||||
},
|
||||
|
||||
_containFocus: function(e){
|
||||
// summary:
|
||||
// When in Full Screen mode, it's good to try and retain focus in the editor
|
||||
// so this function is intended to try and constrain the TAB key.
|
||||
// e: Event
|
||||
// The key event.
|
||||
// tags:
|
||||
// private
|
||||
if(this.isFullscreen){
|
||||
var ed = this.editor;
|
||||
if(!ed.isTabIndent &&
|
||||
ed._fullscreen_oldOnKeyDown &&
|
||||
e.keyCode === keys.TAB){
|
||||
// If we're in fullscreen mode, we want to take over how tab moves focus a bit.
|
||||
// to keep it within the editor since it's hiding the rest of the page.
|
||||
// IE hates changing focus IN the event handler, so need to put calls
|
||||
// in a timeout. Gotta love IE.
|
||||
// Also need to check for alternate view nodes if present and active.
|
||||
var f = focus.curNode;
|
||||
var avn = this._getAltViewNode();
|
||||
if(f == ed.iframe ||
|
||||
(avn && f === avn)){
|
||||
setTimeout(lang.hitch(this, function(){
|
||||
ed.toolbar.focus();
|
||||
}), 10);
|
||||
}else{
|
||||
if(avn && domStyle.get(ed.iframe, "display") === "none"){
|
||||
setTimeout(lang.hitch(this, function(){
|
||||
focus.focus(avn);
|
||||
}), 10);
|
||||
}else{
|
||||
setTimeout(lang.hitch(this, function(){
|
||||
ed.focus();
|
||||
}), 10);
|
||||
}
|
||||
}
|
||||
event.stop(e);
|
||||
}else if(ed._fullscreen_oldOnKeyDown){
|
||||
// Only call up when it's a different function. Traps corner case event issue
|
||||
// on IE which caused stack overflow on handler cleanup.
|
||||
ed._fullscreen_oldOnKeyDown(e);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_resizeEditor: function(){
|
||||
// summary:
|
||||
// Function to handle resizing the editor as the viewport
|
||||
// resizes (window scaled)
|
||||
// tags:
|
||||
// private
|
||||
var vp = winUtils.getBox();
|
||||
domGeometry.setMarginBox(this.editor.domNode, {
|
||||
w: vp.w,
|
||||
h: vp.h
|
||||
});
|
||||
|
||||
//Adjust the internal heights too, as they can be a bit off.
|
||||
var hHeight = this.editor.getHeaderHeight();
|
||||
var fHeight = this.editor.getFooterHeight();
|
||||
var extents = domGeometry.getPadBorderExtents(this.editor.domNode);
|
||||
var fcpExtents = domGeometry.getPadBorderExtents(this.editor.iframe.parentNode);
|
||||
var fcmExtents = domGeometry.getMarginExtents(this.editor.iframe.parentNode);
|
||||
|
||||
var cHeight = vp.h - (hHeight + extents.h + fHeight);
|
||||
domGeometry.setMarginBox(this.editor.iframe.parentNode, {
|
||||
h: cHeight,
|
||||
w: vp.w
|
||||
});
|
||||
domGeometry.setMarginBox(this.editor.iframe, {
|
||||
h: cHeight - (fcpExtents.h + fcmExtents.h)
|
||||
});
|
||||
},
|
||||
|
||||
_getAltViewNode: function(){
|
||||
// summary:
|
||||
// This function is intended as a hook point for setting an
|
||||
// alternate view node for when in full screen mode and the
|
||||
// editable iframe is hidden.
|
||||
// tags:
|
||||
// protected.
|
||||
},
|
||||
|
||||
_setFullScreen: function(full){
|
||||
// summary:
|
||||
// Function to handle toggling between full screen and
|
||||
// regular view.
|
||||
// tags:
|
||||
// private
|
||||
var vp = winUtils.getBox();
|
||||
|
||||
//Alias this for shorter code.
|
||||
var ed = this.editor;
|
||||
var body = win.body();
|
||||
var editorParent = ed.domNode.parentNode;
|
||||
|
||||
this.isFullscreen = full;
|
||||
|
||||
if(full){
|
||||
//Parent classes can royally screw up this plugin, so we
|
||||
//have to set everything to position static.
|
||||
while(editorParent && editorParent !== win.body()){
|
||||
domClass.add(editorParent, "dijitForceStatic");
|
||||
editorParent = editorParent.parentNode;
|
||||
}
|
||||
|
||||
// Save off the resize function. We want to kill its behavior.
|
||||
this._editorResizeHolder = this.editor.resize;
|
||||
ed.resize = function(){} ;
|
||||
|
||||
// Try to constrain focus control.
|
||||
ed._fullscreen_oldOnKeyDown = ed.onKeyDown;
|
||||
ed.onKeyDown = lang.hitch(this, this._containFocus);
|
||||
|
||||
this._origState = {};
|
||||
this._origiFrameState = {};
|
||||
|
||||
// Store the basic editor state we have to restore later.
|
||||
// Not using domStyle.get here, had problems, didn't
|
||||
// give me stuff like 100%, gave me pixel calculated values.
|
||||
// Need the exact original values.
|
||||
var domNode = ed.domNode,
|
||||
rawStyle = domNode && domNode.style || {};
|
||||
this._origState = {
|
||||
width: rawStyle.width || "",
|
||||
height: rawStyle.height || "",
|
||||
top: domStyle.get(domNode, "top") || "",
|
||||
left: domStyle.get(domNode, "left") || "",
|
||||
position: domStyle.get(domNode, "position") || "static",
|
||||
marginBox: domGeometry.getMarginBox(ed.domNode)
|
||||
};
|
||||
|
||||
// Store the iframe state we have to restore later.
|
||||
// Not using domStyle.get here, had problems, didn't
|
||||
// give me stuff like 100%, gave me pixel calculated values.
|
||||
// Need the exact original values.
|
||||
var iframe = ed.iframe,
|
||||
iframeStyle = iframe && iframe.style || {};
|
||||
|
||||
var bc = domStyle.get(ed.iframe, "backgroundColor");
|
||||
this._origiFrameState = {
|
||||
backgroundColor: bc || "transparent",
|
||||
width: iframeStyle.width || "auto",
|
||||
height: iframeStyle.height || "auto",
|
||||
zIndex: iframeStyle.zIndex || ""
|
||||
};
|
||||
|
||||
// Okay, size everything.
|
||||
domStyle.set(ed.domNode, {
|
||||
position: "absolute",
|
||||
top: "0px",
|
||||
left: "0px",
|
||||
zIndex: this.zIndex,
|
||||
width: vp.w + "px",
|
||||
height: vp.h + "px"
|
||||
});
|
||||
|
||||
domStyle.set(ed.iframe, {
|
||||
height: "100%",
|
||||
width: "100%",
|
||||
zIndex: this.zIndex,
|
||||
backgroundColor: bc !== "transparent" &&
|
||||
bc !== "rgba(0, 0, 0, 0)"?bc:"white"
|
||||
});
|
||||
|
||||
domStyle.set(ed.iframe.parentNode, {
|
||||
height: "95%",
|
||||
width: "100%"
|
||||
});
|
||||
|
||||
// Store the overflow state we have to restore later.
|
||||
// IE had issues, so have to check that it's defined. Ugh.
|
||||
if(body.style && body.style.overflow){
|
||||
this._oldOverflow = domStyle.get(body, "overflow");
|
||||
}else{
|
||||
this._oldOverflow = "";
|
||||
}
|
||||
|
||||
if(has("ie") && !has("quirks")){
|
||||
// IE will put scrollbars in anyway, html (parent of body)
|
||||
// also controls them in standards mode, so we have to
|
||||
// remove them, argh.
|
||||
if(body.parentNode &&
|
||||
body.parentNode.style &&
|
||||
body.parentNode.style.overflow){
|
||||
this._oldBodyParentOverflow = body.parentNode.style.overflow;
|
||||
}else{
|
||||
try{
|
||||
this._oldBodyParentOverflow = domStyle.get(body.parentNode, "overflow");
|
||||
}catch(e){
|
||||
this._oldBodyParentOverflow = "scroll";
|
||||
}
|
||||
}
|
||||
domStyle.set(body.parentNode, "overflow", "hidden");
|
||||
}
|
||||
domStyle.set(body, "overflow", "hidden");
|
||||
|
||||
var resizer = function(){
|
||||
// function to handle resize events.
|
||||
// Will check current VP and only resize if
|
||||
// different.
|
||||
var vp = winUtils.getBox();
|
||||
if("_prevW" in this && "_prevH" in this){
|
||||
// No actual size change, ignore.
|
||||
if(vp.w === this._prevW && vp.h === this._prevH){
|
||||
return;
|
||||
}
|
||||
}else{
|
||||
this._prevW = vp.w;
|
||||
this._prevH = vp.h;
|
||||
}
|
||||
if(this._resizer){
|
||||
clearTimeout(this._resizer);
|
||||
delete this._resizer;
|
||||
}
|
||||
// Timeout it to help avoid spamming resize on IE.
|
||||
// Works for all browsers.
|
||||
this._resizer = setTimeout(lang.hitch(this, function(){
|
||||
delete this._resizer;
|
||||
this._resizeEditor();
|
||||
}), 10);
|
||||
};
|
||||
this._resizeHandle = on(window, "resize", lang.hitch(this, resizer));
|
||||
|
||||
// Also monitor for direct calls to resize and adapt editor.
|
||||
this._resizeHandle2 = aspect.after(ed, "onResize", lang.hitch(this, function(){
|
||||
if(this._resizer){
|
||||
clearTimeout(this._resizer);
|
||||
delete this._resizer;
|
||||
}
|
||||
this._resizer = setTimeout(lang.hitch(this, function(){
|
||||
delete this._resizer;
|
||||
this._resizeEditor();
|
||||
}), 10);
|
||||
}));
|
||||
|
||||
// Call it once to work around IE glitchiness. Safe for other browsers too.
|
||||
this._resizeEditor();
|
||||
var dn = this.editor.toolbar.domNode;
|
||||
setTimeout(function(){winUtils.scrollIntoView(dn);}, 250);
|
||||
}else{
|
||||
if(this._resizeHandle){
|
||||
// Cleanup resizing listeners
|
||||
this._resizeHandle.remove();
|
||||
this._resizeHandle = null;
|
||||
}
|
||||
if(this._resizeHandle2){
|
||||
// Cleanup resizing listeners
|
||||
this._resizeHandle2.remove();
|
||||
this._resizeHandle2 = null;
|
||||
}
|
||||
if(this._rst){
|
||||
clearTimeout(this._rst);
|
||||
this._rst = null;
|
||||
}
|
||||
|
||||
//Remove all position static class assigns.
|
||||
while(editorParent && editorParent !== win.body()){
|
||||
domClass.remove(editorParent, "dijitForceStatic");
|
||||
editorParent = editorParent.parentNode;
|
||||
}
|
||||
|
||||
// Restore resize function
|
||||
if(this._editorResizeHolder){
|
||||
this.editor.resize = this._editorResizeHolder;
|
||||
}
|
||||
|
||||
if(!this._origState && !this._origiFrameState){
|
||||
// If we actually didn't toggle, then don't do anything.
|
||||
return;
|
||||
}
|
||||
if(ed._fullscreen_oldOnKeyDown){
|
||||
ed.onKeyDown = ed._fullscreen_oldOnKeyDown;
|
||||
delete ed._fullscreen_oldOnKeyDown;
|
||||
}
|
||||
|
||||
// Add a timeout to make sure we don't have a resize firing in the
|
||||
// background at the time of minimize.
|
||||
var self = this;
|
||||
setTimeout(function(){
|
||||
// Restore all the editor state.
|
||||
var mb = self._origState.marginBox;
|
||||
var oh = self._origState.height;
|
||||
if(has("ie") && !has("quirks")){
|
||||
body.parentNode.style.overflow = self._oldBodyParentOverflow;
|
||||
delete self._oldBodyParentOverflow;
|
||||
}
|
||||
domStyle.set(body, "overflow", self._oldOverflow);
|
||||
delete self._oldOverflow;
|
||||
|
||||
domStyle.set(ed.domNode, self._origState);
|
||||
domStyle.set(ed.iframe.parentNode, {
|
||||
height: "",
|
||||
width: ""
|
||||
});
|
||||
domStyle.set(ed.iframe, self._origiFrameState);
|
||||
delete self._origState;
|
||||
delete self._origiFrameState;
|
||||
// In case it is contained in a layout and the layout changed size,
|
||||
// go ahead and call resize.
|
||||
var pWidget = registry.getEnclosingWidget(ed.domNode.parentNode);
|
||||
if(pWidget && pWidget.resize){
|
||||
pWidget.resize();
|
||||
}else{
|
||||
if(!oh || oh.indexOf("%") < 0){
|
||||
// Resize if the original size wasn't set
|
||||
// or wasn't in percent. Timeout is to avoid
|
||||
// an IE crash in unit testing.
|
||||
setTimeout(lang.hitch(this, function(){ed.resize({h: mb.h});}), 0);
|
||||
}
|
||||
}
|
||||
winUtils.scrollIntoView(self.editor.toolbar.domNode);
|
||||
}, 100);
|
||||
}
|
||||
},
|
||||
|
||||
updateState: function(){
|
||||
// summary:
|
||||
// Over-ride for button state control for disabled to work.
|
||||
this.button.set("disabled", this.get("disabled"));
|
||||
},
|
||||
|
||||
destroy: function(){
|
||||
// summary:
|
||||
// Over-ride to ensure the resize handle gets cleaned up.
|
||||
if(this._resizeHandle){
|
||||
// Cleanup resizing listeners
|
||||
this._resizeHandle.remove();
|
||||
this._resizeHandle = null;
|
||||
}
|
||||
if(this._resizeHandle2){
|
||||
// Cleanup resizing listeners
|
||||
this._resizeHandle2.remove();
|
||||
this._resizeHandle2 = null;
|
||||
}
|
||||
if(this._resizer){
|
||||
clearTimeout(this._resizer);
|
||||
this._resizer = null;
|
||||
}
|
||||
this.inherited(arguments);
|
||||
}
|
||||
});
|
||||
|
||||
// Register this plugin.
|
||||
// For back-compat accept "fullscreen" (all lowercase) too, remove in 2.0
|
||||
_Plugin.registry["fullScreen"] = _Plugin.registry["fullscreen"] = function(args){
|
||||
return new FullScreen({
|
||||
zIndex: ("zIndex" in args)?args.zIndex:500
|
||||
});
|
||||
};
|
||||
|
||||
return FullScreen;
|
||||
});
|
||||
@@ -1,586 +0,0 @@
|
||||
define("dijit/_editor/plugins/LinkDialog", [
|
||||
"require",
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom-attr", // domAttr.get
|
||||
"dojo/keys", // keys.ENTER
|
||||
"dojo/_base/lang", // lang.delegate lang.hitch lang.trim
|
||||
"dojo/_base/sniff", // has("ie")
|
||||
"dojo/string", // string.substitute
|
||||
"dojo/_base/window", // win.withGlobal
|
||||
"../../_Widget",
|
||||
"../_Plugin",
|
||||
"../../form/DropDownButton",
|
||||
"../range",
|
||||
"../selection"
|
||||
], function(require, declare, domAttr, keys, lang, has, string, win,
|
||||
_Widget, _Plugin, DropDownButton, rangeapi, selectionapi){
|
||||
|
||||
/*=====
|
||||
var _Plugin = dijit._editor._Plugin;
|
||||
=====*/
|
||||
|
||||
// module:
|
||||
// dijit/_editor/plugins/LinkDialog
|
||||
// summary:
|
||||
// Editor plugins: LinkDialog (for inserting links) and ImgLinkDialog (for inserting images)
|
||||
|
||||
|
||||
var LinkDialog = declare("dijit._editor.plugins.LinkDialog", _Plugin, {
|
||||
// summary:
|
||||
// This plugin provides the basis for an 'anchor' (link) dialog and an extension of it
|
||||
// provides the image link dialog.
|
||||
//
|
||||
// description:
|
||||
// The command provided by this plugin is:
|
||||
// * createLink
|
||||
|
||||
// Override _Plugin.buttonClass. This plugin is controlled by a DropDownButton
|
||||
// (which triggers a TooltipDialog).
|
||||
buttonClass: DropDownButton,
|
||||
|
||||
// Override _Plugin.useDefaultCommand... processing is handled by this plugin, not by dijit.Editor.
|
||||
useDefaultCommand: false,
|
||||
|
||||
// urlRegExp: [protected] String
|
||||
// Used for validating input as correct URL. While file:// urls are not terribly
|
||||
// useful, they are technically valid.
|
||||
urlRegExp: "((https?|ftps?|file)\\://|\./|/|)(/[a-zA-Z]{1,1}:/|)(((?:(?:[\\da-zA-Z](?:[-\\da-zA-Z]{0,61}[\\da-zA-Z])?)\\.)*(?:[a-zA-Z](?:[-\\da-zA-Z]{0,80}[\\da-zA-Z])?)\\.?)|(((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])|(0[xX]0*[\\da-fA-F]?[\\da-fA-F]\\.){3}0[xX]0*[\\da-fA-F]?[\\da-fA-F]|(0+[0-3][0-7][0-7]\\.){3}0+[0-3][0-7][0-7]|(0|[1-9]\\d{0,8}|[1-3]\\d{9}|4[01]\\d{8}|42[0-8]\\d{7}|429[0-3]\\d{6}|4294[0-8]\\d{5}|42949[0-5]\\d{4}|429496[0-6]\\d{3}|4294967[01]\\d{2}|42949672[0-8]\\d|429496729[0-5])|0[xX]0*[\\da-fA-F]{1,8}|([\\da-fA-F]{1,4}\\:){7}[\\da-fA-F]{1,4}|([\\da-fA-F]{1,4}\\:){6}((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])))(\\:\\d+)?(/(?:[^?#\\s/]+/)*(?:[^?#\\s/]{0,}(?:\\?[^?#\\s/]*)?(?:#.*)?)?)?",
|
||||
|
||||
// emailRegExp: [protected] String
|
||||
// Used for validating input as correct email address. Taken from dojox.validate
|
||||
emailRegExp: "<?(mailto\\:)([!#-'*+\\-\\/-9=?A-Z^-~]+[.])*[!#-'*+\\-\\/-9=?A-Z^-~]+" /*username*/ + "@" +
|
||||
"((?:(?:[\\da-zA-Z](?:[-\\da-zA-Z]{0,61}[\\da-zA-Z])?)\\.)+(?:[a-zA-Z](?:[-\\da-zA-Z]{0,6}[\\da-zA-Z])?)\\.?)|localhost|^[^-][a-zA-Z0-9_-]*>?", // host.
|
||||
|
||||
// htmlTemplate: [protected] String
|
||||
// String used for templating the HTML to insert at the desired point.
|
||||
htmlTemplate: "<a href=\"${urlInput}\" _djrealurl=\"${urlInput}\"" +
|
||||
" target=\"${targetSelect}\"" +
|
||||
">${textInput}</a>",
|
||||
|
||||
// tag: [protected] String
|
||||
// Tag used for the link type.
|
||||
tag: "a",
|
||||
|
||||
// _hostRxp [private] RegExp
|
||||
// Regular expression used to validate url fragments (ip address, hostname, etc)
|
||||
_hostRxp: /^((([^\[:]+):)?([^@]+)@)?(\[([^\]]+)\]|([^\[:]*))(:([0-9]+))?$/,
|
||||
|
||||
// _userAtRxp [private] RegExp
|
||||
// Regular expression used to validate e-mail address fragment.
|
||||
_userAtRxp: /^([!#-'*+\-\/-9=?A-Z^-~]+[.])*[!#-'*+\-\/-9=?A-Z^-~]+@/i,
|
||||
|
||||
// linkDialogTemplate: [protected] String
|
||||
// Template for contents of TooltipDialog to pick URL
|
||||
linkDialogTemplate: [
|
||||
"<table><tr><td>",
|
||||
"<label for='${id}_urlInput'>${url}</label>",
|
||||
"</td><td>",
|
||||
"<input data-dojo-type='dijit.form.ValidationTextBox' required='true' " +
|
||||
"id='${id}_urlInput' name='urlInput' data-dojo-props='intermediateChanges:true'/>",
|
||||
"</td></tr><tr><td>",
|
||||
"<label for='${id}_textInput'>${text}</label>",
|
||||
"</td><td>",
|
||||
"<input data-dojo-type='dijit.form.ValidationTextBox' required='true' id='${id}_textInput' " +
|
||||
"name='textInput' data-dojo-props='intermediateChanges:true'/>",
|
||||
"</td></tr><tr><td>",
|
||||
"<label for='${id}_targetSelect'>${target}</label>",
|
||||
"</td><td>",
|
||||
"<select id='${id}_targetSelect' name='targetSelect' data-dojo-type='dijit.form.Select'>",
|
||||
"<option selected='selected' value='_self'>${currentWindow}</option>",
|
||||
"<option value='_blank'>${newWindow}</option>",
|
||||
"<option value='_top'>${topWindow}</option>",
|
||||
"<option value='_parent'>${parentWindow}</option>",
|
||||
"</select>",
|
||||
"</td></tr><tr><td colspan='2'>",
|
||||
"<button data-dojo-type='dijit.form.Button' type='submit' id='${id}_setButton'>${set}</button>",
|
||||
"<button data-dojo-type='dijit.form.Button' type='button' id='${id}_cancelButton'>${buttonCancel}</button>",
|
||||
"</td></tr></table>"
|
||||
].join(""),
|
||||
|
||||
_initButton: function(){
|
||||
this.inherited(arguments);
|
||||
|
||||
// Setup to lazy create TooltipDialog first time the button is clicked
|
||||
this.button.loadDropDown = lang.hitch(this, "_loadDropDown");
|
||||
|
||||
this._connectTagEvents();
|
||||
},
|
||||
_loadDropDown: function(callback){
|
||||
// Called the first time the button is pressed. Initialize TooltipDialog.
|
||||
require([
|
||||
"dojo/i18n", // i18n.getLocalization
|
||||
"../../TooltipDialog",
|
||||
"../../registry", // registry.byId, registry.getUniqueId
|
||||
"../../form/Button", // used by template
|
||||
"../../form/Select", // used by template
|
||||
"../../form/ValidationTextBox", // used by template
|
||||
"dojo/i18n!../../nls/common",
|
||||
"dojo/i18n!../nls/LinkDialog"
|
||||
], lang.hitch(this, function(i18n, TooltipDialog, registry){
|
||||
var _this = this;
|
||||
this.tag = this.command == 'insertImage' ? 'img' : 'a';
|
||||
var messages = lang.delegate(i18n.getLocalization("dijit", "common", this.lang),
|
||||
i18n.getLocalization("dijit._editor", "LinkDialog", this.lang));
|
||||
var dropDown = (this.dropDown = this.button.dropDown = new TooltipDialog({
|
||||
title: messages[this.command + "Title"],
|
||||
execute: lang.hitch(this, "setValue"),
|
||||
onOpen: function(){
|
||||
_this._onOpenDialog();
|
||||
TooltipDialog.prototype.onOpen.apply(this, arguments);
|
||||
},
|
||||
onCancel: function(){
|
||||
setTimeout(lang.hitch(_this, "_onCloseDialog"),0);
|
||||
}
|
||||
}));
|
||||
messages.urlRegExp = this.urlRegExp;
|
||||
messages.id = registry.getUniqueId(this.editor.id);
|
||||
this._uniqueId = messages.id;
|
||||
this._setContent(dropDown.title +
|
||||
"<div style='border-bottom: 1px black solid;padding-bottom:2pt;margin-bottom:4pt'></div>" +
|
||||
string.substitute(this.linkDialogTemplate, messages));
|
||||
dropDown.startup();
|
||||
this._urlInput = registry.byId(this._uniqueId + "_urlInput");
|
||||
this._textInput = registry.byId(this._uniqueId + "_textInput");
|
||||
this._setButton = registry.byId(this._uniqueId + "_setButton");
|
||||
this.connect(registry.byId(this._uniqueId + "_cancelButton"), "onClick", function(){
|
||||
this.dropDown.onCancel();
|
||||
});
|
||||
if(this._urlInput){
|
||||
this.connect(this._urlInput, "onChange", "_checkAndFixInput");
|
||||
}
|
||||
if(this._textInput){
|
||||
this.connect(this._textInput, "onChange", "_checkAndFixInput");
|
||||
}
|
||||
|
||||
// Build up the dual check for http/https/file:, and mailto formats.
|
||||
this._urlRegExp = new RegExp("^" + this.urlRegExp + "$", "i");
|
||||
this._emailRegExp = new RegExp("^" + this.emailRegExp + "$", "i");
|
||||
this._urlInput.isValid = lang.hitch(this, function(){
|
||||
// Function over-ride of isValid to test if the input matches a url or a mailto style link.
|
||||
var value = this._urlInput.get("value");
|
||||
return this._urlRegExp.test(value) || this._emailRegExp.test(value);
|
||||
});
|
||||
|
||||
// Listen for enter and execute if valid.
|
||||
this.connect(dropDown.domNode, "onkeypress", function(e){
|
||||
if(e && e.charOrCode == keys.ENTER &&
|
||||
!e.shiftKey && !e.metaKey && !e.ctrlKey && !e.altKey){
|
||||
if(!this._setButton.get("disabled")){
|
||||
dropDown.onExecute();
|
||||
dropDown.execute(dropDown.get('value'));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
callback();
|
||||
}));
|
||||
},
|
||||
|
||||
_checkAndFixInput: function(){
|
||||
// summary:
|
||||
// A function to listen for onChange events and test the input contents
|
||||
// for valid information, such as valid urls with http/https/ftp and if
|
||||
// not present, try and guess if the input url is relative or not, and if
|
||||
// not, append http:// to it. Also validates other fields as determined by
|
||||
// the internal _isValid function.
|
||||
var self = this;
|
||||
var url = this._urlInput.get("value");
|
||||
var fixupUrl = function(url){
|
||||
var appendHttp = false;
|
||||
var appendMailto = false;
|
||||
if(url && url.length > 1){
|
||||
url = lang.trim(url);
|
||||
if(url.indexOf("mailto:") !== 0){
|
||||
if(url.indexOf("/") > 0){
|
||||
if(url.indexOf("://") === -1){
|
||||
// Check that it doesn't start with / or ./, which would
|
||||
// imply 'target server relativeness'
|
||||
if(url.charAt(0) !== '/' && url.indexOf("./") !== 0){
|
||||
if(self._hostRxp.test(url)){
|
||||
appendHttp = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}else if(self._userAtRxp.test(url)){
|
||||
// If it looks like a foo@, append a mailto.
|
||||
appendMailto = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(appendHttp){
|
||||
self._urlInput.set("value", "http://" + url);
|
||||
}
|
||||
if(appendMailto){
|
||||
self._urlInput.set("value", "mailto:" + url);
|
||||
}
|
||||
self._setButton.set("disabled", !self._isValid());
|
||||
};
|
||||
if(this._delayedCheck){
|
||||
clearTimeout(this._delayedCheck);
|
||||
this._delayedCheck = null;
|
||||
}
|
||||
this._delayedCheck = setTimeout(function(){
|
||||
fixupUrl(url);
|
||||
}, 250);
|
||||
},
|
||||
|
||||
_connectTagEvents: function(){
|
||||
// summary:
|
||||
// Over-ridable function that connects tag specific events.
|
||||
this.editor.onLoadDeferred.addCallback(lang.hitch(this, function(){
|
||||
this.connect(this.editor.editNode, "ondblclick", this._onDblClick);
|
||||
}));
|
||||
},
|
||||
|
||||
_isValid: function(){
|
||||
// summary:
|
||||
// Internal function to allow validating of the inputs
|
||||
// for a link to determine if set should be disabled or not
|
||||
// tags:
|
||||
// protected
|
||||
return this._urlInput.isValid() && this._textInput.isValid();
|
||||
},
|
||||
|
||||
_setContent: function(staticPanel){
|
||||
// summary:
|
||||
// Helper for _initButton above. Not sure why it's a separate method.
|
||||
this.dropDown.set({
|
||||
parserScope: "dojo", // make parser search for dojoType/data-dojo-type even if page is multi-version
|
||||
content: staticPanel
|
||||
});
|
||||
},
|
||||
|
||||
_checkValues: function(args){
|
||||
// summary:
|
||||
// Function to check the values in args and 'fix' them up as needed.
|
||||
// args: Object
|
||||
// Content being set.
|
||||
// tags:
|
||||
// protected
|
||||
if(args && args.urlInput){
|
||||
args.urlInput = args.urlInput.replace(/"/g, """);
|
||||
}
|
||||
return args;
|
||||
},
|
||||
|
||||
setValue: function(args){
|
||||
// summary:
|
||||
// Callback from the dialog when user presses "set" button.
|
||||
// tags:
|
||||
// private
|
||||
//TODO: prevent closing popup if the text is empty
|
||||
this._onCloseDialog();
|
||||
if(has("ie") < 9){ //see #4151
|
||||
var sel = rangeapi.getSelection(this.editor.window);
|
||||
var range = sel.getRangeAt(0);
|
||||
var a = range.endContainer;
|
||||
if(a.nodeType === 3){
|
||||
// Text node, may be the link contents, so check parent.
|
||||
// This plugin doesn't really support nested HTML elements
|
||||
// in the link, it assumes all link content is text.
|
||||
a = a.parentNode;
|
||||
}
|
||||
if(a && (a.nodeName && a.nodeName.toLowerCase() !== this.tag)){
|
||||
// Still nothing, one last thing to try on IE, as it might be 'img'
|
||||
// and thus considered a control.
|
||||
a = win.withGlobal(this.editor.window,
|
||||
"getSelectedElement", selectionapi, [this.tag]);
|
||||
}
|
||||
if(a && (a.nodeName && a.nodeName.toLowerCase() === this.tag)){
|
||||
// Okay, we do have a match. IE, for some reason, sometimes pastes before
|
||||
// instead of removing the targeted paste-over element, so we unlink the
|
||||
// old one first. If we do not the <a> tag remains, but it has no content,
|
||||
// so isn't readily visible (but is wrong for the action).
|
||||
if(this.editor.queryCommandEnabled("unlink")){
|
||||
// Select all the link children, then unlink. The following insert will
|
||||
// then replace the selected text.
|
||||
win.withGlobal(this.editor.window,
|
||||
"selectElementChildren", selectionapi, [a]);
|
||||
this.editor.execCommand("unlink");
|
||||
}
|
||||
}
|
||||
}
|
||||
// make sure values are properly escaped, etc.
|
||||
args = this._checkValues(args);
|
||||
this.editor.execCommand('inserthtml',
|
||||
string.substitute(this.htmlTemplate, args));
|
||||
},
|
||||
|
||||
_onCloseDialog: function(){
|
||||
// summary:
|
||||
// Handler for close event on the dialog
|
||||
this.editor.focus();
|
||||
},
|
||||
|
||||
_getCurrentValues: function(a){
|
||||
// summary:
|
||||
// Over-ride for getting the values to set in the dropdown.
|
||||
// a:
|
||||
// The anchor/link to process for data for the dropdown.
|
||||
// tags:
|
||||
// protected
|
||||
var url, text, target;
|
||||
if(a && a.tagName.toLowerCase() === this.tag){
|
||||
url = a.getAttribute('_djrealurl') || a.getAttribute('href');
|
||||
target = a.getAttribute('target') || "_self";
|
||||
text = a.textContent || a.innerText;
|
||||
win.withGlobal(this.editor.window, "selectElement", selectionapi, [a, true]);
|
||||
}else{
|
||||
text = win.withGlobal(this.editor.window, selectionapi.getSelectedText);
|
||||
}
|
||||
return {urlInput: url || '', textInput: text || '', targetSelect: target || ''}; //Object;
|
||||
},
|
||||
|
||||
_onOpenDialog: function(){
|
||||
// summary:
|
||||
// Handler for when the dialog is opened.
|
||||
// If the caret is currently in a URL then populate the URL's info into the dialog.
|
||||
var a;
|
||||
if(has("ie") < 9){
|
||||
// IE is difficult to select the element in, using the range unified
|
||||
// API seems to work reasonably well.
|
||||
var sel = rangeapi.getSelection(this.editor.window);
|
||||
var range = sel.getRangeAt(0);
|
||||
a = range.endContainer;
|
||||
if(a.nodeType === 3){
|
||||
// Text node, may be the link contents, so check parent.
|
||||
// This plugin doesn't really support nested HTML elements
|
||||
// in the link, it assumes all link content is text.
|
||||
a = a.parentNode;
|
||||
}
|
||||
if(a && (a.nodeName && a.nodeName.toLowerCase() !== this.tag)){
|
||||
// Still nothing, one last thing to try on IE, as it might be 'img'
|
||||
// and thus considered a control.
|
||||
a = win.withGlobal(this.editor.window,
|
||||
"getSelectedElement", selectionapi, [this.tag]);
|
||||
}
|
||||
}else{
|
||||
a = win.withGlobal(this.editor.window,
|
||||
"getAncestorElement", selectionapi, [this.tag]);
|
||||
}
|
||||
this.dropDown.reset();
|
||||
this._setButton.set("disabled", true);
|
||||
this.dropDown.set("value", this._getCurrentValues(a));
|
||||
},
|
||||
|
||||
_onDblClick: function(e){
|
||||
// summary:
|
||||
// Function to define a behavior on double clicks on the element
|
||||
// type this dialog edits to select it and pop up the editor
|
||||
// dialog.
|
||||
// e: Object
|
||||
// The double-click event.
|
||||
// tags:
|
||||
// protected.
|
||||
if(e && e.target){
|
||||
var t = e.target;
|
||||
var tg = t.tagName? t.tagName.toLowerCase() : "";
|
||||
if(tg === this.tag && domAttr.get(t,"href")){
|
||||
var editor = this.editor;
|
||||
|
||||
win.withGlobal(editor.window,
|
||||
"selectElement",
|
||||
selectionapi, [t]);
|
||||
|
||||
editor.onDisplayChanged();
|
||||
|
||||
// Call onNormalizedDisplayChange() now, rather than on timer.
|
||||
// On IE, when focus goes to the first <input> in the TooltipDialog, the editor loses it's selection.
|
||||
// Later if onNormalizedDisplayChange() gets called via the timer it will disable the LinkDialog button
|
||||
// (actually, all the toolbar buttons), at which point clicking the <input> will close the dialog,
|
||||
// since (for unknown reasons) focus.js ignores disabled controls.
|
||||
if(editor._updateTimer){
|
||||
clearTimeout(editor._updateTimer);
|
||||
delete editor._updateTimer;
|
||||
}
|
||||
editor.onNormalizedDisplayChanged();
|
||||
|
||||
var button = this.button;
|
||||
setTimeout(function(){
|
||||
// Focus shift outside the event handler.
|
||||
// IE doesn't like focus changes in event handles.
|
||||
button.set("disabled", false);
|
||||
button.loadAndOpenDropDown().then(function(){
|
||||
if(button.dropDown.focus){
|
||||
button.dropDown.focus();
|
||||
}
|
||||
});
|
||||
}, 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var ImgLinkDialog = declare("dijit._editor.plugins.ImgLinkDialog", [LinkDialog], {
|
||||
// summary:
|
||||
// This plugin extends LinkDialog and adds in a plugin for handling image links.
|
||||
// provides the image link dialog.
|
||||
//
|
||||
// description:
|
||||
// The command provided by this plugin is:
|
||||
// * insertImage
|
||||
|
||||
// linkDialogTemplate: [protected] String
|
||||
// Over-ride for template since img dialog doesn't need target that anchor tags may.
|
||||
linkDialogTemplate: [
|
||||
"<table><tr><td>",
|
||||
"<label for='${id}_urlInput'>${url}</label>",
|
||||
"</td><td>",
|
||||
"<input dojoType='dijit.form.ValidationTextBox' regExp='${urlRegExp}' " +
|
||||
"required='true' id='${id}_urlInput' name='urlInput' data-dojo-props='intermediateChanges:true'/>",
|
||||
"</td></tr><tr><td>",
|
||||
"<label for='${id}_textInput'>${text}</label>",
|
||||
"</td><td>",
|
||||
"<input data-dojo-type='dijit.form.ValidationTextBox' required='false' id='${id}_textInput' " +
|
||||
"name='textInput' data-dojo-props='intermediateChanges:true'/>",
|
||||
"</td></tr><tr><td>",
|
||||
"</td><td>",
|
||||
"</td></tr><tr><td colspan='2'>",
|
||||
"<button data-dojo-type='dijit.form.Button' type='submit' id='${id}_setButton'>${set}</button>",
|
||||
"<button data-dojo-type='dijit.form.Button' type='button' id='${id}_cancelButton'>${buttonCancel}</button>",
|
||||
"</td></tr></table>"
|
||||
].join(""),
|
||||
|
||||
// htmlTemplate: [protected] String
|
||||
// String used for templating the <img> HTML to insert at the desired point.
|
||||
htmlTemplate: "<img src=\"${urlInput}\" _djrealurl=\"${urlInput}\" alt=\"${textInput}\" />",
|
||||
|
||||
// tag: [protected] String
|
||||
// Tag used for the link type (img).
|
||||
tag: "img",
|
||||
|
||||
_getCurrentValues: function(img){
|
||||
// summary:
|
||||
// Over-ride for getting the values to set in the dropdown.
|
||||
// a:
|
||||
// The anchor/link to process for data for the dropdown.
|
||||
// tags:
|
||||
// protected
|
||||
var url, text;
|
||||
if(img && img.tagName.toLowerCase() === this.tag){
|
||||
url = img.getAttribute('_djrealurl') || img.getAttribute('src');
|
||||
text = img.getAttribute('alt');
|
||||
win.withGlobal(this.editor.window,
|
||||
"selectElement", selectionapi, [img, true]);
|
||||
}else{
|
||||
text = win.withGlobal(this.editor.window, selectionapi.getSelectedText);
|
||||
}
|
||||
return {urlInput: url || '', textInput: text || ''}; //Object;
|
||||
},
|
||||
|
||||
_isValid: function(){
|
||||
// summary:
|
||||
// Over-ride for images. You can have alt text of blank, it is valid.
|
||||
// tags:
|
||||
// protected
|
||||
return this._urlInput.isValid();
|
||||
},
|
||||
|
||||
_connectTagEvents: function(){
|
||||
// summary:
|
||||
// Over-ridable function that connects tag specific events.
|
||||
this.inherited(arguments);
|
||||
this.editor.onLoadDeferred.addCallback(lang.hitch(this, function(){
|
||||
// Use onmousedown instead of onclick. Seems that IE eats the first onclick
|
||||
// to wrap it in a selector box, then the second one acts as onclick. See #10420
|
||||
this.connect(this.editor.editNode, "onmousedown", this._selectTag);
|
||||
}));
|
||||
},
|
||||
|
||||
_selectTag: function(e){
|
||||
// summary:
|
||||
// A simple event handler that lets me select an image if it is clicked on.
|
||||
// makes it easier to select images in a standard way across browsers. Otherwise
|
||||
// selecting an image for edit becomes difficult.
|
||||
// e: Event
|
||||
// The mousedown event.
|
||||
// tags:
|
||||
// private
|
||||
if(e && e.target){
|
||||
var t = e.target;
|
||||
var tg = t.tagName? t.tagName.toLowerCase() : "";
|
||||
if(tg === this.tag){
|
||||
win.withGlobal(this.editor.window,
|
||||
"selectElement",
|
||||
selectionapi, [t]);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_checkValues: function(args){
|
||||
// summary:
|
||||
// Function to check the values in args and 'fix' them up as needed
|
||||
// (special characters in the url or alt text)
|
||||
// args: Object
|
||||
// Content being set.
|
||||
// tags:
|
||||
// protected
|
||||
if(args && args.urlInput){
|
||||
args.urlInput = args.urlInput.replace(/"/g, """);
|
||||
}
|
||||
if(args && args.textInput){
|
||||
args.textInput = args.textInput.replace(/"/g, """);
|
||||
}
|
||||
return args;
|
||||
},
|
||||
|
||||
_onDblClick: function(e){
|
||||
// summary:
|
||||
// Function to define a behavior on double clicks on the element
|
||||
// type this dialog edits to select it and pop up the editor
|
||||
// dialog.
|
||||
// e: Object
|
||||
// The double-click event.
|
||||
// tags:
|
||||
// protected.
|
||||
if(e && e.target){
|
||||
var t = e.target;
|
||||
var tg = t.tagName ? t.tagName.toLowerCase() : "";
|
||||
if(tg === this.tag && domAttr.get(t,"src")){
|
||||
var editor = this.editor;
|
||||
|
||||
win.withGlobal(editor.window,
|
||||
"selectElement",
|
||||
selectionapi, [t]);
|
||||
editor.onDisplayChanged();
|
||||
|
||||
// Call onNormalizedDisplayChange() now, rather than on timer.
|
||||
// On IE, when focus goes to the first <input> in the TooltipDialog, the editor loses it's selection.
|
||||
// Later if onNormalizedDisplayChange() gets called via the timer it will disable the LinkDialog button
|
||||
// (actually, all the toolbar buttons), at which point clicking the <input> will close the dialog,
|
||||
// since (for unknown reasons) focus.js ignores disabled controls.
|
||||
if(editor._updateTimer){
|
||||
clearTimeout(editor._updateTimer);
|
||||
delete editor._updateTimer;
|
||||
}
|
||||
editor.onNormalizedDisplayChanged();
|
||||
|
||||
var button = this.button;
|
||||
setTimeout(function(){
|
||||
// Focus shift outside the event handler.
|
||||
// IE doesn't like focus changes in event handles.
|
||||
button.set("disabled", false);
|
||||
button.loadAndOpenDropDown().then(function(){
|
||||
if(button.dropDown.focus){
|
||||
button.dropDown.focus();
|
||||
}
|
||||
});
|
||||
}, 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Register these plugins
|
||||
_Plugin.registry["createLink"] = function(){
|
||||
return new LinkDialog({command: "createLink"});
|
||||
};
|
||||
_Plugin.registry["insertImage"] = function(){
|
||||
return new ImgLinkDialog({command: "insertImage"});
|
||||
};
|
||||
|
||||
|
||||
// Export both LinkDialog and ImgLinkDialog
|
||||
LinkDialog.ImgLinkDialog = ImgLinkDialog;
|
||||
return LinkDialog;
|
||||
});
|
||||
@@ -1,83 +0,0 @@
|
||||
define("dijit/_editor/plugins/NewPage", [
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/i18n", // i18n.getLocalization
|
||||
"dojo/_base/lang", // lang.hitch
|
||||
"../_Plugin",
|
||||
"../../form/Button",
|
||||
"dojo/i18n!../nls/commands"
|
||||
], function(declare, i18n, lang, _Plugin, Button){
|
||||
|
||||
/*=====
|
||||
var _Plugin = dijit._editor._Plugin;
|
||||
=====*/
|
||||
|
||||
// module:
|
||||
// dijit/_editor/plugins/NewPage
|
||||
// summary:
|
||||
// This plugin provides a simple 'new page' capability. In other
|
||||
// words, set content to some default user defined string.
|
||||
|
||||
|
||||
var NewPage = declare("dijit._editor.plugins.NewPage",_Plugin,{
|
||||
// summary:
|
||||
// This plugin provides a simple 'new page' capability. In other
|
||||
// words, set content to some default user defined string.
|
||||
|
||||
// content: [public] String
|
||||
// The default content to insert into the editor as the new page.
|
||||
// The default is the <br> tag, a single blank line.
|
||||
content: "<br>",
|
||||
|
||||
_initButton: function(){
|
||||
// summary:
|
||||
// Over-ride for creation of the Print button.
|
||||
var strings = i18n.getLocalization("dijit._editor", "commands"),
|
||||
editor = this.editor;
|
||||
this.button = new Button({
|
||||
label: strings["newPage"],
|
||||
dir: editor.dir,
|
||||
lang: editor.lang,
|
||||
showLabel: false,
|
||||
iconClass: this.iconClassPrefix + " " + this.iconClassPrefix + "NewPage",
|
||||
tabIndex: "-1",
|
||||
onClick: lang.hitch(this, "_newPage")
|
||||
});
|
||||
},
|
||||
|
||||
setEditor: function(/*dijit.Editor*/ editor){
|
||||
// summary:
|
||||
// Tell the plugin which Editor it is associated with.
|
||||
// editor: Object
|
||||
// The editor object to attach the newPage capability to.
|
||||
this.editor = editor;
|
||||
this._initButton();
|
||||
},
|
||||
|
||||
updateState: function(){
|
||||
// summary:
|
||||
// Over-ride for button state control for disabled to work.
|
||||
this.button.set("disabled", this.get("disabled"));
|
||||
},
|
||||
|
||||
_newPage: function(){
|
||||
// summary:
|
||||
// Function to set the content to blank.
|
||||
// tags:
|
||||
// private
|
||||
this.editor.beginEditing();
|
||||
this.editor.set("value", this.content);
|
||||
this.editor.endEditing();
|
||||
this.editor.focus();
|
||||
}
|
||||
});
|
||||
|
||||
// Register this plugin.
|
||||
// For back-compat accept "newpage" (all lowercase) too, remove in 2.0
|
||||
_Plugin.registry["newPage"] = _Plugin.registry["newpage"] = function(args){
|
||||
return new NewPage({
|
||||
content: ("content" in args)?args.content:"<br>"
|
||||
});
|
||||
};
|
||||
|
||||
return NewPage;
|
||||
});
|
||||
@@ -1,129 +0,0 @@
|
||||
define("dijit/_editor/plugins/Print", [
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/i18n", // i18n.getLocalization
|
||||
"dojo/_base/lang", // lang.hitch
|
||||
"dojo/_base/sniff", // has("chrome") has("opera")
|
||||
"../../focus", // focus.focus()
|
||||
"../_Plugin",
|
||||
"../../form/Button",
|
||||
"dojo/i18n!../nls/commands"
|
||||
], function(declare, i18n, lang, has, focus, _Plugin, Button){
|
||||
|
||||
/*=====
|
||||
var _Plugin = dijit._editor._Plugin;
|
||||
=====*/
|
||||
|
||||
// module:
|
||||
// dijit/_editor/plugins/Print
|
||||
// summary:
|
||||
// This plugin provides Print capability to the editor. When
|
||||
// clicked, the document in the editor frame will be printed.
|
||||
|
||||
|
||||
var Print = declare("dijit._editor.plugins.Print",_Plugin,{
|
||||
// summary:
|
||||
// This plugin provides Print capability to the editor. When
|
||||
// clicked, the document in the editor frame will be printed.
|
||||
|
||||
_initButton: function(){
|
||||
// summary:
|
||||
// Over-ride for creation of the Print button.
|
||||
var strings = i18n.getLocalization("dijit._editor", "commands"),
|
||||
editor = this.editor;
|
||||
this.button = new Button({
|
||||
label: strings["print"],
|
||||
dir: editor.dir,
|
||||
lang: editor.lang,
|
||||
showLabel: false,
|
||||
iconClass: this.iconClassPrefix + " " + this.iconClassPrefix + "Print",
|
||||
tabIndex: "-1",
|
||||
onClick: lang.hitch(this, "_print")
|
||||
});
|
||||
},
|
||||
|
||||
setEditor: function(/*dijit.Editor*/ editor){
|
||||
// summary:
|
||||
// Tell the plugin which Editor it is associated with.
|
||||
// editor: Object
|
||||
// The editor object to attach the print capability to.
|
||||
this.editor = editor;
|
||||
this._initButton();
|
||||
|
||||
// Set up a check that we have a print function
|
||||
// and disable button if we do not.
|
||||
this.editor.onLoadDeferred.addCallback(
|
||||
lang.hitch(this, function(){
|
||||
if(!this.editor.iframe.contentWindow["print"]){
|
||||
this.button.set("disabled", true);
|
||||
}
|
||||
})
|
||||
);
|
||||
},
|
||||
|
||||
updateState: function(){
|
||||
// summary:
|
||||
// Over-ride for button state control for disabled to work.
|
||||
var disabled = this.get("disabled");
|
||||
if(!this.editor.iframe.contentWindow["print"]){
|
||||
disabled = true;
|
||||
}
|
||||
this.button.set("disabled", disabled);
|
||||
},
|
||||
|
||||
_print: function(){
|
||||
// summary:
|
||||
// Function to trigger printing of the editor document
|
||||
// tags:
|
||||
// private
|
||||
var edFrame = this.editor.iframe;
|
||||
if(edFrame.contentWindow["print"]){
|
||||
// IE requires the frame to be focused for
|
||||
// print to work, but since this is okay for all
|
||||
// no special casing.
|
||||
if(!has("opera") && !has("chrome")){
|
||||
focus.focus(edFrame);
|
||||
edFrame.contentWindow.print();
|
||||
}else{
|
||||
// Neither Opera nor Chrome 3 et you print single frames.
|
||||
// So, open a new 'window', print it, and close it.
|
||||
// Also, can't use size 0x0, have to use 1x1
|
||||
var edDoc = this.editor.document;
|
||||
var content = this.editor.get("value");
|
||||
content = "<html><head><meta http-equiv='Content-Type' " +
|
||||
"content='text/html; charset='UTF-8'></head><body>" +
|
||||
content + "</body></html>";
|
||||
var win = window.open("javascript: ''",
|
||||
"",
|
||||
"status=0,menubar=0,location=0,toolbar=0," +
|
||||
"width=1,height=1,resizable=0,scrollbars=0");
|
||||
win.document.open();
|
||||
win.document.write(content);
|
||||
win.document.close();
|
||||
|
||||
var styleNodes = edDoc.getElementsByTagName("style");
|
||||
if(styleNodes){
|
||||
// Clone over any editor view styles, since we can't print the iframe
|
||||
// directly.
|
||||
var i;
|
||||
for(i = 0; i < styleNodes.length; i++){
|
||||
var style = styleNodes[i].innerHTML;
|
||||
var sNode = win.document.createElement("style");
|
||||
sNode.appendChild(win.document.createTextNode(style));
|
||||
win.document.getElementsByTagName("head")[0].appendChild(sNode);
|
||||
}
|
||||
}
|
||||
win.print();
|
||||
win.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Register this plugin.
|
||||
_Plugin.registry["print"] = function(){
|
||||
return new Print({command: "print"});
|
||||
};
|
||||
|
||||
|
||||
return Print;
|
||||
});
|
||||
@@ -1,69 +0,0 @@
|
||||
define("dijit/_editor/plugins/TabIndent", [
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/_base/kernel", // kernel.experimental
|
||||
"../_Plugin",
|
||||
"../../form/ToggleButton"
|
||||
], function(declare, kernel, _Plugin, ToggleButton){
|
||||
|
||||
/*=====
|
||||
var _Plugin = dijit._editor._Plugin;
|
||||
=====*/
|
||||
|
||||
// module:
|
||||
// dijit/_editor/plugins/TabIndent
|
||||
// summary:
|
||||
// This plugin is used to allow the use of the tab and shift-tab keys
|
||||
// to indent/outdent list items. This overrides the default behavior
|
||||
// of moving focus from/to the toolbar
|
||||
|
||||
|
||||
kernel.experimental("dijit._editor.plugins.TabIndent");
|
||||
|
||||
|
||||
var TabIndent = declare("dijit._editor.plugins.TabIndent", _Plugin, {
|
||||
// summary:
|
||||
// This plugin is used to allow the use of the tab and shift-tab keys
|
||||
// to indent/outdent list items. This overrides the default behavior
|
||||
// of moving focus from/to the toolbar
|
||||
|
||||
// Override _Plugin.useDefaultCommand... processing is handled by this plugin, not by dijit.Editor.
|
||||
useDefaultCommand: false,
|
||||
|
||||
// Override _Plugin.buttonClass to use a ToggleButton for this plugin rather than a vanilla Button
|
||||
buttonClass: ToggleButton,
|
||||
|
||||
command: "tabIndent",
|
||||
|
||||
_initButton: function(){
|
||||
// Override _Plugin._initButton() to setup listener on button click
|
||||
this.inherited(arguments);
|
||||
|
||||
var e = this.editor;
|
||||
this.connect(this.button, "onChange", function(val){
|
||||
e.set("isTabIndent", val);
|
||||
});
|
||||
|
||||
// Set initial checked state of button based on Editor.isTabIndent
|
||||
this.updateState();
|
||||
},
|
||||
|
||||
updateState: function(){
|
||||
// Overrides _Plugin.updateState().
|
||||
// Ctrl-m in the editor will switch tabIndent mode on/off, so we need to react to that.
|
||||
var disabled = this.get("disabled");
|
||||
this.button.set("disabled", disabled);
|
||||
if(disabled){
|
||||
return;
|
||||
}
|
||||
this.button.set('checked', this.editor.isTabIndent, false);
|
||||
}
|
||||
});
|
||||
|
||||
// Register this plugin.
|
||||
_Plugin.registry["tabIndent"] = function(){
|
||||
return new TabIndent({command: "tabIndent"});
|
||||
};
|
||||
|
||||
|
||||
return TabIndent;
|
||||
});
|
||||
@@ -1,119 +0,0 @@
|
||||
define("dijit/_editor/plugins/TextColor", [
|
||||
"require",
|
||||
"dojo/colors", // colors.fromRgb
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/_base/lang",
|
||||
"../_Plugin",
|
||||
"../../form/DropDownButton"
|
||||
], function(require, colors, declare, lang, _Plugin, DropDownButton){
|
||||
|
||||
/*=====
|
||||
var _Plugin = dijit._editor._Plugin;
|
||||
=====*/
|
||||
|
||||
// module:
|
||||
// dijit/_editor/plugins/TextColor
|
||||
// summary:
|
||||
// This plugin provides dropdown color pickers for setting text color and background color
|
||||
|
||||
|
||||
var TextColor = declare("dijit._editor.plugins.TextColor", _Plugin, {
|
||||
// summary:
|
||||
// This plugin provides dropdown color pickers for setting text color and background color
|
||||
//
|
||||
// description:
|
||||
// The commands provided by this plugin are:
|
||||
// * foreColor - sets the text color
|
||||
// * hiliteColor - sets the background color
|
||||
|
||||
// Override _Plugin.buttonClass to use DropDownButton (with ColorPalette) to control this plugin
|
||||
buttonClass: DropDownButton,
|
||||
|
||||
// useDefaultCommand: Boolean
|
||||
// False as we do not use the default editor command/click behavior.
|
||||
useDefaultCommand: false,
|
||||
|
||||
_initButton: function(){
|
||||
this.inherited(arguments);
|
||||
|
||||
// Setup to lazy load ColorPalette first time the button is clicked
|
||||
var self = this;
|
||||
this.button.loadDropDown = function(callback){
|
||||
require(["../../ColorPalette"], lang.hitch(this, function(ColorPalette){
|
||||
this.dropDown = new ColorPalette({
|
||||
value: self.value,
|
||||
onChange: function(color){
|
||||
self.editor.execCommand(self.command, color);
|
||||
}
|
||||
});
|
||||
callback();
|
||||
}));
|
||||
};
|
||||
},
|
||||
|
||||
updateState: function(){
|
||||
// summary:
|
||||
// Overrides _Plugin.updateState(). This updates the ColorPalette
|
||||
// to show the color of the currently selected text.
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
var _e = this.editor;
|
||||
var _c = this.command;
|
||||
if(!_e || !_e.isLoaded || !_c.length){
|
||||
return;
|
||||
}
|
||||
|
||||
if(this.button){
|
||||
var disabled = this.get("disabled");
|
||||
this.button.set("disabled", disabled);
|
||||
if(disabled){ return; }
|
||||
|
||||
var value;
|
||||
try{
|
||||
value = _e.queryCommandValue(_c)|| "";
|
||||
}catch(e){
|
||||
//Firefox may throw error above if the editor is just loaded, ignore it
|
||||
value = "";
|
||||
}
|
||||
}
|
||||
|
||||
if(value == ""){
|
||||
value = "#000000";
|
||||
}
|
||||
if(value == "transparent"){
|
||||
value = "#ffffff";
|
||||
}
|
||||
|
||||
if(typeof value == "string"){
|
||||
//if RGB value, convert to hex value
|
||||
if(value.indexOf("rgb")> -1){
|
||||
value = colors.fromRgb(value).toHex();
|
||||
}
|
||||
}else{ //it's an integer(IE returns an MS access #)
|
||||
value =((value & 0x0000ff)<< 16)|(value & 0x00ff00)|((value & 0xff0000)>>> 16);
|
||||
value = value.toString(16);
|
||||
value = "#000000".slice(0, 7 - value.length)+ value;
|
||||
|
||||
}
|
||||
|
||||
this.value = value;
|
||||
|
||||
var dropDown = this.button.dropDown;
|
||||
if(dropDown && value !== dropDown.get('value')){
|
||||
dropDown.set('value', value, false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Register this plugin.
|
||||
_Plugin.registry["foreColor"] = function(){
|
||||
return new TextColor({command: "foreColor"});
|
||||
};
|
||||
_Plugin.registry["hiliteColor"] = function(){
|
||||
return new TextColor({command: "hiliteColor"});
|
||||
};
|
||||
|
||||
|
||||
return TextColor;
|
||||
});
|
||||
@@ -1,77 +0,0 @@
|
||||
define("dijit/_editor/plugins/ToggleDir", [
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom-style", // domStyle.getComputedStyle
|
||||
"dojo/_base/kernel", // kernel.experimental
|
||||
"dojo/_base/lang", // lang.hitch
|
||||
"../_Plugin",
|
||||
"../../form/ToggleButton"
|
||||
], function(declare, domStyle, kernel, lang, _Plugin, ToggleButton){
|
||||
|
||||
/*=====
|
||||
var _Plugin = dijit._editor._Plugin;
|
||||
=====*/
|
||||
|
||||
// module:
|
||||
// dijit/_editor/plugins/ToggleDir
|
||||
// summary:
|
||||
// This plugin is used to toggle direction of the edited document,
|
||||
// independent of what direction the whole page is.
|
||||
|
||||
|
||||
kernel.experimental("dijit._editor.plugins.ToggleDir");
|
||||
|
||||
var ToggleDir = declare("dijit._editor.plugins.ToggleDir", _Plugin, {
|
||||
// summary:
|
||||
// This plugin is used to toggle direction of the edited document,
|
||||
// independent of what direction the whole page is.
|
||||
|
||||
// Override _Plugin.useDefaultCommand: processing is done in this plugin
|
||||
// rather than by sending commands to the Editor
|
||||
useDefaultCommand: false,
|
||||
|
||||
command: "toggleDir",
|
||||
|
||||
// Override _Plugin.buttonClass to use a ToggleButton for this plugin rather than a vanilla Button
|
||||
buttonClass: ToggleButton,
|
||||
|
||||
_initButton: function(){
|
||||
// Override _Plugin._initButton() to setup handler for button click events.
|
||||
this.inherited(arguments);
|
||||
this.editor.onLoadDeferred.addCallback(lang.hitch(this, function(){
|
||||
var editDoc = this.editor.editorObject.contentWindow.document.documentElement;
|
||||
//IE direction has to toggle on the body, not document itself.
|
||||
//If you toggle just the document, things get very strange in the
|
||||
//view. But, the nice thing is this works for all supported browsers.
|
||||
editDoc = editDoc.getElementsByTagName("body")[0];
|
||||
var isLtr = domStyle.getComputedStyle(editDoc).direction == "ltr";
|
||||
this.button.set("checked", !isLtr);
|
||||
this.connect(this.button, "onChange", "_setRtl");
|
||||
}));
|
||||
},
|
||||
|
||||
updateState: function(){
|
||||
// summary:
|
||||
// Over-ride for button state control for disabled to work.
|
||||
this.button.set("disabled", this.get("disabled"));
|
||||
},
|
||||
|
||||
_setRtl: function(rtl){
|
||||
// summary:
|
||||
// Handler for button click events, to switch the text direction of the editor
|
||||
var dir = "ltr";
|
||||
if(rtl){
|
||||
dir = "rtl";
|
||||
}
|
||||
var editDoc = this.editor.editorObject.contentWindow.document.documentElement;
|
||||
editDoc = editDoc.getElementsByTagName("body")[0];
|
||||
editDoc.dir/*html node*/ = dir;
|
||||
}
|
||||
});
|
||||
|
||||
// Register this plugin.
|
||||
_Plugin.registry["toggleDir"] = function(){
|
||||
return new ToggleDir({command: "toggleDir"});
|
||||
};
|
||||
|
||||
return ToggleDir;
|
||||
});
|
||||
@@ -1,564 +0,0 @@
|
||||
define("dijit/_editor/plugins/ViewSource", [
|
||||
"dojo/_base/array", // array.forEach
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom-attr", // domAttr.set
|
||||
"dojo/dom-construct", // domConstruct.create domConstruct.place
|
||||
"dojo/dom-geometry", // domGeometry.setMarginBox domGeometry.position
|
||||
"dojo/dom-style", // domStyle.set
|
||||
"dojo/_base/event", // event.stop
|
||||
"dojo/i18n", // i18n.getLocalization
|
||||
"dojo/keys", // keys.F12
|
||||
"dojo/_base/lang", // lang.hitch
|
||||
"dojo/on", // on()
|
||||
"dojo/_base/sniff", // has("ie") has("webkit")
|
||||
"dojo/_base/window", // win.body win.global
|
||||
"dojo/window", // winUtils.getBox
|
||||
"../../focus", // focus.focus()
|
||||
"../_Plugin",
|
||||
"../../form/ToggleButton",
|
||||
"../..", // dijit._scopeName
|
||||
"../../registry", // registry.getEnclosingWidget()
|
||||
"dojo/i18n!../nls/commands"
|
||||
], function(array, declare, domAttr, domConstruct, domGeometry, domStyle, event, i18n, keys, lang, on, has, win,
|
||||
winUtils, focus, _Plugin, ToggleButton, dijit, registry){
|
||||
|
||||
/*=====
|
||||
var _Plugin = dijit._editor._Plugin;
|
||||
=====*/
|
||||
|
||||
// module:
|
||||
// dijit/_editor/plugins/ViewSource
|
||||
// summary:
|
||||
// This plugin provides a simple view source capability.
|
||||
|
||||
|
||||
var ViewSource = declare("dijit._editor.plugins.ViewSource",_Plugin, {
|
||||
// summary:
|
||||
// This plugin provides a simple view source capability. When view
|
||||
// source mode is enabled, it disables all other buttons/plugins on the RTE.
|
||||
// It also binds to the hotkey: CTRL-SHIFT-F11 for toggling ViewSource mode.
|
||||
|
||||
// stripScripts: [public] Boolean
|
||||
// Boolean flag used to indicate if script tags should be stripped from the document.
|
||||
// Defaults to true.
|
||||
stripScripts: true,
|
||||
|
||||
// stripComments: [public] Boolean
|
||||
// Boolean flag used to indicate if comment tags should be stripped from the document.
|
||||
// Defaults to true.
|
||||
stripComments: true,
|
||||
|
||||
// stripComments: [public] Boolean
|
||||
// Boolean flag used to indicate if iframe tags should be stripped from the document.
|
||||
// Defaults to true.
|
||||
stripIFrames: true,
|
||||
|
||||
// readOnly: [const] Boolean
|
||||
// Boolean flag used to indicate if the source view should be readonly or not.
|
||||
// Cannot be changed after initialization of the plugin.
|
||||
// Defaults to false.
|
||||
readOnly: false,
|
||||
|
||||
// _fsPlugin: [private] Object
|
||||
// Reference to a registered fullscreen plugin so that viewSource knows
|
||||
// how to scale.
|
||||
_fsPlugin: null,
|
||||
|
||||
toggle: function(){
|
||||
// summary:
|
||||
// Function to allow programmatic toggling of the view.
|
||||
|
||||
// For Webkit, we have to focus a very particular way.
|
||||
// when swapping views, otherwise focus doesn't shift right
|
||||
// but can't focus this way all the time, only for VS changes.
|
||||
// If we did it all the time, buttons like bold, italic, etc
|
||||
// break.
|
||||
if(has("webkit")){this._vsFocused = true;}
|
||||
this.button.set("checked", !this.button.get("checked"));
|
||||
|
||||
},
|
||||
|
||||
_initButton: function(){
|
||||
// summary:
|
||||
// Over-ride for creation of the resize button.
|
||||
var strings = i18n.getLocalization("dijit._editor", "commands"),
|
||||
editor = this.editor;
|
||||
this.button = new ToggleButton({
|
||||
label: strings["viewSource"],
|
||||
dir: editor.dir,
|
||||
lang: editor.lang,
|
||||
showLabel: false,
|
||||
iconClass: this.iconClassPrefix + " " + this.iconClassPrefix + "ViewSource",
|
||||
tabIndex: "-1",
|
||||
onChange: lang.hitch(this, "_showSource")
|
||||
});
|
||||
|
||||
// IE 7 has a horrible bug with zoom, so we have to create this node
|
||||
// to cross-check later. Sigh.
|
||||
if(has("ie") == 7){
|
||||
this._ieFixNode = domConstruct.create("div", {
|
||||
style: {
|
||||
opacity: "0",
|
||||
zIndex: "-1000",
|
||||
position: "absolute",
|
||||
top: "-1000px"
|
||||
}
|
||||
}, win.body());
|
||||
}
|
||||
// Make sure readonly mode doesn't make the wrong cursor appear over the button.
|
||||
this.button.set("readOnly", false);
|
||||
},
|
||||
|
||||
|
||||
setEditor: function(/*dijit.Editor*/ editor){
|
||||
// summary:
|
||||
// Tell the plugin which Editor it is associated with.
|
||||
// editor: Object
|
||||
// The editor object to attach the print capability to.
|
||||
this.editor = editor;
|
||||
this._initButton();
|
||||
|
||||
this.editor.addKeyHandler(keys.F12, true, true, lang.hitch(this, function(e){
|
||||
// Move the focus before switching
|
||||
// It'll focus back. Hiding a focused
|
||||
// node causes issues.
|
||||
this.button.focus();
|
||||
this.toggle();
|
||||
event.stop(e);
|
||||
|
||||
// Call the focus shift outside of the handler.
|
||||
setTimeout(lang.hitch(this, function(){
|
||||
// We over-ride focus, so we just need to call.
|
||||
this.editor.focus();
|
||||
}), 100);
|
||||
}));
|
||||
},
|
||||
|
||||
_showSource: function(source){
|
||||
// summary:
|
||||
// Function to toggle between the source and RTE views.
|
||||
// source: boolean
|
||||
// Boolean value indicating if it should be in source mode or not.
|
||||
// tags:
|
||||
// private
|
||||
var ed = this.editor;
|
||||
var edPlugins = ed._plugins;
|
||||
var html;
|
||||
this._sourceShown = source;
|
||||
var self = this;
|
||||
try{
|
||||
if(!this.sourceArea){
|
||||
this._createSourceView();
|
||||
}
|
||||
if(source){
|
||||
// Update the QueryCommandEnabled function to disable everything but
|
||||
// the source view mode. Have to over-ride a function, then kick all
|
||||
// plugins to check their state.
|
||||
ed._sourceQueryCommandEnabled = ed.queryCommandEnabled;
|
||||
ed.queryCommandEnabled = function(cmd){
|
||||
return cmd.toLowerCase() === "viewsource";
|
||||
};
|
||||
this.editor.onDisplayChanged();
|
||||
html = ed.get("value");
|
||||
html = this._filter(html);
|
||||
ed.set("value", html);
|
||||
array.forEach(edPlugins, function(p){
|
||||
// Turn off any plugins not controlled by queryCommandenabled.
|
||||
if(!(p instanceof ViewSource)){
|
||||
p.set("disabled", true)
|
||||
}
|
||||
});
|
||||
|
||||
// We actually do need to trap this plugin and adjust how we
|
||||
// display the textarea.
|
||||
if(this._fsPlugin){
|
||||
this._fsPlugin._getAltViewNode = function(){
|
||||
return self.sourceArea;
|
||||
};
|
||||
}
|
||||
|
||||
this.sourceArea.value = html;
|
||||
|
||||
// Since neither iframe nor textarea have margin, border, or padding,
|
||||
// just set sizes equal
|
||||
this.sourceArea.style.height = ed.iframe.style.height;
|
||||
this.sourceArea.style.width = ed.iframe.style.width;
|
||||
domStyle.set(ed.iframe, "display", "none");
|
||||
domStyle.set(this.sourceArea, {
|
||||
display: "block"
|
||||
});
|
||||
|
||||
var resizer = function(){
|
||||
// function to handle resize events.
|
||||
// Will check current VP and only resize if
|
||||
// different.
|
||||
var vp = winUtils.getBox();
|
||||
|
||||
if("_prevW" in this && "_prevH" in this){
|
||||
// No actual size change, ignore.
|
||||
if(vp.w === this._prevW && vp.h === this._prevH){
|
||||
return;
|
||||
}else{
|
||||
this._prevW = vp.w;
|
||||
this._prevH = vp.h;
|
||||
}
|
||||
}else{
|
||||
this._prevW = vp.w;
|
||||
this._prevH = vp.h;
|
||||
}
|
||||
if(this._resizer){
|
||||
clearTimeout(this._resizer);
|
||||
delete this._resizer;
|
||||
}
|
||||
// Timeout it to help avoid spamming resize on IE.
|
||||
// Works for all browsers.
|
||||
this._resizer = setTimeout(lang.hitch(this, function(){
|
||||
delete this._resizer;
|
||||
this._resize();
|
||||
}), 10);
|
||||
};
|
||||
this._resizeHandle = on(window, "resize", lang.hitch(this, resizer));
|
||||
|
||||
//Call this on a delay once to deal with IE glitchiness on initial size.
|
||||
setTimeout(lang.hitch(this, this._resize), 100);
|
||||
|
||||
//Trigger a check for command enablement/disablement.
|
||||
this.editor.onNormalizedDisplayChanged();
|
||||
|
||||
this.editor.__oldGetValue = this.editor.getValue;
|
||||
this.editor.getValue = lang.hitch(this, function(){
|
||||
var txt = this.sourceArea.value;
|
||||
txt = this._filter(txt);
|
||||
return txt;
|
||||
});
|
||||
}else{
|
||||
// First check that we were in source view before doing anything.
|
||||
// corner case for being called with a value of false and we hadn't
|
||||
// actually been in source display mode.
|
||||
if(!ed._sourceQueryCommandEnabled){
|
||||
return;
|
||||
}
|
||||
this._resizeHandle.remove();
|
||||
delete this._resizeHandle;
|
||||
|
||||
if(this.editor.__oldGetValue){
|
||||
this.editor.getValue = this.editor.__oldGetValue;
|
||||
delete this.editor.__oldGetValue;
|
||||
}
|
||||
|
||||
// Restore all the plugin buttons state.
|
||||
ed.queryCommandEnabled = ed._sourceQueryCommandEnabled;
|
||||
if(!this._readOnly){
|
||||
html = this.sourceArea.value;
|
||||
html = this._filter(html);
|
||||
ed.beginEditing();
|
||||
ed.set("value", html);
|
||||
ed.endEditing();
|
||||
}
|
||||
|
||||
array.forEach(edPlugins, function(p){
|
||||
// Turn back on any plugins we turned off.
|
||||
p.set("disabled", false);
|
||||
});
|
||||
|
||||
domStyle.set(this.sourceArea, "display", "none");
|
||||
domStyle.set(ed.iframe, "display", "block");
|
||||
delete ed._sourceQueryCommandEnabled;
|
||||
|
||||
//Trigger a check for command enablement/disablement.
|
||||
this.editor.onDisplayChanged();
|
||||
}
|
||||
// Call a delayed resize to wait for some things to display in header/footer.
|
||||
setTimeout(lang.hitch(this, function(){
|
||||
// Make resize calls.
|
||||
var parent = ed.domNode.parentNode;
|
||||
if(parent){
|
||||
var container = registry.getEnclosingWidget(parent);
|
||||
if(container && container.resize){
|
||||
container.resize();
|
||||
}
|
||||
}
|
||||
ed.resize();
|
||||
}), 300);
|
||||
}catch(e){
|
||||
console.log(e);
|
||||
}
|
||||
},
|
||||
|
||||
updateState: function(){
|
||||
// summary:
|
||||
// Over-ride for button state control for disabled to work.
|
||||
this.button.set("disabled", this.get("disabled"));
|
||||
},
|
||||
|
||||
_resize: function(){
|
||||
// summary:
|
||||
// Internal function to resize the source view
|
||||
// tags:
|
||||
// private
|
||||
var ed = this.editor;
|
||||
var tbH = ed.getHeaderHeight();
|
||||
var fH = ed.getFooterHeight();
|
||||
var eb = domGeometry.position(ed.domNode);
|
||||
|
||||
// Styles are now applied to the internal source container, so we have
|
||||
// to subtract them off.
|
||||
var containerPadding = domGeometry.getPadBorderExtents(ed.iframe.parentNode);
|
||||
var containerMargin = domGeometry.getMarginExtents(ed.iframe.parentNode);
|
||||
|
||||
var extents = domGeometry.getPadBorderExtents(ed.domNode);
|
||||
var edb = {
|
||||
w: eb.w - extents.w,
|
||||
h: eb.h - (tbH + extents.h + + fH)
|
||||
};
|
||||
|
||||
// Fullscreen gets odd, so we need to check for the FS plugin and
|
||||
// adapt.
|
||||
if(this._fsPlugin && this._fsPlugin.isFullscreen){
|
||||
//Okay, probably in FS, adjust.
|
||||
var vp = winUtils.getBox();
|
||||
edb.w = (vp.w - extents.w);
|
||||
edb.h = (vp.h - (tbH + extents.h + fH));
|
||||
}
|
||||
|
||||
if(has("ie")){
|
||||
// IE is always off by 2px, so we have to adjust here
|
||||
// Note that IE ZOOM is broken here. I can't get
|
||||
//it to scale right.
|
||||
edb.h -= 2;
|
||||
}
|
||||
|
||||
// IE has a horrible zoom bug. So, we have to try and account for
|
||||
// it and fix up the scaling.
|
||||
if(this._ieFixNode){
|
||||
var _ie7zoom = -this._ieFixNode.offsetTop / 1000;
|
||||
edb.w = Math.floor((edb.w + 0.9) / _ie7zoom);
|
||||
edb.h = Math.floor((edb.h + 0.9) / _ie7zoom);
|
||||
}
|
||||
|
||||
domGeometry.setMarginBox(this.sourceArea, {
|
||||
w: edb.w - (containerPadding.w + containerMargin.w),
|
||||
h: edb.h - (containerPadding.h + containerMargin.h)
|
||||
});
|
||||
|
||||
// Scale the parent container too in this case.
|
||||
domGeometry.setMarginBox(ed.iframe.parentNode, {
|
||||
h: edb.h
|
||||
});
|
||||
},
|
||||
|
||||
_createSourceView: function(){
|
||||
// summary:
|
||||
// Internal function for creating the source view area.
|
||||
// tags:
|
||||
// private
|
||||
var ed = this.editor;
|
||||
var edPlugins = ed._plugins;
|
||||
this.sourceArea = domConstruct.create("textarea");
|
||||
if(this.readOnly){
|
||||
domAttr.set(this.sourceArea, "readOnly", true);
|
||||
this._readOnly = true;
|
||||
}
|
||||
domStyle.set(this.sourceArea, {
|
||||
padding: "0px",
|
||||
margin: "0px",
|
||||
borderWidth: "0px",
|
||||
borderStyle: "none"
|
||||
});
|
||||
domConstruct.place(this.sourceArea, ed.iframe, "before");
|
||||
|
||||
if(has("ie") && ed.iframe.parentNode.lastChild !== ed.iframe){
|
||||
// There's some weirdo div in IE used for focus control
|
||||
// But is messed up scaling the textarea if we don't config
|
||||
// it some so it doesn't have a varying height.
|
||||
domStyle.set(ed.iframe.parentNode.lastChild,{
|
||||
width: "0px",
|
||||
height: "0px",
|
||||
padding: "0px",
|
||||
margin: "0px",
|
||||
borderWidth: "0px",
|
||||
borderStyle: "none"
|
||||
});
|
||||
}
|
||||
|
||||
// We also need to take over editor focus a bit here, so that focus calls to
|
||||
// focus the editor will focus to the right node when VS is active.
|
||||
ed._viewsource_oldFocus = ed.focus;
|
||||
var self = this;
|
||||
ed.focus = function(){
|
||||
if(self._sourceShown){
|
||||
self.setSourceAreaCaret();
|
||||
}else{
|
||||
try{
|
||||
if(this._vsFocused){
|
||||
delete this._vsFocused;
|
||||
// Must focus edit node in this case (webkit only) or
|
||||
// focus doesn't shift right, but in normal
|
||||
// cases we focus with the regular function.
|
||||
focus.focus(ed.editNode);
|
||||
}else{
|
||||
ed._viewsource_oldFocus();
|
||||
}
|
||||
}catch(e){
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var i, p;
|
||||
for(i = 0; i < edPlugins.length; i++){
|
||||
// We actually do need to trap this plugin and adjust how we
|
||||
// display the textarea.
|
||||
p = edPlugins[i];
|
||||
if(p && (p.declaredClass === "dijit._editor.plugins.FullScreen" ||
|
||||
p.declaredClass === (dijit._scopeName +
|
||||
"._editor.plugins.FullScreen"))){
|
||||
this._fsPlugin = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(this._fsPlugin){
|
||||
// Found, we need to over-ride the alt-view node function
|
||||
// on FullScreen with our own, chain up to parent call when appropriate.
|
||||
this._fsPlugin._viewsource_getAltViewNode = this._fsPlugin._getAltViewNode;
|
||||
this._fsPlugin._getAltViewNode = function(){
|
||||
return self._sourceShown?self.sourceArea:this._viewsource_getAltViewNode();
|
||||
};
|
||||
}
|
||||
|
||||
// Listen to the source area for key events as well, as we need to be able to hotkey toggle
|
||||
// it from there too.
|
||||
this.connect(this.sourceArea, "onkeydown", lang.hitch(this, function(e){
|
||||
if(this._sourceShown && e.keyCode == keys.F12 && e.ctrlKey && e.shiftKey){
|
||||
this.button.focus();
|
||||
this.button.set("checked", false);
|
||||
setTimeout(lang.hitch(this, function(){ed.focus();}), 100);
|
||||
event.stop(e);
|
||||
}
|
||||
}));
|
||||
},
|
||||
|
||||
_stripScripts: function(html){
|
||||
// summary:
|
||||
// Strips out script tags from the HTML used in editor.
|
||||
// html: String
|
||||
// The HTML to filter
|
||||
// tags:
|
||||
// private
|
||||
if(html){
|
||||
// Look for closed and unclosed (malformed) script attacks.
|
||||
html = html.replace(/<\s*script[^>]*>((.|\s)*?)<\\?\/\s*script\s*>/ig, "");
|
||||
html = html.replace(/<\s*script\b([^<>]|\s)*>?/ig, "");
|
||||
html = html.replace(/<[^>]*=(\s|)*[("|')]javascript:[^$1][(\s|.)]*[$1][^>]*>/ig, "");
|
||||
}
|
||||
return html;
|
||||
},
|
||||
|
||||
_stripComments: function(html){
|
||||
// summary:
|
||||
// Strips out comments from the HTML used in editor.
|
||||
// html: String
|
||||
// The HTML to filter
|
||||
// tags:
|
||||
// private
|
||||
if(html){
|
||||
html = html.replace(/<!--(.|\s){1,}?-->/g, "");
|
||||
}
|
||||
return html;
|
||||
},
|
||||
|
||||
_stripIFrames: function(html){
|
||||
// summary:
|
||||
// Strips out iframe tags from the content, to avoid iframe script
|
||||
// style injection attacks.
|
||||
// html: String
|
||||
// The HTML to filter
|
||||
// tags:
|
||||
// private
|
||||
if(html){
|
||||
html = html.replace(/<\s*iframe[^>]*>((.|\s)*?)<\\?\/\s*iframe\s*>/ig, "");
|
||||
}
|
||||
return html;
|
||||
},
|
||||
|
||||
_filter: function(html){
|
||||
// summary:
|
||||
// Internal function to perform some filtering on the HTML.
|
||||
// html: String
|
||||
// The HTML to filter
|
||||
// tags:
|
||||
// private
|
||||
if(html){
|
||||
if(this.stripScripts){
|
||||
html = this._stripScripts(html);
|
||||
}
|
||||
if(this.stripComments){
|
||||
html = this._stripComments(html);
|
||||
}
|
||||
if(this.stripIFrames){
|
||||
html = this._stripIFrames(html);
|
||||
}
|
||||
}
|
||||
return html;
|
||||
},
|
||||
|
||||
setSourceAreaCaret: function(){
|
||||
// summary:
|
||||
// Internal function to set the caret in the sourceArea
|
||||
// to 0x0
|
||||
var global = win.global;
|
||||
var elem = this.sourceArea;
|
||||
focus.focus(elem);
|
||||
if(this._sourceShown && !this.readOnly){
|
||||
if(has("ie")){
|
||||
if(this.sourceArea.createTextRange){
|
||||
var range = elem.createTextRange();
|
||||
range.collapse(true);
|
||||
range.moveStart("character", -99999); // move to 0
|
||||
range.moveStart("character", 0); // delta from 0 is the correct position
|
||||
range.moveEnd("character", 0);
|
||||
range.select();
|
||||
}
|
||||
}else if(global.getSelection){
|
||||
if(elem.setSelectionRange){
|
||||
elem.setSelectionRange(0,0);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
destroy: function(){
|
||||
// summary:
|
||||
// Over-ride to remove the node used to correct for IE's
|
||||
// zoom bug.
|
||||
if(this._ieFixNode){
|
||||
win.body().removeChild(this._ieFixNode);
|
||||
}
|
||||
if(this._resizer){
|
||||
clearTimeout(this._resizer);
|
||||
delete this._resizer;
|
||||
}
|
||||
if(this._resizeHandle){
|
||||
this._resizeHandle.remove();
|
||||
delete this._resizeHandle;
|
||||
}
|
||||
this.inherited(arguments);
|
||||
}
|
||||
});
|
||||
|
||||
// Register this plugin.
|
||||
// For back-compat accept "viewsource" (all lowercase) too, remove in 2.0
|
||||
_Plugin.registry["viewSource"] = _Plugin.registry["viewsource"] = function(args){
|
||||
return new ViewSource({
|
||||
readOnly: ("readOnly" in args)?args.readOnly:false,
|
||||
stripComments: ("stripComments" in args)?args.stripComments:true,
|
||||
stripScripts: ("stripScripts" in args)?args.stripScripts:true,
|
||||
stripIFrames: ("stripIFrames" in args)?args.stripIFrames:true
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
return ViewSource;
|
||||
});
|
||||
Reference in New Issue
Block a user