1 /* core.js is part of Aloha Editor project http://aloha-editor.org
  2  *
  3  * Aloha Editor is a WYSIWYG HTML5 inline editing library and editor. 
  4  * Copyright (c) 2010-2012 Gentics Software GmbH, Vienna, Austria.
  5  * Contributors http://aloha-editor.org/contribution.php 
  6  * 
  7  * Aloha Editor is free software; you can redistribute it and/or
  8  * modify it under the terms of the GNU General Public License
  9  * as published by the Free Software Foundation; either version 2
 10  * of the License, or any later version.
 11  *
 12  * Aloha Editor is distributed in the hope that it will be useful,
 13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 15  * GNU General Public License for more details.
 16  *
 17  * You should have received a copy of the GNU General Public License
 18  * along with this program; if not, write to the Free Software
 19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 20  * 
 21  * As an additional permission to the GNU GPL version 2, you may distribute
 22  * non-source (e.g., minimized or compacted) forms of the Aloha-Editor
 23  * source code without the copy of the GNU GPL normally required,
 24  * provided you include this license notice and a URL through which
 25  * recipients can access the Corresponding Source.
 26  */
 27 define([
 28 	'jquery',
 29 	'aloha/pluginmanager'
 30 ], function (
 31 	jQuery,
 32 	PluginManager
 33 ) {
 34 	"use strict";
 35 
 36 	var Aloha = window.Aloha;
 37 	//----------------------------------------
 38 	// Private variables
 39 	//----------------------------------------
 40 
 41 	/**
 42 	 * Base Aloha Object
 43 	 * @namespace Aloha
 44 	 * @class Aloha The Aloha base object, which contains all the core functionality
 45 	 * @singleton
 46 	 */
 47 	jQuery.extend(true, Aloha, {
 48 
 49 		/**
 50 		 * The Aloha Editor Version we are using
 51 		 * It should be set by us and updated for the particular branch
 52 		 * @property
 53 		 */
 54 		version: '${version}',
 55 
 56 		/**
 57 		 * Array of editables that are managed by Aloha
 58 		 * @property
 59 		 * @type Array
 60 		 */
 61 		editables: [],
 62 
 63 		/**
 64 		 * The currently active editable is referenced here
 65 		 * @property
 66 		 * @type Aloha.Editable
 67 		 */
 68 		activeEditable: null,
 69 
 70 		/**
 71 		 * settings object, which will contain all Aloha settings
 72 		 * @cfg {Object} object Aloha's settings
 73 		 */
 74 		settings: {},
 75 
 76 		/**
 77 		 * defaults object, which will contain all Aloha defaults
 78 		 * @cfg {Object} object Aloha's settings
 79 		 */
 80 		defaults: {},
 81 
 82 		/**
 83 		 * Namespace for ui components
 84 		 */
 85 		ui: {},
 86 
 87 		/**
 88 		 * This represents the name of the users OS. Could be:
 89 		 * 'Mac', 'Linux', 'Win', 'Unix', 'Unknown'
 90 		 * @property
 91 		 * @type string
 92 		 */
 93 		OSName: 'Unknown',
 94 
 95 		/**
 96 		 * Which stage is the aloha init process at?
 97 		 * @property
 98 		 * @type string
 99 		 */
100 		stage: 'loadingAloha',
101 
102 		/**
103 		 * A list of loaded plugin names. Available after the
104 		 * "loadPlugins" stage.
105 		 *
106 		 * @property
107 		 * @type array
108 		 * @internal
109 		 */
110 		loadedPlugins: [],
111 
112 		/**
113 		 * Maps names of plugins (link) to the base URL (../plugins/common/link).
114 		 */
115 		_pluginBaseUrlByName: {},
116 
117 		/**
118 		 * Initialize the initialization process
119 		 */
120 121 		init: function () {
122 			// Load & Initialise
123 			Aloha.stage = 'initAloha';
124 			Aloha.initAloha(function () {
125 				Aloha.stage = 'initPlugins';
126 				Aloha.initPlugins(function () {
127 					Aloha.stage = 'initGui';
128 					Aloha.initGui(function () {
129 						Aloha.stage = 'alohaReady';
130 						Aloha.trigger('aloha-ready');
131 					});
132 				});
133 			});
134 		},
135 
136 		/**
137 		 * Returns list of loaded plugins (without Bundle name)
138 		 *
139 		 * @return array
140 		 */
141 		getLoadedPlugins: function () {
142 			return this.loadedPlugins;
143 		},
144 
145 		/**
146 		 * Returns true if a certain plugin is loaded, false otherwise.
147 		 */
148 		isPluginLoaded: function (pluginName) {
149 			var found = false;
150 			jQuery.each(this.loadedPlugins, function () {
151 				if (pluginName.toString() === this.toString()) {
152 					found = true;
153 				}
154 			});
155 			return found;
156 		},
157 
158 		/**
159 		 * Initialise Aloha
160 		 */
161 		initAloha: function (next) {
162 			var $html = jQuery('html');
163 
164 			// check browser version on init
165 			// this has to be revamped, as
166 			if ((jQuery.browser.webkit && parseFloat(jQuery.browser.version) < 532.5) // Chrome/Safari 4
167 			         || (jQuery.browser.mozilla && parseFloat(jQuery.browser.version) < 1.9) // FF 3.5
168 				     || (jQuery.browser.msie && jQuery.browser.version < 7) // IE 7
169 				     || (jQuery.browser.opera && jQuery.browser.version < 11)) { // right now, Opera needs some work
170 				if (window.console && window.console.log) {
171 					window.console.log('Your browser is not supported.');
172 				}
173 			}
174 
175 			// register the body click event to blur editables
176 			jQuery('html').mousedown(function (e) {
177 				// This is a hack to prevent a click into a modal dialog from blurring the editable.
178 				if (Aloha.activeEditable && !jQuery(".aloha-dialog").is(':visible') && !Aloha.eventHandled) {
179 					Aloha.activeEditable.blur();
180 					Aloha.activeEditable = null;
181 				}
182 			}).mouseup(function (e) {
183 				Aloha.eventHandled = false;
184 			});
185 
186 
187 			// add class to body to denote browser
188 			if (jQuery.browser.webkit) {
189 				$html.addClass('aloha-webkit');
190 			} else if (jQuery.browser.opera) {
191 				$html.addClass('aloha-opera');
192 			} else if (jQuery.browser.msie) {
193 				$html.addClass('aloha-ie' + parseInt(jQuery.browser.version, 10));
194 			} else if (jQuery.browser.mozilla) {
195 				$html.addClass('aloha-mozilla');
196 			}
197 
198 			// Initialise the base path to the aloha files
199 			Aloha.settings.base = Aloha.getAlohaUrl();
200 
201 			// initialize the Log
202 			Aloha.Log.init();
203 
204 			// initialize the error handler for general javascript errors
205 			if (Aloha.settings.errorhandling) {
206 				window.onerror = function (msg, url, linenumber) {
207 					Aloha.Log.error(Aloha, 'Error message: ' + msg + '\nURL: ' + url + '\nLine Number: ' + linenumber);
208 					// TODO eventually add a message to the message line?
209 					return true;
210 				};
211 			}
212 
213 			// OS detection
214 			if (navigator.appVersion.indexOf('Win') != -1) {
215 				Aloha.OSName = 'Win';
216 			}
217 			if (navigator.appVersion.indexOf('Mac') != -1) {
218 				Aloha.OSName = 'Mac';
219 			}
220 			if (navigator.appVersion.indexOf('X11') != -1) {
221 				Aloha.OSName = 'Unix';
222 			}
223 			if (navigator.appVersion.indexOf('Linux') != -1) {
224 				Aloha.OSName = 'Linux';
225 			}
226 
227 			// Forward
228 			next();
229 		},
230 
231 		/**
232 		 * Loads plugins Aloha
233 		 * @return void
234 		 */
235 		initPlugins: function (next) {
236 			PluginManager.init(next, this.getLoadedPlugins());
237 		},
238 
239 		/**
240 		 * Loads GUI components
241 		 * @return void
242 		 */
243 		initGui: function (next) {
244 			var i, editablesLength;
245 
246 			Aloha.RepositoryManager.init();
247 
248 			// activate registered editables
249 			for (i = 0, editablesLength = Aloha.editables.length; i < editablesLength; i++) {
250 				if (!Aloha.editables[i].ready) {
251 					Aloha.editables[i].init();
252 				}
253 			}
254 
255 			// Forward
256 			next();
257 		},
258 
259 		/**
260 		 * Activates editable and deactivates all other Editables
261 		 * @param {Editable} editable the Editable to be activated
262 		 * @return void
263 		 */
264 		activateEditable: function (editable) {
265 			var i;
266 
267 			// Don't cache Aloha.editables.length since editables may be removed on blur.
268 			for (i = 0; i < Aloha.editables.length; i++) {
269 				if (Aloha.editables[i] != editable && Aloha.editables[i].isActive) {
270 					Aloha.editables[i].blur();
271 				}
272 			}
273 
274 			Aloha.activeEditable = editable;
275 		},
276 
277 		/**
278 		 * Returns the current Editable
279 		 * @return {Editable} returns the active Editable
280 		 */
281 		getActiveEditable: function () {
282 			return Aloha.activeEditable;
283 		},
284 
285 		/**
286 		 * deactivated the current Editable
287 		 * @return void
288 		 */
289 		deactivateEditable: function () {
290 
291 			if (typeof Aloha.activeEditable === 'undefined' || Aloha.activeEditable === null) {
292 				return;
293 			}
294 
295 			// blur the editable
296 			Aloha.activeEditable.blur();
297 			Aloha.activeEditable = null;
298 		},
299 
300 		/**
301 		 * Gets an editable by an ID or null if no Editable with that ID registered.
302 		 * @param {string} id the element id to look for.
303 		 * @return {Aloha.Editable} editable
304 		 */
305 		getEditableById: function (id) {
306 			var i, editablesLength;
307 
308 			// if the element is a textarea than route to the editable div
309 			if (jQuery('#' + id).get(0).nodeName.toLowerCase() === 'textarea') {
310 				id = id + '-aloha';
311 			}
312 
313 			// serach all editables for id
314 			for (i = 0, editablesLength = Aloha.editables.length; i < editablesLength; i++) {
315 				if (Aloha.editables[i].getId() == id) {
316 					return Aloha.editables[i];
317 				}
318 			}
319 
320 			return null;
321 		},
322 
323 		/**
324 		 * Checks whether an object is a registered Aloha Editable.
325 		 * @param {jQuery} obj the jQuery object to be checked.
326 		 * @return {boolean}
327 		 */
328 		isEditable: function (obj) {
329 			var i, editablesLength;
330 
331 			for (i = 0, editablesLength = Aloha.editables.length; i < editablesLength; i++) {
332 				if (Aloha.editables[i].originalObj.get(0) === obj) {
333 					return true;
334 				}
335 			}
336 			return false;
337 		},
338 
339 		/**
340 		 * Get the nearest editable parent of the given jQuery object
341 		 * @param {jQuery} $obj jQuery object
342 		 * @return {Aloha.Editable} editable or undefined if none found
343 		 */
344 		getEditableHost: function ($obj) {
345 			var $parents, i, $editable, editablesLength = Aloha.editables.length;
346 			if (!$obj) {
347 				return;
348 			}
349 
350 			$parents = $obj.parents().andSelf().each(function () {
351 				for (i = 0; i < editablesLength; i++) {
352 					if (Aloha.editables[i].originalObj.get(0) === this) {
353 						$editable = Aloha.editables[i];
354 						return false;
355 					}
356 				}
357 			});
358 
359 			return $editable;
360 		},
361 
362 		/**
363 		 * Logs a message to the console
364 		 * @param level Level of the log ("error", "warn" or "info", "debug")
365 		 * @param component Component that calls the log
366 		 * @param message log message
367 		 * @return void
368 		 * @hide
369 		 */
370 		log: function (level, component, message) {
371 			if (typeof Aloha.Log !== "undefined") {
372 				Aloha.Log.log(level, component, message);
373 			}
374 		},
375 
376 		/**
377 		 * Register the given editable
378 		 * @param editable editable to register
379 		 * @return void
380 		 * @hide
381 		 */
382 		registerEditable: function (editable) {
383 			Aloha.editables.push(editable);
384 		},
385 
386 		/**
387 388 		 * Unregister the given editable. It will be deactivated and removed from editables.
389 		 * @param editable editable to unregister
390 		 * @return void
391 		 * @hide
392 		 */
393 		unregisterEditable: function (editable) {
394 			var id = jQuery.inArray(editable, Aloha.editables);
395 			if (id != -1) {
396 				Aloha.editables.splice(id, 1);
397 			}
398 		},
399 
400 		/**
401 		 * String representation
402 		 * @hide
403 		 */
404 		toString: function () {
405 			return 'Aloha';
406 		},
407 
408 		/**
409 		 * Check whether at least one editable was modified
410 		 * @method
411 		 * @return {boolean} true when at least one editable was modified, false if not
412 		 */
413 		isModified: function () {
414 			var i;
415 
416 			// check if something needs top be saved
417 			for (i = 0; i < Aloha.editables.length; i++) {
418 				if (Aloha.editables[i].isModified && Aloha.editables[i].isModified()) {
419 					return true;
420 				}
421 			}
422 
423 			return false;
424 		},
425 
426 		/**
427 		 * Determines the Aloha Url
428 		 * Uses Aloha.settings.baseUrl if set.
429 		 * @method
430 		 * @return {String} alohaUrl
431 		 */
432 		getAlohaUrl: function (suffix) {
433 			return Aloha.settings.baseUrl;
434 		},
435 
436 		/**
437 		 * Gets the plugin's url.
438 		 *
439 		 * @method
440 		 * @param {string} name The name with which the plugin was registered
441 		 *                      with.
442 		 * @return {string} The fully qualified url of this plugin.
443 		 */
444 		getPluginUrl: function (name) {
445 			var url;
446 
447 			if (name) {
448 				url = Aloha.settings._pluginBaseUrlByName[name];
449 				if (url) {
450 					//Check if url is absolute and attach base url if it is not
451 					if (!url.match("^(\/|http[s]?:).*")) {
452 						url = Aloha.getAlohaUrl() + '/' + url;
453 					}
454 				}
455 			}
456 			return url;
457 		},
458 
459 		/**
460 		 * Disable object resizing by executing command 'enableObjectResizing',
461 		 * if the browser supports this
462 463 		 */
464 		disableObjectResizing: function () {
465 			try {
466 				// this will disable browsers image resizing facilities
467 				// disable resize handles
468 				var supported;
469 				try {
470 					supported = document.queryCommandSupported('enableObjectResizing');
471 				} catch (e) {
472 					supported = false;
473 					Aloha.Log.log('enableObjectResizing is not supported.');
474 				}
475 
476 				if (supported) {
477 					document.execCommand('enableObjectResizing', false, false);
478 					Aloha.Log.log('enableObjectResizing disabled.');
479 				}
480 			} catch (e2) {
481 				Aloha.Log.error(e2, 'Could not disable enableObjectResizing');
482 				// this is just for others, who will not support disabling enableObjectResizing
483 			}
484 		}
485 	});
486 487 
	return Aloha;
488 });
489