JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
e5b7044ec8b8a0ee53913db1af9fe931507789d8
[ckeditor.git] / _source / plugins / link / plugin.js
1 /*\r
2 Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved.\r
3 For licensing, see LICENSE.html or http://ckeditor.com/license\r
4 */\r
5 \r
6 CKEDITOR.plugins.add( 'link',\r
7 {\r
8         init : function( editor )\r
9         {\r
10                 // Add the link and unlink buttons.\r
11                 editor.addCommand( 'link', new CKEDITOR.dialogCommand( 'link' ) );\r
12                 editor.addCommand( 'anchor', new CKEDITOR.dialogCommand( 'anchor' ) );\r
13                 editor.addCommand( 'unlink', new CKEDITOR.unlinkCommand() );\r
14                 editor.ui.addButton( 'Link',\r
15                         {\r
16                                 label : editor.lang.link.toolbar,\r
17                                 command : 'link'\r
18                         } );\r
19                 editor.ui.addButton( 'Unlink',\r
20                         {\r
21                                 label : editor.lang.unlink,\r
22                                 command : 'unlink'\r
23                         } );\r
24                 editor.ui.addButton( 'Anchor',\r
25                         {\r
26                                 label : editor.lang.anchor.toolbar,\r
27                                 command : 'anchor'\r
28                         } );\r
29                 CKEDITOR.dialog.add( 'link', this.path + 'dialogs/link.js' );\r
30                 CKEDITOR.dialog.add( 'anchor', this.path + 'dialogs/anchor.js' );\r
31 \r
32                 // Add the CSS styles for anchor placeholders.\r
33                 var side = editor.lang.dir == 'rtl' ? 'right' : 'left';\r
34                 editor.addCss(\r
35                         'img.cke_anchor' +\r
36                         '{' +\r
37                                 'background-image: url(' + CKEDITOR.getUrl( this.path + 'images/anchor.gif' ) + ');' +\r
38                                 'background-position: center center;' +\r
39                                 'background-repeat: no-repeat;' +\r
40                                 'border: 1px solid #a9a9a9;' +\r
41                                 'width: 18px !important;' +\r
42                                 'height: 18px !important;' +\r
43                         '}\n' +\r
44                         'a.cke_anchor' +\r
45                         '{' +\r
46                                 'background-image: url(' + CKEDITOR.getUrl( this.path + 'images/anchor.gif' ) + ');' +\r
47                                 'background-position: ' + side + ' center;' +\r
48                                 'background-repeat: no-repeat;' +\r
49                                 'border: 1px solid #a9a9a9;' +\r
50                                 'padding-' + side + ': 18px;' +\r
51                         '}'\r
52                         );\r
53 \r
54                 // Register selection change handler for the unlink button.\r
55                  editor.on( 'selectionChange', function( evt )\r
56                         {\r
57                                 /*\r
58                                  * Despite our initial hope, document.queryCommandEnabled() does not work\r
59                                  * for this in Firefox. So we must detect the state by element paths.\r
60                                  */\r
61                                 var command = editor.getCommand( 'unlink' ),\r
62                                         element = evt.data.path.lastElement && evt.data.path.lastElement.getAscendant( 'a', true );\r
63                                 if ( element && element.getName() == 'a' && element.getAttribute( 'href' ) )\r
64                                         command.setState( CKEDITOR.TRISTATE_OFF );\r
65                                 else\r
66                                         command.setState( CKEDITOR.TRISTATE_DISABLED );\r
67                         } );\r
68 \r
69                 editor.on( 'doubleclick', function( evt )\r
70                         {\r
71                                 var element = CKEDITOR.plugins.link.getSelectedLink( editor ) || evt.data.element;\r
72 \r
73                                 if ( !element.isReadOnly() )\r
74                                 {\r
75                                         if ( element.is( 'a' ) )\r
76                                                 evt.data.dialog =  ( element.getAttribute( 'name' ) && !element.getAttribute( 'href' ) ) ? 'anchor' : 'link';\r
77                                         else if ( element.is( 'img' ) && element.data( 'cke-real-element-type' ) == 'anchor' )\r
78                                                 evt.data.dialog = 'anchor';\r
79                                 }\r
80                         });\r
81 \r
82                 // If the "menu" plugin is loaded, register the menu items.\r
83                 if ( editor.addMenuItems )\r
84                 {\r
85                         editor.addMenuItems(\r
86                                 {\r
87                                         anchor :\r
88                                         {\r
89                                                 label : editor.lang.anchor.menu,\r
90                                                 command : 'anchor',\r
91                                                 group : 'anchor'\r
92                                         },\r
93 \r
94                                         link :\r
95                                         {\r
96                                                 label : editor.lang.link.menu,\r
97                                                 command : 'link',\r
98                                                 group : 'link',\r
99                                                 order : 1\r
100                                         },\r
101 \r
102                                         unlink :\r
103                                         {\r
104                                                 label : editor.lang.unlink,\r
105                                                 command : 'unlink',\r
106                                                 group : 'link',\r
107                                                 order : 5\r
108                                         }\r
109                                 });\r
110                 }\r
111 \r
112                 // If the "contextmenu" plugin is loaded, register the listeners.\r
113                 if ( editor.contextMenu )\r
114                 {\r
115                         editor.contextMenu.addListener( function( element, selection )\r
116                                 {\r
117                                         if ( !element || element.isReadOnly() )\r
118                                                 return null;\r
119 \r
120                                         var isAnchor = ( element.is( 'img' ) && element.data( 'cke-real-element-type' ) == 'anchor' );\r
121 \r
122                                         if ( !isAnchor )\r
123                                         {\r
124                                                 if ( !( element = CKEDITOR.plugins.link.getSelectedLink( editor ) ) )\r
125                                                         return null;\r
126 \r
127                                                 isAnchor = ( element.getAttribute( 'name' ) && !element.getAttribute( 'href' ) );\r
128                                         }\r
129 \r
130                                         return isAnchor ?\r
131                                                         { anchor : CKEDITOR.TRISTATE_OFF } :\r
132                                                         { link : CKEDITOR.TRISTATE_OFF, unlink : CKEDITOR.TRISTATE_OFF };\r
133                                 });\r
134                 }\r
135         },\r
136 \r
137         afterInit : function( editor )\r
138         {\r
139                 // Register a filter to displaying placeholders after mode change.\r
140 \r
141                 var dataProcessor = editor.dataProcessor,\r
142                         dataFilter = dataProcessor && dataProcessor.dataFilter;\r
143 \r
144                 if ( dataFilter )\r
145                 {\r
146                         dataFilter.addRules(\r
147                                 {\r
148                                         elements :\r
149                                         {\r
150                                                 a : function( element )\r
151                                                 {\r
152                                                         var attributes = element.attributes;\r
153                                                         if ( attributes.name && !attributes.href )\r
154                                                                 return editor.createFakeParserElement( element, 'cke_anchor', 'anchor' );\r
155                                                 }\r
156                                         }\r
157                                 });\r
158                 }\r
159         },\r
160 \r
161         requires : [ 'fakeobjects' ]\r
162 } );\r
163 \r
164 CKEDITOR.plugins.link =\r
165 {\r
166         /**\r
167          *  Get the surrounding link element of current selection.\r
168          * @param editor\r
169          * @example CKEDITOR.plugins.link.getSelectedLink( editor );\r
170          * @since 3.2.1\r
171          * The following selection will all return the link element.\r
172          *       <pre>\r
173          *  <a href="#">li^nk</a>\r
174          *  <a href="#">[link]</a>\r
175          *  text[<a href="#">link]</a>\r
176          *  <a href="#">li[nk</a>]\r
177          *  [<b><a href="#">li]nk</a></b>]\r
178          *  [<a href="#"><b>li]nk</b></a>\r
179          * </pre>\r
180          */\r
181         getSelectedLink : function( editor )\r
182         {\r
183                 try\r
184                 {\r
185                         var selection = editor.getSelection();\r
186                         if ( selection.getType() == CKEDITOR.SELECTION_ELEMENT )\r
187                         {\r
188                                 var selectedElement = selection.getSelectedElement();\r
189                                 if ( selectedElement.is( 'a' ) )\r
190                                         return selectedElement;\r
191                         }\r
192 \r
193                         var range = selection.getRanges( true )[ 0 ];\r
194                         range.shrink( CKEDITOR.SHRINK_TEXT );\r
195                         var root = range.getCommonAncestor();\r
196                         return root.getAscendant( 'a', true );\r
197                 }\r
198                 catch( e ) { return null; }\r
199         }\r
200 };\r
201 \r
202 CKEDITOR.unlinkCommand = function(){};\r
203 CKEDITOR.unlinkCommand.prototype =\r
204 {\r
205         /** @ignore */\r
206         exec : function( editor )\r
207         {\r
208                 /*\r
209                  * execCommand( 'unlink', ... ) in Firefox leaves behind <span> tags at where\r
210                  * the <a> was, so again we have to remove the link ourselves. (See #430)\r
211                  *\r
212                  * TODO: Use the style system when it's complete. Let's use execCommand()\r
213                  * as a stopgap solution for now.\r
214                  */\r
215                 var selection = editor.getSelection(),\r
216                         bookmarks = selection.createBookmarks(),\r
217                         ranges = selection.getRanges(),\r
218                         rangeRoot,\r
219                         element;\r
220 \r
221                 for ( var i = 0 ; i < ranges.length ; i++ )\r
222                 {\r
223                         rangeRoot = ranges[i].getCommonAncestor( true );\r
224                         element = rangeRoot.getAscendant( 'a', true );\r
225                         if ( !element )\r
226                                 continue;\r
227                         ranges[i].selectNodeContents( element );\r
228                 }\r
229 \r
230                 selection.selectRanges( ranges );\r
231                 editor.document.$.execCommand( 'unlink', false, null );\r
232                 selection.selectBookmarks( bookmarks );\r
233         },\r
234 \r
235         startDisabled : true\r
236 };\r
237 \r
238 CKEDITOR.tools.extend( CKEDITOR.config,\r
239 {\r
240         linkShowAdvancedTab : true,\r
241         linkShowTargetTab : true\r
242 } );\r