]>
Commit | Line | Data |
---|---|---|
1 | /** | |
2 | * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved. | |
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | |
4 | */ | |
5 | ||
6 | /** | |
7 | * @fileOverview Defines the {@link CKEDITOR.skin} class that is used to manage skin parts. | |
8 | */ | |
9 | ||
10 | ( function() { | |
11 | var cssLoaded = {}; | |
12 | ||
13 | function getName() { | |
14 | return CKEDITOR.skinName.split( ',' )[ 0 ]; | |
15 | } | |
16 | ||
17 | function getConfigPath() { | |
18 | return CKEDITOR.getUrl( CKEDITOR.skinName.split( ',' )[ 1 ] || ( 'skins/' + getName() + '/' ) ); | |
19 | } | |
20 | ||
21 | /** | |
22 | * Manages the loading of skin parts among all editor instances. | |
23 | * | |
24 | * @class | |
25 | * @singleton | |
26 | */ | |
27 | CKEDITOR.skin = { | |
28 | /** | |
29 | * Returns the root path to the skin directory. | |
30 | * | |
31 | * @method | |
32 | * @todo | |
33 | */ | |
34 | path: getConfigPath, | |
35 | ||
36 | /** | |
37 | * Loads a skin part into the page. Does nothing if the part has already been loaded. | |
38 | * | |
39 | * **Note:** The "editor" part is always auto loaded upon instance creation, | |
40 | * thus this function is mainly used to **lazy load** other parts of the skin | |
41 | * that do not have to be displayed until requested. | |
42 | * | |
43 | * // Load the dialog part. | |
44 | * editor.skin.loadPart( 'dialog' ); | |
45 | * | |
46 | * @param {String} part The name of the skin part CSS file that resides in the skin directory. | |
47 | * @param {Function} fn The provided callback function which is invoked after the part is loaded. | |
48 | */ | |
49 | loadPart: function( part, fn ) { | |
50 | if ( CKEDITOR.skin.name != getName() ) { | |
51 | CKEDITOR.scriptLoader.load( CKEDITOR.getUrl( getConfigPath() + 'skin.js' ), function() { | |
52 | loadCss( part, fn ); | |
53 | } ); | |
54 | } else { | |
55 | loadCss( part, fn ); | |
56 | } | |
57 | }, | |
58 | ||
59 | /** | |
60 | * Retrieves the real URL of a (CSS) skin part. | |
61 | * | |
62 | * @param {String} part | |
63 | */ | |
64 | getPath: function( part ) { | |
65 | return CKEDITOR.getUrl( getCssPath( part ) ); | |
66 | }, | |
67 | ||
68 | /** | |
69 | * The list of registered icons. To add new icons to this list, use {@link #addIcon}. | |
70 | */ | |
71 | icons: {}, | |
72 | ||
73 | /** | |
74 | * Registers an icon. | |
75 | * | |
76 | * @param {String} name The icon name. | |
77 | * @param {String} path The path to the icon image file. | |
78 | * @param {Number} [offset] The vertical offset position of the icon, if | |
79 | * available inside a strip image. | |
80 | * @param {String} [bgsize] The value of the CSS "background-size" property to | |
81 | * use for this icon | |
82 | */ | |
83 | addIcon: function( name, path, offset, bgsize ) { | |
84 | name = name.toLowerCase(); | |
85 | if ( !this.icons[ name ] ) { | |
86 | this.icons[ name ] = { | |
87 | path: path, | |
88 | offset: offset || 0, | |
89 | bgsize: bgsize || '16px' | |
90 | }; | |
91 | } | |
92 | }, | |
93 | ||
94 | /** | |
95 | * Gets the CSS background styles to be used to render a specific icon. | |
96 | * | |
97 | * @param {String} name The icon name, as registered with {@link #addIcon}. | |
98 | * @param {Boolean} [rtl] Indicates that the RTL version of the icon is | |
99 | * to be used, if available. | |
100 | * @param {String} [overridePath] The path to the icon image file. It | |
101 | * overrides the path defined by the named icon, if available, and is | |
102 | * used if the named icon was not registered. | |
103 | * @param {Number} [overrideOffset] The vertical offset position of the | |
104 | * icon. It overrides the offset defined by the named icon, if | |
105 | * available, and is used if the named icon was not registered. | |
106 | * @param {String} [overrideBgsize] The value of the CSS "background-size" property | |
107 | * to use for the icon. It overrides the value defined by the named icon, | |
108 | * if available, and is used if the named icon was not registered. | |
109 | */ | |
110 | getIconStyle: function( name, rtl, overridePath, overrideOffset, overrideBgsize ) { | |
111 | var icon, path, offset, bgsize; | |
112 | ||
113 | if ( name ) { | |
114 | name = name.toLowerCase(); | |
115 | // If we're in RTL, try to get the RTL version of the icon. | |
116 | if ( rtl ) | |
117 | icon = this.icons[ name + '-rtl' ]; | |
118 | ||
119 | // If not in LTR or no RTL version available, get the generic one. | |
120 | if ( !icon ) | |
121 | icon = this.icons[ name ]; | |
122 | } | |
123 | ||
124 | path = overridePath || ( icon && icon.path ) || ''; | |
125 | offset = overrideOffset || ( icon && icon.offset ); | |
126 | bgsize = overrideBgsize || ( icon && icon.bgsize ) || '16px'; | |
127 | ||
128 | // If we use apostrophes in background-image, we must escape apostrophes in path (just to be sure). (#13361) | |
129 | if ( path ) | |
130 | path = path.replace( /'/g, '\\\'' ); | |
131 | ||
132 | return path && | |
133 | ( 'background-image:url(\'' + CKEDITOR.getUrl( path ) + '\');background-position:0 ' + offset + 'px;background-size:' + bgsize + ';' ); | |
134 | } | |
135 | }; | |
136 | ||
137 | function getCssPath( part ) { | |
138 | // Check for ua-specific version of skin part. | |
139 | var uas = CKEDITOR.skin[ 'ua_' + part ], env = CKEDITOR.env; | |
140 | if ( uas ) { | |
141 | ||
142 | // Having versioned UA checked first. | |
143 | uas = uas.split( ',' ).sort( function( a, b ) { | |
144 | return a > b ? -1 : 1; | |
145 | } ); | |
146 | ||
147 | // Loop through all ua entries, checking is any of them match the current ua. | |
148 | for ( var i = 0, ua; i < uas.length; i++ ) { | |
149 | ua = uas[ i ]; | |
150 | ||
151 | if ( env.ie ) { | |
152 | if ( ( ua.replace( /^ie/, '' ) == env.version ) || ( env.quirks && ua == 'iequirks' ) ) | |
153 | ua = 'ie'; | |
154 | } | |
155 | ||
156 | if ( env[ ua ] ) { | |
157 | part += '_' + uas[ i ]; | |
158 | break; | |
159 | } | |
160 | } | |
161 | } | |
162 | return CKEDITOR.getUrl( getConfigPath() + part + '.css' ); | |
163 | } | |
164 | ||
165 | function loadCss( part, callback ) { | |
166 | // Avoid reload. | |
167 | if ( !cssLoaded[ part ] ) { | |
168 | CKEDITOR.document.appendStyleSheet( getCssPath( part ) ); | |
169 | cssLoaded[ part ] = 1; | |
170 | } | |
171 | ||
172 | // CSS loading should not be blocking. | |
173 | callback && callback(); | |
174 | } | |
175 | ||
176 | CKEDITOR.tools.extend( CKEDITOR.editor.prototype, { | |
177 | /** Gets the color of the editor user interface. | |
178 | * | |
179 | * CKEDITOR.instances.editor1.getUiColor(); | |
180 | * | |
181 | * @method | |
182 | * @member CKEDITOR.editor | |
183 | * @returns {String} uiColor The editor UI color or `undefined` if the UI color is not set. | |
184 | */ | |
185 | getUiColor: function() { | |
186 | return this.uiColor; | |
187 | }, | |
188 | ||
189 | /** Sets the color of the editor user interface. This method accepts a color value in | |
190 | * hexadecimal notation, with a `#` character (e.g. #ffffff). | |
191 | * | |
192 | * CKEDITOR.instances.editor1.setUiColor( '#ff00ff' ); | |
193 | * | |
194 | * @method | |
195 | * @member CKEDITOR.editor | |
196 | * @param {String} color The desired editor UI color in hexadecimal notation. | |
197 | */ | |
198 | setUiColor: function( color ) { | |
199 | var uiStyle = getStylesheet( CKEDITOR.document ); | |
200 | ||
201 | return ( this.setUiColor = function( color ) { | |
202 | this.uiColor = color; | |
203 | ||
204 | var chameleon = CKEDITOR.skin.chameleon, | |
205 | editorStyleContent = '', | |
206 | panelStyleContent = ''; | |
207 | ||
208 | if ( typeof chameleon == 'function' ) { | |
209 | editorStyleContent = chameleon( this, 'editor' ); | |
210 | panelStyleContent = chameleon( this, 'panel' ); | |
211 | } | |
212 | ||
213 | var replace = [ [ uiColorRegexp, color ] ]; | |
214 | ||
215 | // Update general style. | |
216 | updateStylesheets( [ uiStyle ], editorStyleContent, replace ); | |
217 | ||
218 | // Update panel styles. | |
219 | updateStylesheets( uiColorMenus, panelStyleContent, replace ); | |
220 | } ).call( this, color ); | |
221 | } | |
222 | } ); | |
223 | ||
224 | var uiColorStylesheetId = 'cke_ui_color', | |
225 | uiColorMenus = [], | |
226 | uiColorRegexp = /\$color/g; | |
227 | ||
228 | function getStylesheet( document ) { | |
229 | var node = document.getById( uiColorStylesheetId ); | |
230 | if ( !node ) { | |
231 | node = document.getHead().append( 'style' ); | |
232 | node.setAttribute( 'id', uiColorStylesheetId ); | |
233 | node.setAttribute( 'type', 'text/css' ); | |
234 | } | |
235 | return node; | |
236 | } | |
237 | ||
238 | function updateStylesheets( styleNodes, styleContent, replace ) { | |
239 | var r, i, content; | |
240 | ||
241 | // We have to split CSS declarations for webkit. | |
242 | if ( CKEDITOR.env.webkit ) { | |
243 | styleContent = styleContent.split( '}' ).slice( 0, -1 ); | |
244 | for ( i = 0; i < styleContent.length; i++ ) | |
245 | styleContent[ i ] = styleContent[ i ].split( '{' ); | |
246 | } | |
247 | ||
248 | for ( var id = 0; id < styleNodes.length; id++ ) { | |
249 | if ( CKEDITOR.env.webkit ) { | |
250 | for ( i = 0; i < styleContent.length; i++ ) { | |
251 | content = styleContent[ i ][ 1 ]; | |
252 | for ( r = 0; r < replace.length; r++ ) | |
253 | content = content.replace( replace[ r ][ 0 ], replace[ r ][ 1 ] ); | |
254 | ||
255 | styleNodes[ id ].$.sheet.addRule( styleContent[ i ][ 0 ], content ); | |
256 | } | |
257 | } else { | |
258 | content = styleContent; | |
259 | for ( r = 0; r < replace.length; r++ ) | |
260 | content = content.replace( replace[ r ][ 0 ], replace[ r ][ 1 ] ); | |
261 | ||
262 | if ( CKEDITOR.env.ie && CKEDITOR.env.version < 11 ) | |
263 | styleNodes[ id ].$.styleSheet.cssText += content; | |
264 | else | |
265 | styleNodes[ id ].$.innerHTML += content; | |
266 | } | |
267 | } | |
268 | } | |
269 | ||
270 | CKEDITOR.on( 'instanceLoaded', function( evt ) { | |
271 | // The chameleon feature is not for IE quirks. | |
272 | if ( CKEDITOR.env.ie && CKEDITOR.env.quirks ) | |
273 | return; | |
274 | ||
275 | var editor = evt.editor, | |
276 | showCallback = function( event ) { | |
277 | var panel = event.data[ 0 ] || event.data; | |
278 | var iframe = panel.element.getElementsByTag( 'iframe' ).getItem( 0 ).getFrameDocument(); | |
279 | ||
280 | // Add stylesheet if missing. | |
281 | if ( !iframe.getById( 'cke_ui_color' ) ) { | |
282 | var node = getStylesheet( iframe ); | |
283 | uiColorMenus.push( node ); | |
284 | ||
285 | var color = editor.getUiColor(); | |
286 | // Set uiColor for new panel. | |
287 | if ( color ) | |
288 | updateStylesheets( [ node ], CKEDITOR.skin.chameleon( editor, 'panel' ), [ [ uiColorRegexp, color ] ] ); | |
289 | ||
290 | } | |
291 | }; | |
292 | ||
293 | editor.on( 'panelShow', showCallback ); | |
294 | editor.on( 'menuShow', showCallback ); | |
295 | ||
296 | // Apply UI color if specified in config. | |
297 | if ( editor.config.uiColor ) | |
298 | editor.setUiColor( editor.config.uiColor ); | |
299 | } ); | |
300 | } )(); | |
301 | ||
302 | /** | |
303 | * The list of file names matching the browser user agent string from | |
304 | * {@link CKEDITOR.env}. This is used to load the skin part file in addition | |
305 | * to the "main" skin file for a particular browser. | |
306 | * | |
307 | * **Note:** For each of the defined skin parts the corresponding | |
308 | * CSS file with the same name as the user agent must exist inside | |
309 | * the skin directory. | |
310 | * | |
311 | * @property ua | |
312 | * @todo type? | |
313 | */ | |
314 | ||
315 | /** | |
316 | * The name of the skin that is currently used. | |
317 | * | |
318 | * @property {String} name | |
319 | * @todo | |
320 | */ | |
321 | ||
322 | /** | |
323 | * The editor skin name. Note that it is not possible to have editors with | |
324 | * different skin settings in the same page. In such case just one of the | |
325 | * skins will be used for all editors. | |
326 | * | |
327 | * This is a shortcut to {@link CKEDITOR#skinName}. | |
328 | * | |
329 | * It is possible to install skins outside the default `skin` folder in the | |
330 | * editor installation. In that case, the absolute URL path to that folder | |
331 | * should be provided, separated by a comma (`'skin_name,skin_path'`). | |
332 | * | |
333 | * config.skin = 'moono'; | |
334 | * | |
335 | * config.skin = 'myskin,/customstuff/myskin/'; | |
336 | * | |
337 | * @cfg {String} skin | |
338 | * @member CKEDITOR.config | |
339 | */ | |
340 | ||
341 | /** | |
342 | * A function that supports the chameleon (skin color switch) feature, providing | |
343 | * the skin color style updates to be applied in runtime. | |
344 | * | |
345 | * **Note:** The embedded `$color` variable is to be substituted with a specific UI color. | |
346 | * | |
347 | * @method chameleon | |
348 | * @param {String} editor The editor instance that the color changes apply to. | |
349 | * @param {String} part The name of the skin part where the color changes take place. | |
350 | */ |