1 /*global global: true, process: true, require: true, module: true */
  2 
  3 /**
  4  * Establishes the `GCN' object and exposes it in the global context.
  5  */
  6 GCN = (function (global) {
  7 	'use strict';
  8 
  9 	// Check whether we are in nodeJS context.
 10 	if (typeof process !== 'undefined' && process.versions
 11 			&& process.versions.node) {
 12 		global.isNode = true;
 13 		var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;
 14 		jQuery = global.$ = global.jQuery = require('jquery');
 15 		global.jQuery.ajaxSettings.xhr = function createNodeXHRForGCN() {
 16 			return new XMLHttpRequest();
 17 		};
 18 		// http://stackoverflow.com/a/6432602
 19 		global.jQuery.support.cors = true;
 20 	}
 21 
 22 	/**
 23 	 * @private
 24 	 * @type {boolean} A flag to indicate whether or not a handler has been
 25 	 *                 registerd through the `GCN.onRender()' function.
 26 	 */
 27 	var hasOnRenderHandler = false;
 28 
 29 	/**
 30 	 * @private
 31 	 * @type {boolean} A flag to indicate whether or not a handler has been
 32 	 *                 registerd through the `GCN.onError()' function.
 33 	 */
 34 	var hasOnErrorHandler = false;
 35 
 36 	/**
 37 	 * @type {boolean} An internal flag that stores whether an authentication
 38 	 *                 handler has been set.
 39 	 */
 40 	var hasAuthenticationHandler = false;
 41 
 42 	/**
 43 	 * GCN JS API error object.  This is the object passed to error handlers.
 44 	 *
 45 	 * @class GCNError
 46 	 * @param {string} code
 47 	 * @param {string} message
 48 	 * @param {object} data
 49 	 */
 50 	var GCNError = function (code, message, data) {
 51 		this.code = code;
 52 		this.message = message;
 53 		this.data = data;
 54 	};
 55 
 56 	/**
 57 	 * Returns a human-readable representation of this error object.
 58 	 *
 59 	 * @public
 60 	 * @return {string}
 61 	 */
 62 	GCNError.prototype.toString = function () {
 63 		return 'GCN ERROR (' + this.code + '): "' + (this.message || '') + '"';
 64 	};
 65 
 66 	/**
 67 	 * @name GCN
 68 	 * @class
 69 	 *
 70 	 * Base namespace for the Gentics Content.Node JavaScript API.
 71 	 */
 72 	var GCN = global.GCN || {};
 73 
 74 	jQuery.extend(GCN, {
 75 		/** @lends GCN */
 76 
 77 		/**
 78 		 * @type {object} Reference to the global context.
 79 		 */
 80 		global: global,
 81 
 82 		/**
 83 		 * @type {object<string, string>} Settings for the Gentics Content.Node
 84 		 *                                JavaScript API.
 85 		 */
 86 		settings: {
 87 
 88 			/**
 89 			 * @name settings.lang
 90 			 * @memberOf GCN
 91 			 * @type {string} The language code with which to render tags.
 92 			 */
 93 			lang: 'en',
 94 
 95 			/**
 96 			 * @const
 97 			 * @name settings.BACKEND_PATH
 98 			 * @memberOf GCN
 99 			 * @type {string} Default GCN backend path. Do not add a trailing
100 			 *                slash here.
101 			 */
102 			BACKEND_PATH: '/CNPortletapp',
103 
104 			/**
105 			 * @const
106 			 * @name settings.MAGIC_LINK
107 			 * @memberOf GCN
108 			 * @type {string} The keyword for the construct that defines Aloha
109 			 *                Editor links.  In most Content.Node installations
110 			 *                this will be "gtxalohapagelink", but can be
111 			 *                otherwise defined.
112 			 */
113 			MAGIC_LINK: 'gtxalohapagelink',
114 
115 			/**
116 			 * @const
117 			 * @name settings.linksRenderMode
118 			 * @memberOf GCN
119 			 * @type {string} Determines whether links will be rendered as
120 			 *                back-end urls or front-end urls.  Can either be
121 			 *                set to "backend" or "frontend".
122 			 */
123 			linksRenderMode: 'backend',
124 
125 			/**
126 			 * @memberOf GCN
127 			 * @default false
128 			 * @type {bool|int|string} Set a channelid to work on for
129 			 *                         multichannelling or false if no channel
130 			 *                         should be used
131 			 */
132 			channel: false
133 		},
134 
135 		/**
136 		 * Publish a message
137 		 *
138 		 * @param {string} message channel name
139 		 * @param {*=} params
140 		 */
141 		pub: function (channel, params) {
142 			if (!hasOnErrorHandler && channel === 'error-encountered') {
143 				// throw an error if there is no subscription to
144 				// error-encountered.
145 				throw params;
146 			}
147 
148 			jQuery(GCN).trigger(channel, params);
149 		},
150 
151 		/**
152 		 * Subscribe to a message channel
153 		 *
154 		 * @param {string} message channel name
155 		 * @param {function} handler function - message parameters will be
156 		 *                           passed.
157 		 */
158 		sub: function (channel, handler) {
159 			// register default handlers
160 			switch (channel) {
161 			case 'error-encountered':
162 				hasOnErrorHandler = true;
163 				break;
164 			case 'content-rendered':
165 				hasOnRenderHandler = true;
166 				break;
167 			case 'authentication-required':
168 				hasAuthenticationHandler = true;
169 				break;
170 			}
171 
172 			jQuery(GCN).bind(channel, function (event, param1, param2, param3) {
173 				handler(param1, param2, param3);
174 			});
175 		},
176 
177 		/**
178 		 * Tigger an error message 'error-encountered'.
179 		 *
180 		 * @param {string} error code
181 		 * @param {string} error message
182 		 * @param {object} additional error data
183 		 */
184 		error: function (code, message, data) {
185 			var error = new GCNError(code, message, data);
186 			this.pub('error-encountered', error);
187 		},
188 
189 		/**
190 		 * Returns an object containing the formal error fields.  The object
191 		 * contains a `toString' method to print any uncaught exceptions
192 		 * nicely.
193 		 *
194 		 * @param {string} code
195 		 * @param {string} message
196 		 * @param {object} data
197 		 * @return {GCNError}
198 		 */
199 		createError: function (code, message, data) {
200 			return new GCNError(code, message, data);
201 		},
202 
203 		/**
204 		 * Wraps the `jQuery.ajax()' method.
205 		 *
206 		 * @public
207 		 * @param {object} settings
208 		 * @throws HTTP_ERROR
209 		 */
210 		ajax: function (settings) {
211 			if (settings.json) {
212 				settings.data = JSON.stringify(settings.json);
213 				delete settings.json;
214 			}
215 			settings.dataType = 'json';
216 			settings.contentType = 'application/json; charset=utf-8';
217 			jQuery.ajax(settings);
218 		},
219 
220 		/**
221 		 * Set links render mode if a parameter is given
222 		 * retrieve it if not
223 		 *
224 		 * @param {string} mode
225 		 * @return {string} mode
226 		 */
227 		linksRenderMode: function (mode) {
228 			if (mode) {
229 				GCN.settings.linksRenderMode = mode;
230 			}
231 			return GCN.settings.linksRenderMode;
232 		},
233 
234 		/**
235 		 * Set channel if a parameter is given retrieve it otherwise.
236 		 *
237 		 * If you don't want to work on a channel just set it to false, which
238 		 * is the default value.
239 		 *
240 		 * @param {string|boolean} channel The id of the channel to be set.
241 		 * @return {string} current channel id.
242 		 */
243 		channel: function (channel) {
244 			if (channel || false === channel) {
245 				GCN.settings.channel = channel;
246 			}
247 			return GCN.settings.channel;
248 		},
249 
250 		/**
251 		 * @param {string} html Rendered content
252 		 * @param {Chainback} contentObject The ContentObject which was
253 		 *                                  rendered.
254 		 * @param {function(html)} callback Receives the processed html.
255 		 */
256 		_handleContentRendered: function (html, contentObject, callback) {
257 			if (hasOnRenderHandler) {
258 				GCN.pub('content-rendered', [html, contentObject, callback]);
259 			} else {
260 				callback(html);
261 			}
262 		},
263 
264 		/**
265 		 * Handles the ajax transport error.  It will invoke the custom error
266 		 * handler if one is provided, and propagate the error onto the global
267 		 * handler if the an error handler does not return `false'.
268 		 *
269 		 * @param {object} xhr
270 		 * @param {string} msg The error message
271 		 * @param {function} handler Custom error handler.
272 		 * @throws HTTP_ERROR
273 		 */
274 		handleHttpError: function (xhr, msg, handler) {
275 			var throwException = true;
276 
277 			if (handler) {
278 				throwException = handler(GCN.createError('HTTP_ERROR', msg,
279 					xhr));
280 			}
281 
282 			if (throwException !== 'false') {
283 				GCN.error('HTTP_ERROR', msg, xhr);
284 			}
285 		},
286 
287 		/**
288 		 * Handles error that occur when an ajax request succeeds but the
289 		 * backend responds with an error.
290 		 *
291 		 * @param {object} reponse The REST API response object.
292 		 * @param {function(GCNError):boolean} handler Custom error handler.
293 		 */
294 		handleResponseError: function (response, handler) {
295 			var info = response.responseInfo;
296 			var throwException = true;
297 
298 			if (handler) {
299 				throwException = handler(GCN.createError(
300 					info.responseCode,
301 					info.responseMessage,
302 					response
303 				));
304 			}
305 
306 			if (throwException !== false) {
307 				GCN.error(info.responseCode, info.responseMessage, response);
308 			}
309 		},
310 
311 		/**
312 		 * Tiggers the GCN error event.
313 		 *
314 		 * @param {GCNError} error
315 		 * @param {function(GCNError):boolean} handler Custom error handler.
316 		 * @return {boolean} Whether or not to the exception was thrown.
317 		 */
318 		handleError: function (error, handler) {
319 			var throwException = true;
320 
321 			if (handler) {
322 				throwException = handler(error);
323 			}
324 
325 			if (throwException !== false) {
326 				GCN.error(error.code, error.message, error.data);
327 			}
328 
329 			return throwException;
330 		},
331 
332 		/**
333 		 * Check if an authentication handler has been registered.
334 		 *
335 		 * @return {boolean} True if an handler for the
336 		 *                   'authentication-required' message has been
337 		 *                   registered.
338 		 */
339 		_hasAuthenticationHandler: function () {
340 			return hasAuthenticationHandler;
341 		}
342 
343 	});
344 
345 	// Expose the Gentics Content.Node JavaScript API to the global context.
346 	// This will be `window' in most cases.
347 	return (global.GCN = GCN);
348 
349 }(typeof global !== 'undefined' ? global : window));
350