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