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