236 lines
7.2 KiB
JavaScript
236 lines
7.2 KiB
JavaScript
//>>built
|
|
define("dojox/editor/plugins/AutoUrlLink", [
|
|
"dojo",
|
|
"dijit",
|
|
"dojox",
|
|
"dijit/_editor/range",
|
|
"dijit/_editor/selection",
|
|
"dijit/_editor/_Plugin",
|
|
"dijit/form/Button",
|
|
"dojo/_base/connect",
|
|
"dojo/_base/declare",
|
|
"dojo/string"
|
|
], function(dojo, dijit, dojox) {
|
|
|
|
dojo.declare("dojox.editor.plugins.AutoUrlLink", [dijit._editor._Plugin], {
|
|
//summary:
|
|
// This plugin can recognize a URL like string
|
|
// (such as http://www.website.com) and turn it into
|
|
// a hyperlink that points to that URL.
|
|
|
|
// _template [private] String
|
|
// The link template
|
|
_template: "<a _djrealurl='${url}' href='${url}'>${url}</a>",
|
|
|
|
setEditor: function(/*dijit.Editor*/ editor){
|
|
// summary:
|
|
// Called by the editor it belongs to.
|
|
// editor:
|
|
// The editor it belongs to.
|
|
this.editor = editor;
|
|
if(!dojo.isIE){
|
|
// IE will recognize URL as a link automatically
|
|
// No need to re-invent the wheel.
|
|
dojo.some(editor._plugins, function(plugin){
|
|
// Need to detect which enter key mode it is now
|
|
if(plugin.isInstanceOf(dijit._editor.plugins.EnterKeyHandling)){
|
|
this.blockNodeForEnter = plugin.blockNodeForEnter;
|
|
return true;
|
|
}
|
|
return false;
|
|
}, this);
|
|
this.connect(editor, "onKeyPress", "_keyPress");
|
|
this.connect(editor, "onClick", "_recognize");
|
|
this.connect(editor, "onBlur", "_recognize");
|
|
}
|
|
},
|
|
|
|
_keyPress: function(evt){
|
|
// summary:
|
|
// Handle the keypress event and dispatch it to the target handler
|
|
// evt:
|
|
// The keypress event object.
|
|
// tags:
|
|
// protected
|
|
var ks = dojo.keys, v = 118, V = 86,
|
|
kc = evt.keyCode, cc = evt.charCode;
|
|
if(cc == ks.SPACE || (evt.ctrlKey && (cc == v || cc == V))){
|
|
setTimeout(dojo.hitch(this, "_recognize"), 0);
|
|
}else if(kc == ks.ENTER){
|
|
// Handle the enter event after EnterKeyHandling finishes its job
|
|
setTimeout(dojo.hitch(this, function(){
|
|
this._recognize({enter: true});
|
|
}), 0);
|
|
}else{
|
|
// _saved: The previous dom node when the cursor is at a new dom node.
|
|
// When we click elsewhere, the previous dom node
|
|
// should be examed to see if there is any URL need to be activated
|
|
this._saved = this.editor.window.getSelection().anchorNode;
|
|
}
|
|
},
|
|
|
|
_recognize: function(args){
|
|
// summary:
|
|
// Recognize the URL like strings and turn them into a link
|
|
// tags:
|
|
// private
|
|
var template = this._template,
|
|
isEnter = args ? args.enter : false,
|
|
ed = this.editor,
|
|
selection = ed.window.getSelection();
|
|
if(selection){
|
|
var node = isEnter ? this._findLastEditingNode(selection.anchorNode) :
|
|
(this._saved || selection.anchorNode),
|
|
bm = this._saved = selection.anchorNode,
|
|
bmOff = selection.anchorOffset;
|
|
|
|
if(node.nodeType == 3 && !this._inLink(node)){
|
|
var linked = false, result = this._findUrls(node, bm, bmOff),
|
|
range = ed.document.createRange(),
|
|
item, cost = 0, isSameNode = (bm == node);
|
|
|
|
item = result.shift();
|
|
while(item){
|
|
// Covert a URL to a link.
|
|
range.setStart(node, item.start);
|
|
range.setEnd(node, item.end);
|
|
selection.removeAllRanges();
|
|
selection.addRange(range);
|
|
ed.execCommand("insertHTML", dojo.string.substitute(template, {url: range.toString()}));
|
|
cost += item.end;
|
|
item = result.shift();
|
|
linked = true;
|
|
}
|
|
|
|
// If bm and node are the some dom node, caculate the actual bookmark offset
|
|
// If the position of the cursor is modified (turned into a link, etc.), no
|
|
// need to recover the cursor position
|
|
if(isSameNode && (bmOff = bmOff - cost) <= 0){ return; }
|
|
|
|
// We didn't update anything, so don't collapse selections.
|
|
if(!linked) { return ; }
|
|
try{
|
|
// Try to recover the cursor position
|
|
range.setStart(bm, 0);
|
|
range.setEnd(bm, bmOff);
|
|
selection.removeAllRanges();
|
|
selection.addRange(range);
|
|
dojo.withGlobal(ed.window, "collapse", dijit._editor.selection, []);
|
|
}catch(e){}
|
|
}
|
|
}
|
|
},
|
|
|
|
_inLink: function(/*DomNode*/ node){
|
|
// summary:
|
|
// Check if the node is already embraced within a <a>...</a> tag.
|
|
// node:
|
|
// The node to be examed.
|
|
// tags:
|
|
// private
|
|
var editNode = this.editor.editNode,
|
|
result = false, tagName;
|
|
|
|
node = node.parentNode;
|
|
while(node && node !== editNode){
|
|
tagName = node.tagName ? node.tagName.toLowerCase() : "";
|
|
if(tagName == "a"){
|
|
result = true;
|
|
break;
|
|
}
|
|
node = node.parentNode;
|
|
}
|
|
return result;
|
|
},
|
|
|
|
_findLastEditingNode: function(/*DomNode*/ node){
|
|
// summary:
|
|
// Find the last node that was edited so that we can
|
|
// get the last edited text.
|
|
// node:
|
|
// The current node that the cursor is at.
|
|
// tags:
|
|
// private
|
|
var blockTagNames = dijit.range.BlockTagNames,
|
|
editNode = this.editor.editNode, blockNode;
|
|
|
|
if(!node){ return node; }
|
|
if(this.blockNodeForEnter == "BR" &&
|
|
(!(blockNode = dijit.range.getBlockAncestor(node, null, editNode).blockNode) ||
|
|
blockNode.tagName.toUpperCase() != "LI")){
|
|
while((node = node.previousSibling) && node.nodeType != 3){}
|
|
}else{
|
|
// EnterKeyHandling is under "DIV" or "P" mode or
|
|
// it's in a LI element. Find the last editing block
|
|
if((blockNode || (blockNode = dijit.range.getBlockAncestor(node, null, editNode).blockNode)) &&
|
|
blockNode.tagName.toUpperCase() == "LI"){
|
|
node = blockNode;
|
|
}else{
|
|
node = dijit.range.getBlockAncestor(node, null, editNode).blockNode;
|
|
}
|
|
// Find the last editing text node
|
|
while((node = node.previousSibling) && !(node.tagName && node.tagName.match(blockTagNames))){}
|
|
if(node){
|
|
node = node.lastChild;
|
|
while(node){
|
|
if(node.nodeType == 3 && dojo.trim(node.nodeValue) != ""){
|
|
break;
|
|
}else if(node.nodeType == 1){
|
|
node = node.lastChild;
|
|
}else{
|
|
node = node.previousSibling;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return node;
|
|
},
|
|
|
|
_findUrls: function(/*DomNode*/ node, /*DomNode*/ bm, /*Number*/ bmOff){
|
|
// summary:
|
|
// Find the occurrace of the URL strings.
|
|
// FF, Chrome && Safri have a behavior that when insertHTML is executed,
|
|
// the orignal referrence to the text node will be the text node next to
|
|
// the inserted anchor automatically. So we have to re-caculate the index of
|
|
// the following URL occurrence.
|
|
// value:
|
|
// A text to be scanned.
|
|
// tags:
|
|
// private
|
|
var pattern = /(http|https|ftp):\/\/[^\s]+/ig,
|
|
list = [], baseIndex = 0,
|
|
value = node.nodeValue, result, ch;
|
|
|
|
if(node === bm && bmOff < value.length){
|
|
// Break the text so that it may not grab extra words.
|
|
// Such as if you type:
|
|
// foo http://foo.com|bar (And | is where you press enter).
|
|
// It will grab the bar word as part of the link. That's annoying/bad.
|
|
// Also it prevents recognizing the text after the cursor.
|
|
value = value.substr(0, bmOff);
|
|
}
|
|
|
|
while((result = pattern.exec(value)) != null){
|
|
if(result.index == 0 || (ch = value.charAt(result.index - 1)) == " " || ch == "\xA0"){
|
|
list.push({start: result.index - baseIndex, end: result.index + result[0].length - baseIndex});
|
|
baseIndex = result.index + result[0].length;
|
|
}
|
|
}
|
|
|
|
return list;
|
|
}
|
|
});
|
|
|
|
// Register this plugin.
|
|
dojo.subscribe(dijit._scopeName + ".Editor.getPlugin",null,function(o){
|
|
if(o.plugin){ return; }
|
|
var name = o.args.name.toLowerCase();
|
|
if(name === "autourllink"){
|
|
o.plugin = new dojox.editor.plugins.AutoUrlLink();
|
|
}
|
|
});
|
|
|
|
return dojox.editor.plugins.AutoUrlLink;
|
|
|
|
});
|