c23dcf22791954cbcb352d2db10efc5a3b921d27
[ckeditor.git] / _source / core / skins.js
1 /*
2 Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved.
3 For licensing, see LICENSE.html or http://ckeditor.com/license
4 */
5
6 /**
7 * @fileOverview Defines the {@link CKEDITOR.skins} object, which is used to
8 * manage skins loading.
9 */
10
11 /**
12 * Manages skins loading.
13 * @namespace
14 * @example
15 */
16 CKEDITOR.skins = (function()
17 {
18 // Holds the list of loaded skins.
19 var loaded = {},
20 paths = {};
21
22 var loadPart = function( editor, skinName, part, callback )
23 {
24 // Get the skin definition.
25 var skinDefinition = loaded[ skinName ];
26
27 if ( !editor.skin )
28 {
29 editor.skin = skinDefinition;
30
31 // Trigger init function if any.
32 if ( skinDefinition.init )
33 skinDefinition.init( editor );
34 }
35
36 var appendSkinPath = function( fileNames )
37 {
38 for ( var n = 0 ; n < fileNames.length ; n++ )
39 {
40 fileNames[ n ] = CKEDITOR.getUrl( paths[ skinName ] + fileNames[ n ] );
41 }
42 };
43
44 function fixCSSTextRelativePath( cssStyleText, baseUrl )
45 {
46 return cssStyleText.replace( /url\s*\(([\s'"]*)(.*?)([\s"']*)\)/g,
47 function( match, opener, path, closer )
48 {
49 if ( /^\/|^\w?:/.test( path ) )
50 return match;
51 else
52 return 'url(' + baseUrl + opener + path + closer + ')';
53 } );
54 }
55
56 // Get the part definition.
57 part = skinDefinition[ part ];
58 var partIsLoaded = !part || !!part._isLoaded;
59
60 // Call the callback immediately if already loaded.
61 if ( partIsLoaded )
62 callback && callback();
63 else
64 {
65 // Put the callback in a queue.
66 var pending = part._pending || ( part._pending = [] );
67 pending.push( callback );
68
69 // We may have more than one skin part load request. Just the first
70 // one must do the loading job.
71 if ( pending.length > 1 )
72 return;
73
74 // Check whether the "css" and "js" properties have been defined
75 // for that part.
76 var cssIsLoaded = !part.css || !part.css.length,
77 jsIsLoaded = !part.js || !part.js.length;
78
79 // This is the function that will trigger the callback calls on
80 // load.
81 var checkIsLoaded = function()
82 {
83 if ( cssIsLoaded && jsIsLoaded )
84 {
85 // Mark the part as loaded.
86 part._isLoaded = 1;
87
88 // Call all pending callbacks.
89 for ( var i = 0 ; i < pending.length ; i++ )
90 {
91 if ( pending[ i ] )
92 pending[ i ]();
93 }
94 }
95 };
96
97 // Load the "css" pieces.
98 if ( !cssIsLoaded )
99 {
100 var cssPart = part.css;
101
102 if ( CKEDITOR.tools.isArray( cssPart ) )
103 {
104 appendSkinPath( cssPart );
105 for ( var c = 0 ; c < cssPart.length ; c++ )
106 CKEDITOR.document.appendStyleSheet( cssPart[ c ] );
107 }
108 else
109 {
110 cssPart = fixCSSTextRelativePath(
111 cssPart, CKEDITOR.getUrl( paths[ skinName ] ) );
112 // Processing Inline CSS part.
113 CKEDITOR.document.appendStyleText( cssPart );
114 }
115
116 part.css = cssPart;
117
118 cssIsLoaded = 1;
119 }
120
121 // Load the "js" pieces.
122 if ( !jsIsLoaded )
123 {
124 appendSkinPath( part.js );
125 CKEDITOR.scriptLoader.load( part.js, function()
126 {
127 jsIsLoaded = 1;
128 checkIsLoaded();
129 });
130 }
131
132 // We may have nothing to load, so check it immediately.
133 checkIsLoaded();
134 }
135 };
136
137 return /** @lends CKEDITOR.skins */ {
138
139 /**
140 * Registers a skin definition.
141 * @param {String} skinName The skin name.
142 * @param {Object} skinDefinition The skin definition.
143 * @example
144 */
145 add : function( skinName, skinDefinition )
146 {
147 loaded[ skinName ] = skinDefinition;
148
149 skinDefinition.skinPath = paths[ skinName ]
150 || ( paths[ skinName ] =
151 CKEDITOR.getUrl(
152 '_source/' + // @Packager.RemoveLine
153 'skins/' + skinName + '/' ) );
154 },
155
156 /**
157 * Loads a skin part. Skins are defined in parts, which are basically
158 * separated CSS files. This function is mainly used by the core code and
159 * should not have much use out of it.
160 * @param {String} skinName The name of the skin to be loaded.
161 * @param {String} skinPart The skin part to be loaded. Common skin parts
162 * are "editor" and "dialog".
163 * @param {Function} [callback] A function to be called once the skin
164 * part files are loaded.
165 * @example
166 */
167 load : function( editor, skinPart, callback )
168 {
169 var skinName = editor.skinName,
170 skinPath = editor.skinPath;
171
172 if ( loaded[ skinName ] )
173 loadPart( editor, skinName, skinPart, callback );
174 else
175 {
176 paths[ skinName ] = skinPath;
177 CKEDITOR.scriptLoader.load( CKEDITOR.getUrl( skinPath + 'skin.js' ), function()
178 {
179 loadPart( editor, skinName, skinPart, callback );
180 });
181 }
182 }
183 };
184 })();