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 'content-rendered': 181 hasOnRenderHandler = true; 182 break; 183 case 'authentication-required': 184 hasAuthenticationHandler = true; 185 break; 186 } 187 188 jQuery(GCN).bind(channel, function (event, param1, param2, param3) { 189 handler(param1, param2, param3); 190 }); 191 }, 192 193 /** 194 * Tigger an error message 'error-encountered'. 195 * 196 * @param {string} error code 197 * @param {string} error message 198 * @param {object} additional error data 199 */ 200 error: function (code, message, data) { 201 var error = new GCNError(code, message, data); 202 this.pub('error-encountered', error); 203 }, 204 205 /** 206 * Returns an object containing the formal error fields. The object 207 * contains a `toString' method to print any uncaught exceptions 208 * nicely. 209 * 210 * @param {string} code 211 * @param {string} message 212 * @param {object} data 213 * @return {GCNError} 214 */ 215 createError: function (code, message, data) { 216 return new GCNError(code, message, data); 217 }, 218 219 /** 220 * Wraps the `jQuery.ajax()' method. 221 * 222 * @public 223 * @param {object} settings 224 * @throws HTTP_ERROR 225 */ 226 ajax: function (settings) { 227 if (settings.json) { 228 settings.data = JSON.stringify(settings.json); 229 delete settings.json; 230 } 231 settings.dataType = 'json'; 232 settings.contentType = 'application/json; charset=utf-8'; 233 jQuery.ajax(settings); 234 }, 235 236 /** 237 * Set links render mode if a parameter is given 238 * retrieve it if not 239 * 240 * @param {string} mode 241 * @return {string} mode 242 */ 243 linksRenderMode: function (mode) { 244 if (mode) { 245 GCN.settings.linksRenderMode = mode; 246 } 247 return GCN.settings.linksRenderMode; 248 }, 249 250 /** 251 * Set channel if a parameter is given retrieve it otherwise. 252 * 253 * If you don't want to work on a channel just set it to false, which 254 * is the default value. 255 * 256 * @param {string|boolean} channel The id of the channel to be set or false to unset the channel. 257 * @return {string} current channel id. 258 */ 259 channel: function (channel) { 260 if (channel || false === channel) { 261 GCN.settings.channel = channel; 262 } 263 return GCN.settings.channel; 264 }, 265 266 /** 267 * Constructs the nodeId query parameter for rest calls. 268 * 269 * @param {AbstractContentObject} contentObject A content object instance. 270 * @param {string=} delimiter Optional delimiter character. 271 * @return {string} Query parameter string. 272 */ 273 _getChannelParameter: function (contentObject, delimiter) { 274 if (false === contentObject._channel) { 275 return ''; 276 } 277 return (delimiter || '?') + 'nodeId=' + contentObject._channel; 278 }, 279 280 /** 281 * @param {string} html Rendered content 282 * @param {Chainback} contentObject The ContentObject which was 283 * rendered. 284 * @param {function(html)} callback Receives the processed html. 285 */ 286 _handleContentRendered: function (html, contentObject, callback) { 287 if (hasOnRenderHandler) { 288 GCN.pub('content-rendered', [html, contentObject, callback]); 289 } else { 290 callback(html); 291 } 292 }, 293 294 /** 295 * Handles the ajax transport error. It will invoke the custom error 296 * handler if one is provided, and propagate the error onto the global 297 * handler if the an error handler does not return `false'. 298 * 299 * @param {object} xhr 300 * @param {string} msg The error message 301 * @param {function} handler Custom error handler. 302 * @throws HTTP_ERROR 303 */ 304 handleHttpError: function (xhr, msg, handler) { 305 var throwException = true; 306 307 if (handler) { 308 throwException = handler(GCN.createError('HTTP_ERROR', msg, 309 xhr)); 310 } 311 312 if (throwException !== 'false') { 313 GCN.error('HTTP_ERROR', msg, xhr); 314 } 315 }, 316 317 /** 318 * Handles error that occur when an ajax request succeeds but the 319 * backend responds with an error. 320 * 321 * @param {object} reponse The REST API response object. 322 * @param {function(GCNError):boolean} handler Custom error handler. 323 */ 324 handleResponseError: function (response, handler) { 325 var info = response.responseInfo; 326 var throwException = true; 327 328 if (handler) { 329 throwException = handler(GCN.createError( 330 info.responseCode, 331 info.responseMessage, 332 response 333 )); 334 } 335 336 if (throwException !== false) { 337 GCN.error(info.responseCode, info.responseMessage, response); 338 } 339 }, 340 341 /** 342 * Tiggers the GCN error event. 343 * 344 * @param {GCNError} error 345 * @param {function(GCNError):boolean} handler Custom error handler. 346 * @return {boolean} Whether or not to the exception was thrown. 347 */ 348 handleError: function (error, handler) { 349 var throwException = true; 350 351 if (handler) { 352 throwException = handler(error); 353 } 354 355 if (throwException !== false) { 356 GCN.error(error.code, error.message, error.data); 357 } 358 359 return throwException; 360 }, 361 362 /** 363 * Check if an authentication handler has been registered. 364 * 365 * @return {boolean} True if an handler for the 366 * 'authentication-required' message has been 367 * registered. 368 */ 369 _hasAuthenticationHandler: function () { 370 return hasAuthenticationHandler; 371 } 372 373 }); 374 375 // Expose the Gentics Content.Node JavaScript API to the global context. 376 // This will be `window' in most cases. 377 return (global.GCN = GCN); 378 379 }(typeof global !== 'undefined' ? global : window)); 380