1 /*
  2 Copyright (c) 2003-2009, 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 	var preloaded = {};
 21 	var paths = {};
 22
 23 	var loadedPart = function( skinName, part, callback )
 24 	{
 25 		// Get the skin definition.
 26 		var skinDefinition = loaded[ skinName ];
 27
 28 		var appendSkinPath = function( fileNames )
 29 		{
 30 			for ( var n = 0 ; n < fileNames.length ; n++ )
 31 			{
 32 				fileNames[ n ] = CKEDITOR.getUrl( paths[ skinName ] + fileNames[ n ] );
 33 			}
 34 		};
 35
 36 		// Check if we need to preload images from it.
 37 		if ( !preloaded[ skinName ] )
 38 		{
 39 			var preload = skinDefinition.preload;
 40 			if ( preload && preload.length > 0 )
 41 			{
 42 				appendSkinPath( preload );
 43 				CKEDITOR.imageCacher.load( preload, function()
 44 					{
 45 						preloaded[ skinName ] = 1;
 46 						loadedPart( skinName, part, callback );
 47 					} );
 48 				return;
 49 			}
 50
 51 			// Mark it as preloaded.
 52 			preloaded[ skinName ] = 1;
 53 		}
 54
 55 		// Get the part definition.
 56 		part = skinDefinition[ part ];
 57 		var partIsLoaded = !part || !!part._isLoaded;
 58
 59 		// Call the callback immediately if already loaded.
 60 		if ( partIsLoaded )
 61 			callback && callback();
 62 		else
 63 		{
 64 			// Put the callback in a queue.
 65 			var pending = part._pending || ( part._pending = [] );
 66 			pending.push( callback );
 67
 68 			// We may have more than one skin part load request. Just the first
 69 			// one must do the loading job.
 70 			if ( pending.length > 1 )
 71 				return;
 72
 73 			// Check whether the "css" and "js" properties have been defined
 74 			// for that part.
 75 			var cssIsLoaded = !part.css || !part.css.length;
 76 			var jsIsLoaded = !part.js || !part.js.length;
 77
 78 			// This is the function that will trigger the callback calls on
 79 			// load.
 80 			var checkIsLoaded = function()
 81 			{
 82 				if ( cssIsLoaded && jsIsLoaded )
 83 				{
 84 					// Mark the part as loaded.
 85 					part._isLoaded = 1;
 86
 87 					// Call all pending callbacks.
 88 					for ( var i = 0 ; i < pending.length ; i++ )
 89 					{
 90 						if ( pending[ i ] )
 91 							pending[ i ]();
 92 					}
 93 				}
 94 			};
 95
 96 			// Load the "css" pieces.
 97 			if ( !cssIsLoaded )
 98 			{
 99 				appendSkinPath( part.css );
100
101 				for ( var c = 0 ; c < part.css.length ; c++ )
102 					CKEDITOR.document.appendStyleSheet( part.css[ c ] );
103
104 				cssIsLoaded = 1;
105 			}
106
107 			// Load the "js" pieces.
108 			if ( !jsIsLoaded )
109 			{
110 				appendSkinPath( part.js );
111 				CKEDITOR.scriptLoader.load( part.js, function()
112 					{
113 						jsIsLoaded = 1;
114 						checkIsLoaded();
115 					});
116 			}
117
118 			// We may have nothing to load, so check it immediately.
119 			checkIsLoaded();
120 		}
121 	};
122
123 	return /** @lends CKEDITOR.skins */ {
124
125 		/**
126 		 * Registers a skin definition.
127 		 * @param {String} skinName The skin name.
128 		 * @param {Object} skinDefinition The skin definition.
129 		 * @example
130 		 */
131 		add : function( skinName, skinDefinition )
132 		{
133 			loaded[ skinName ] = skinDefinition;
134
135 			skinDefinition.skinPath = paths[ skinName ]
136 				|| ( paths[ skinName ] =
137 						CKEDITOR.getUrl(
139 							'skins/' + skinName + '/' ) );
140 		},
141
142 		/**
143 		 * Loads a skin part. Skins are defined in parts, which are basically
144 		 * separated CSS files. This function is mainly used by the core code and
145 		 * should not have much use out of it.
146 		 * @param {String} skinName The name of the skin to be loaded.
147 		 * @param {String} skinPart The skin part to be loaded. Common skin parts
148 		 *		are "editor" and "dialog".
149 		 * @param {Function} [callback] A function to be called once the skin
150 		 *		part files are loaded.
151 		 * @example
152 		 */
153 		load : function( editor, skinPart, callback )
154 		{
155 			var skinName = editor.skinName,
156 				skinPath = editor.skinPath;
157
158 			if ( loaded[ skinName ] )
159 			{
160 				loadedPart( skinName, skinPart, callback );
161
162 				// Get the skin definition.
163 				var skinDefinition = loaded[ skinName ];
164
165 				// Trigger init function if any.
166 				if ( skinDefinition.init )
167 					skinDefinition.init( editor );
168 			}
169 			else
170 			{
171 				paths[ skinName ] = skinPath;
172 				CKEDITOR.scriptLoader.load( skinPath + 'skin.js', function()
173 						{
174 							loadedPart( skinName, skinPart, callback );
175
176 							// Get the skin definition.
177 							var skinDefinition = loaded[ skinName ];
178
179 							// Trigger init function if any.
180 							if ( skinDefinition.init )
181 								skinDefinition.init( editor );
182 						});
183 			}
184 		}
185 	};
186 })();
187