diff options
Diffstat (limited to 'sources/core/skin.js')
-rw-r--r-- | sources/core/skin.js | 350 |
1 files changed, 350 insertions, 0 deletions
diff --git a/sources/core/skin.js b/sources/core/skin.js new file mode 100644 index 00000000..143a7346 --- /dev/null +++ b/sources/core/skin.js | |||
@@ -0,0 +1,350 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2015, 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 | */ | ||