/* Copyright (c) 2004-2012, The Dojo Foundation All Rights Reserved. Available via Academic Free License >= 2.1 OR the modified BSD license. see: http://dojotoolkit.org/license for details */ if(!dojo._hasResource["dojox.editor.plugins.AutoUrlLink"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["dojox.editor.plugins.AutoUrlLink"] = true; dojo.provide("dojox.editor.plugins.AutoUrlLink"); dojo.require("dojo.string"); dojo.require("dijit._editor._Plugin"); dojo.require("dijit.form.Button"); 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: "${url}", 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 ... 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(); } }); }