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