source: Dev/trunk/src/client/dojox/editor/plugins/AutoUrlLink.js

Last change on this file was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

File size: 7.2 KB
Line 
1define([
2        "dojo",
3        "dijit",
4        "dojox",
5        "dijit/_editor/_Plugin",
6        "dijit/form/Button",
7        "dojo/_base/declare",
8        "dojo/string"
9], function(dojo, dijit, dojox, _Plugin) {
10
11var AutoUrlLink = dojo.declare("dojox.editor.plugins.AutoUrlLink", [_Plugin], {
12        // summary:
13        //              This plugin can recognize a URL like string
14        //              (such as http://www.website.com) and turn it into
15        //              a hyperlink that points to that URL.
16       
17        // _template: [private] String
18        //              The link template
19        _template: "<a _djrealurl='${url}' href='${url}'>${url}</a>",
20       
21        setEditor: function(/*dijit.Editor*/ editor){
22                // summary:
23                //              Called by the editor it belongs to.
24                // editor:
25                //              The editor it belongs to.
26                this.editor = editor;
27                if(!dojo.isIE){
28                        // IE will recognize URL as a link automatically
29                        // No need to re-invent the wheel.
30                        dojo.some(editor._plugins, function(plugin){
31                                // Need to detect which enter key mode it is now
32                                if(plugin.isInstanceOf(dijit._editor.plugins.EnterKeyHandling)){
33                                        this.blockNodeForEnter = plugin.blockNodeForEnter;
34                                        return true;
35                                }
36                                return false;
37                        }, this);
38                        this.connect(editor, "onKeyPress", "_keyPress");
39                        this.connect(editor, "onClick", "_recognize");
40                        this.connect(editor, "onBlur", "_recognize");
41                }
42        },
43       
44        _keyPress: function(evt){
45                // summary:
46                //              Handle the keypress event and dispatch it to the target handler
47                // evt:
48                //              The keypress event object.
49                // tags:
50                //              protected
51                var ks = dojo.keys, v = 118, V = 86,
52                        kc = evt.keyCode, cc = evt.charCode;
53                if(cc == ks.SPACE || (evt.ctrlKey && (cc == v || cc == V))){
54                        setTimeout(dojo.hitch(this, "_recognize"), 0);
55                }else if(kc == ks.ENTER){
56                        // Handle the enter event after EnterKeyHandling finishes its job
57                        setTimeout(dojo.hitch(this, function(){
58                                this._recognize({enter: true});
59                        }), 0);
60                }else{
61                        // _saved: The previous dom node when the cursor is at a new dom node.
62                        // When we click elsewhere, the previous dom node
63                        // should be examed to see if there is any URL need to be activated
64                        this._saved = this.editor.window.getSelection().anchorNode;
65                }
66        },
67       
68        _recognize: function(args){
69                // summary:
70                //              Recognize the URL like strings and turn them into a link
71                // tags:
72                //              private
73                var template = this._template,
74                        isEnter = args ? args.enter : false,
75                        ed = this.editor,
76                        selection = ed.window.getSelection();
77                console.log("_recognize: isEnter = ", isEnter, ", selection is ", selection,  selection.anchorNode, this._findLastEditingNode(selection.anchorNode))
78                        if(selection){
79                                var node = isEnter ? this._findLastEditingNode(selection.anchorNode) :
80                                                                (this._saved || selection.anchorNode),
81                                bm = this._saved = selection.anchorNode,
82                                bmOff = selection.anchorOffset;
83                       
84                        if(node.nodeType == 3 && !this._inLink(node)){
85                                var linked = false, result = this._findUrls(node, bm, bmOff),
86                                        range = ed.document.createRange(),
87                                        item, cost = 0, isSameNode = (bm == node);
88                                               
89                                item = result.shift();
90                                while(item){
91                                        // Covert a URL to a link.
92                                        range.setStart(node, item.start);
93                                        range.setEnd(node, item.end);
94                                        selection.removeAllRanges();
95                                        selection.addRange(range);
96                                        ed.execCommand("insertHTML", dojo.string.substitute(template, {url: range.toString()}));
97                                        cost += item.end;
98                                        item = result.shift();
99                                        linked = true;
100                                }
101                               
102                                // If bm and node are the some dom node, caculate the actual bookmark offset
103                                // If the position of the cursor is modified (turned into a link, etc.), no
104                                // need to recover the cursor position
105                                if(isSameNode && (bmOff = bmOff - cost) <= 0){ return; }
106       
107                                // We didn't update anything, so don't collapse selections.
108                                if(!linked) { return ; }
109                                try{
110                                        // Try to recover the cursor position
111                                        range.setStart(bm, 0);
112                                        range.setEnd(bm, bmOff);
113                                        selection.removeAllRanges();
114                                        selection.addRange(range);
115                                        ed._sCall("collapse", []);
116                                }catch(e){}
117                        }
118                }
119        },
120       
121        _inLink: function(/*DomNode*/ node){
122                // summary:
123                //              Check if the node is already embraced within a `<a>...</a>` tag.
124                // node:
125                //              The node to be examined.
126                // tags:
127                //              private
128                var editNode = this.editor.editNode,
129                        result = false, tagName;
130                       
131                node = node.parentNode;
132                while(node && node !== editNode){
133                        tagName = node.tagName ? node.tagName.toLowerCase() : "";
134                        if(tagName == "a"){
135                                result = true;
136                                break;
137                        }
138                        node = node.parentNode;
139                }
140                return result;
141        },
142       
143        _findLastEditingNode: function(/*DomNode*/ node){
144                // summary:
145                //              Find the last node that was edited so that we can
146                //              get the last edited text.
147                // node:
148                //              The current node that the cursor is at.
149                // tags:
150                //              private
151                var blockTagNames = dijit.range.BlockTagNames,
152                        editNode = this.editor.editNode, blockNode;
153
154                if(!node){ return node; }
155                if(this.blockNodeForEnter == "BR" &&
156                                (!(blockNode = dijit.range.getBlockAncestor(node, null, editNode).blockNode) ||
157                                blockNode.tagName.toUpperCase() != "LI")){
158                        while((node = node.previousSibling) && node.nodeType != 3){}
159                }else{
160                        // EnterKeyHandling is under "DIV" or "P" mode or
161                        // it's in a LI element. Find the last editing block
162                        if((blockNode || (blockNode = dijit.range.getBlockAncestor(node, null, editNode).blockNode)) &&
163                                        blockNode.tagName.toUpperCase() == "LI"){
164                                node = blockNode;
165                        }else{
166                                node = dijit.range.getBlockAncestor(node, null, editNode).blockNode;
167                        }
168                        // Find the last editing text node
169                        while((node = node.previousSibling) && !(node.tagName && node.tagName.match(blockTagNames))){}
170                        if(node){
171                                node = node.lastChild;
172                                while(node){
173                                        if(node.nodeType == 3 && dojo.trim(node.nodeValue) != ""){
174                                                break;
175                                        }else if(node.nodeType == 1){
176                                                node = node.lastChild;
177                                        }else{
178                                                node = node.previousSibling;
179                                        }
180                                }
181                        }
182                }
183                return node;
184        },
185       
186        _findUrls: function(/*DomNode*/ node, /*DomNode*/ bm, /*Number*/ bmOff){
187                // summary:
188                //              Find the occurrace of the URL strings.
189                //              FF, Chrome && Safri have a behavior that when insertHTML is executed,
190                //              the orignal referrence to the text node will be the text node next to
191                //              the inserted anchor automatically. So we have to re-caculate the index of
192                //              the following URL occurrence.
193                // value:
194                //              A text to be scanned.
195                // tags:
196                //              private
197                var pattern = /(http|https|ftp):\/\/[^\s]+/ig,
198                        list = [], baseIndex = 0,
199                        value = node.nodeValue, result, ch;
200               
201                if(node === bm && bmOff < value.length){
202                        // Break the text so that it may not grab extra words.
203                        // Such as if you type:
204                        // foo http://foo.com|bar (And | is where you press enter).
205                        // It will grab the bar word as part of the link. That's annoying/bad.
206                        // Also it prevents recognizing the text after the cursor.
207                        value = value.substr(0, bmOff);
208                }
209               
210                while((result = pattern.exec(value)) != null){
211                        if(result.index == 0 || (ch = value.charAt(result.index - 1)) == " " || ch == "\xA0"){
212                                list.push({start: result.index - baseIndex, end: result.index + result[0].length - baseIndex});
213                                baseIndex = result.index + result[0].length;
214                        }
215                }
216
217                return list;
218        }
219});
220
221// Register this plugin.
222dojo.subscribe(dijit._scopeName + ".Editor.getPlugin",null,function(o){
223        if(o.plugin){ return; }
224        var name = o.args.name.toLowerCase();
225        if(name ===  "autourllink"){
226                o.plugin = new AutoUrlLink();
227        }
228});
229
230return AutoUrlLink;
231
232});
Note: See TracBrowser for help on using the repository browser.