1 /** 2 * TAO API core. 3 * It provides the tools to set up the environment, 4 * stock the data and push them to the server 5 * 6 * @author CRP Henri Tudor - TAO Team - {@link http://www.tao.lu} 7 * @license GPLv2 http://www.opensource.org/licenses/gpl-2.0.php 8 * @package taoItems 9 * @requires jquery >= 1.4.0 {@link http://www.jquery.com} 10 */ 11 12 /** 13 * The TaoStack class enables you: 14 * - to set up the platform to communicate with 15 * (it's by default the TAO plateform but could be any other with the same services provided by the server side) 16 * - to set and get variables created by the user or defined by the platform 17 * - to manage the source of data that the item could need 18 * - to push the communications with the platform 19 * 20 * @class TaoStack 21 */ 22 function TaoStack (){ 23 24 25 /** 26 * This object describes the way the data are accessed 27 * @fieldOf TaoStack 28 * @type {Object} 29 */ 30 this.dataSource = new Object(); 31 32 //default data source environment 33 this.dataSource.environment = { 34 'type' : 'async', // (manual|sync|async) 35 'url' : root_url + '/taoDelivery/ResultDelivery/initialize', // the url to the server [NOT for manual type] 36 'params' : { } // the key/values to send to the server [NOT for manual type] 37 }; 38 39 //default data source settings 40 this.dataSource.settings = { 41 'format' : 'json', //only json is supported 42 'method' : 'post', //HTTP method (get|post) [NOT for manual type] 43 'load' : 'onInit' // when the source is loaded (ONLY onInit is currently supported] 44 }; 45 46 /** 47 * This object stores the contextual data (sent by the server on load, or on getting them) 48 * @fieldOf TaoStack 49 * @type {Object} 50 */ 51 this.dataStore = new Object(); 52 53 /** 54 * Initialize and setup the data source. 55 * 56 * @methodOf TaoStack 57 * 58 * @param {Object} environment 59 * @see TaoStack.dataSource.environment 60 * 61 * @param {Object} settings 62 * @see TaoStack.dataSource.settings 63 * 64 * @param {Object} source if manual data source 65 */ 66 this.initDataSource = function(environment, settings, source){ 67 if($.inArray(environment.type, ['manual','sync','async']) > -1){ 68 69 this.dataSource.environment.type = environment.type; 70 71 if(this.dataSource.environment.type != 'manual'){ 72 73 //set the source url 74 if(environment.url){ 75 if(/(\/[-a-z\d%_.~+]*)*(\?[;&a-z\d%_.~+=-]*)?(\#[-a-z\d_]*)?$/.test(environment.url)){ //test url format 76 this.dataSource.environment.url = url; 77 } 78 } 79 80 //and the parameters to add 81 if($.isPlainObject(environment.params)){ 82 for(key in params){ 83 if(isScalar(environment.params[key])){ 84 this.dataSource.environment.params[key] = environment.params[key]+''; 85 } 86 } 87 } 88 } 89 90 //set the source settings 91 if($.isPlainObject(settings)){ 92 if(settings.method){ //only the method is supported now 93 if(/^get|post$/i.test(settings.method)){ 94 this.dataSource.settings.method = settings.method; 95 } 96 } 97 } 98 99 //load the source 100 if(this.dataSource.settings.load == 'onInit'){ 101 this.loadData(source); 102 } 103 } 104 }; 105 106 /** 107 * Load the contextual data 108 * @methodOf TaoStack 109 * @param {Object} [source] the data ONLY for the manual source 110 */ 111 this.loadData = function(source){ 112 113 /** 114 * Assign the 115 * @param {Object} data to the 116 * @param {TaoStack} instance 117 */ 118 var populateData = function(data, instance){ 119 //we filter on what we want 120 if($.isPlainObject(data)){ 121 for(key in data){ 122 for(uriKey in URI){ 123 if(URI[uriKey] == key || $.inArray(key, ['token', 'localNamespace']) > -1){ 124 instance.dataStore[key] = data[key]; 125 } 126 } 127 } 128 } 129 }; 130 131 if(this.dataSource.environment.type == 'manual' && source != null){ 132 133 //manual loading 134 populateData(source, this); 135 } 136 else{ 137 138 //sync|async loading, use an ajax request 139 var params = this.dataSource.environment.params; 140 var instance = this; 141 $.ajax({ 142 'url' : this.dataSource.environment.url, 143 'data' : params, 144 'type' : this.dataSource.settings.method, 145 'async' : (this.dataSource.environment.type == 'async'), 146 'dataType' : this.dataSource.settings.format, 147 'success' : function(data){ 148 //we load the data sent back by the remote source, in the FORMAT defined 149 150 if(data.token){ // the token field is MANDATORY 151 populateData(data, instance); 152 } 153 } 154 }); 155 } 156 }; 157 158 /** 159 * The push data 160 * @fieldOf TaoStack 161 * @type {Object} 162 */ 163 this.dataPush = new Object(); 164 this.dataPush.environment = { 165 'url' : root_url + '/taoDelivery/ResultDelivery/save', // the url to the server 166 'params' : { // the params to send to the server at each communication 167 'token' : this.dataStore.token //these parameters comes from the dataStore 168 } 169 }; 170 this.dataPush.settings = { 171 'format' : 'json', //only json is supported 172 'method' : 'post', //HTTP method to push the data (get|post) 173 'async' : false, //if the request is asynchrone 174 'clearAfter' : true //if the variables stacks are cleared once pushed 175 }; 176 177 178 /** 179 * Initialize and setup the push. 180 * 181 * @methodOf TaoStack 182 * 183 * @param {Object} environment 184 * @see TaoStack#dataPush#environment 185 * @param {Object} settings 186 * @see TaoStack#dataPush#settings 187 */ 188 this.initPush = function(environment, settings){ 189 190 if($.isPlainObject(environment)){ 191 if(environment.url){ 192 if(/(\/[-a-z\d%_.~+]*)*(\?[;&a-z\d%_.~+=-]*)?(\#[-a-z\d_]*)?$/.test(environment.url)){ //test url 193 this.dataPush.environment.url = environment.url; //set url 194 } 195 } 196 197 //ADD parameters 198 if($.isPlainObject(environment.params)){ 199 for(key in environment.params){ 200 if(isScalar(environment.params[key]) && !this.dataPush.environment.params[key]){ //don't edit the common params 201 this.dataPush.environment.params[key] = environment.params[key]; 202 } 203 } 204 } 205 } 206 207 //set push settings 208 if($.isPlainObject(settings)){ 209 if(settings.method){ 210 if(/^get|post$/i.test(settings.method)){ 211 this.dataPush.settings.method = settings.method; 212 } 213 } 214 if(settings.async === false){ 215 this.dataPush.settings.async = false; 216 } 217 if(settings.clearAfter === false){ 218 this.dataPush.settings.clearAfter = false; 219 } 220 } 221 }; 222 223 /** 224 * push all the data in the stack to the server 225 * @methodOf TaoStack 226 */ 227 this.push = function(){ 228 229 var params = this.dataPush.environment.params; //common parameters 230 if(params.token == undefined){ 231 params.token = this.dataStore.token; 232 } 233 params['taoVars'] = new Object(); 234 params['userVars'] = this.userVars; 235 236 for (key in this.taoVars){ //tao variables 237 if(/^##NAMESPACE#/.test(key) && this.dataStore.localNamespace != undefined){ 238 newkey = key.replace('##NAMESPACE', this.dataStore.localNamespace); //replace the localNamespace 239 params['taoVars'][newkey]= this.taoVars[key]; 240 } 241 else{ 242 params['taoVars'][key]= this.taoVars[key]; 243 } 244 } 245 246 247 //push the data to the server 248 if(this.dataPush.settings.async === true){ 249 var _instance = this; 250 $.ajax({ 251 'url' : this.dataPush.environment.url, 252 'data' : params, 253 'type' : this.dataPush.settings.method, 254 'async' : true, 255 'dataType' : this.dataPush.settings.format, 256 'success' : function(data){ 257 258 //the server send back the push status as 259 //@example {"saved": true} or {"saved": false} for a json format 260 if(data.saved == true){ 261 //clear the stack 262 if(_instance.dataPush.settings.clearAfter === true){ 263 _instance.taoVars = new Object(); 264 _instance.userVars = new Object(); 265 } 266 } 267 } 268 }); 269 } 270 else{ 271 received = $.parseJSON($.ajax({ 272 async : false, 273 url : this.dataPush.environment.url, 274 data : params, 275 type : this.dataPush.settings.method 276 }).responseText); 277 if(received.saved == true){ 278 //clear the stack 279 if(this.dataPush.settings.clearAfter === true){ 280 this.taoVars = new Object(); 281 this.userVars = new Object(); 282 } 283 } 284 } 285 }; 286 287 /* TAO Variables */ 288 289 /** 290 * The stack container 291 * @fieldOf TaoStack 292 * @type {Object} 293 */ 294 this.taoVars = new Object(); 295 296 /** 297 * Get the value of a TAO varaiable identified by the key 298 * 299 * @methodOf TaoStack 300 * 301 * @param {String} key 302 * @param {boolean} [label] if you want to retrieve the label instead of the complete Object 303 * @returns {mixed} value (false if the key is not found) 304 */ 305 this.getTaoVar = function(key, label){ 306 307 //we check if the data are 308 var value = false; 309 if(this.taoVars[key]){ //set by the taoVar 310 value = this.taoVars[key]; 311 } 312 else if (this.dataStore[key]){ //or comes from the dataStore 313 value = this.dataStore[key]; 314 } 315 316 if($.isPlainObject(value)){ 317 if( (value['uri'] != undefined && value[URI.LABEL] != undefined && value.length == 2) || label){ 318 return value[URI.LABEL]; 319 } 320 } 321 return value; 322 }; 323 324 /** 325 * The set method is restricted to scalar, 326 * but could be used to reference a property node 327 * 328 * @methodOf TaoStack 329 * 330 * @param {String} key 331 * @param {String|number|boolean} value 332 * @param {String} [property] the property uri 333 */ 334 this.setTaoVar = function(key, value, property){ 335 336 if(isScalar(value)){ 337 338 var currentValue = this.getTaoVar(key); 339 if($.isPlainObject(currentValue)){ 340 if(property){ 341 this.taoVars[key][property] = value; 342 } 343 else if( value.indexOf('uri') > -1 && value.indexOf(URI.LABEL) > -1){ 344 this.taoVars[key][URI.LABEL] = value; 345 } 346 } 347 else{ 348 this.taoVars[key] = value; 349 } 350 } 351 }; 352 353 /* Custom Variables */ 354 355 /** 356 * The user custom variables container 357 * @fieldOf TaoStack 358 * @type {Object} 359 */ 360 this.userVars = new Object(); 361 362 /** 363 * Get the value of a previously defined user's custom variable, identified by it's key 364 * 365 * @methodOf TaoStack 366 * 367 * @param {String} key 368 * @returns {String|number|boolean} value (false if the key is not found) 369 */ 370 this.getUserVar = function(key){ 371 return (this.userVars[key]) ? this.userVars[key] : false; 372 }; 373 374 /** 375 * The item author can define it's own variables in order to keep them in the stack 376 * and to send them to the plateform. It's usefull to record cutom field and values 377 * that have not been taken in consideration but have a real interest in the item. 378 * 379 * @methodOf TaoStack 380 * 381 * @param {String} key 382 * @param {String|number|boolean} value 383 */ 384 this.setUserVar = function(key, value){ 385 if(isScalar(value)){ 386 this.userVars[key] = value; 387 } 388 }; 389 } 390 391 392 /** 393 * Utility function to check if a value is a scalar: 394 * (string, integer, float and boolean) 395 * 396 * @param {mixed} value 397 * @returns {bool} true if it's a scalar 398 */ 399 function isScalar(value){ 400 return ($.inArray((typeof value).toLowerCase(), ['string', 'number', 'int', 'float', 'boolean']) > -1); 401 } 402