1*4882a593Smuzhiyun"use strict"; 2*4882a593Smuzhiyun/* All shared functionality to go in libtoaster object. 3*4882a593Smuzhiyun * This object really just helps readability since we can then have 4*4882a593Smuzhiyun * a traceable namespace. 5*4882a593Smuzhiyun */ 6*4882a593Smuzhiyunvar libtoaster = (function () { 7*4882a593Smuzhiyun // prevent conflicts with Bootstrap 2's typeahead (required during 8*4882a593Smuzhiyun // transition from v2 to v3) 9*4882a593Smuzhiyun var typeahead = jQuery.fn.typeahead.noConflict(); 10*4882a593Smuzhiyun jQuery.fn._typeahead = typeahead; 11*4882a593Smuzhiyun 12*4882a593Smuzhiyun /* Make a typeahead from an input element 13*4882a593Smuzhiyun * 14*4882a593Smuzhiyun * _makeTypeahead parameters 15*4882a593Smuzhiyun * jQElement: input element as selected by $('selector') 16*4882a593Smuzhiyun * xhrUrl: the url to get the JSON from; this URL should return JSON in the 17*4882a593Smuzhiyun * format: 18*4882a593Smuzhiyun * { "results": [ { "name": "test", "detail" : "a test thing" }, ... ] } 19*4882a593Smuzhiyun * xhrParams: the data/parameters to pass to the getJSON url e.g. 20*4882a593Smuzhiyun * { 'type' : 'projects' }; the text typed will be passed as 'search'. 21*4882a593Smuzhiyun * selectedCB: function to call once an item has been selected; has 22*4882a593Smuzhiyun * signature selectedCB(item), where item is an item in the format shown 23*4882a593Smuzhiyun * in the JSON list above, i.e. 24*4882a593Smuzhiyun * { "name": "name", "detail": "detail" }. 25*4882a593Smuzhiyun */ 26*4882a593Smuzhiyun function _makeTypeahead(jQElement, xhrUrl, xhrParams, selectedCB) { 27*4882a593Smuzhiyun if (!xhrUrl || xhrUrl.length === 0) { 28*4882a593Smuzhiyun throw("No url supplied for typeahead"); 29*4882a593Smuzhiyun } 30*4882a593Smuzhiyun 31*4882a593Smuzhiyun var xhrReq; 32*4882a593Smuzhiyun 33*4882a593Smuzhiyun jQElement._typeahead( 34*4882a593Smuzhiyun { 35*4882a593Smuzhiyun highlight: true, 36*4882a593Smuzhiyun classNames: { 37*4882a593Smuzhiyun open: "dropdown-menu", 38*4882a593Smuzhiyun cursor: "active" 39*4882a593Smuzhiyun } 40*4882a593Smuzhiyun }, 41*4882a593Smuzhiyun { 42*4882a593Smuzhiyun source: function (query, syncResults, asyncResults) { 43*4882a593Smuzhiyun xhrParams.search = query; 44*4882a593Smuzhiyun 45*4882a593Smuzhiyun // if we have a request in progress, cancel it and start another 46*4882a593Smuzhiyun if (xhrReq) { 47*4882a593Smuzhiyun xhrReq.abort(); 48*4882a593Smuzhiyun } 49*4882a593Smuzhiyun 50*4882a593Smuzhiyun xhrReq = $.getJSON(xhrUrl, xhrParams, function (data) { 51*4882a593Smuzhiyun if (data.error !== "ok") { 52*4882a593Smuzhiyun console.error("Error getting data from server: " + data.error); 53*4882a593Smuzhiyun return; 54*4882a593Smuzhiyun } 55*4882a593Smuzhiyun 56*4882a593Smuzhiyun xhrReq = null; 57*4882a593Smuzhiyun 58*4882a593Smuzhiyun asyncResults(data.results); 59*4882a593Smuzhiyun }); 60*4882a593Smuzhiyun }, 61*4882a593Smuzhiyun 62*4882a593Smuzhiyun // how the selected item is shown in the input 63*4882a593Smuzhiyun display: function (item) { 64*4882a593Smuzhiyun return item.name; 65*4882a593Smuzhiyun }, 66*4882a593Smuzhiyun 67*4882a593Smuzhiyun templates: { 68*4882a593Smuzhiyun // how the item is displayed in the dropdown 69*4882a593Smuzhiyun suggestion: function (item) { 70*4882a593Smuzhiyun var elt = document.createElement("div"); 71*4882a593Smuzhiyun elt.innerHTML = item.name + " " + item.detail; 72*4882a593Smuzhiyun return elt; 73*4882a593Smuzhiyun } 74*4882a593Smuzhiyun } 75*4882a593Smuzhiyun } 76*4882a593Smuzhiyun ); 77*4882a593Smuzhiyun 78*4882a593Smuzhiyun // when an item is selected using the typeahead, invoke the callback 79*4882a593Smuzhiyun jQElement.on("typeahead:select", function (event, item) { 80*4882a593Smuzhiyun selectedCB(item); 81*4882a593Smuzhiyun }); 82*4882a593Smuzhiyun } 83*4882a593Smuzhiyun 84*4882a593Smuzhiyun /* startABuild: 85*4882a593Smuzhiyun * url: xhr_buildrequest or null for current project 86*4882a593Smuzhiyun * targets: an array or space separated list of targets to build 87*4882a593Smuzhiyun * onsuccess: callback for successful execution 88*4882a593Smuzhiyun * onfail: callback for failed execution 89*4882a593Smuzhiyun */ 90*4882a593Smuzhiyun function _startABuild (url, targets, onsuccess, onfail) { 91*4882a593Smuzhiyun 92*4882a593Smuzhiyun if (!url) 93*4882a593Smuzhiyun url = libtoaster.ctx.xhrBuildRequestUrl; 94*4882a593Smuzhiyun 95*4882a593Smuzhiyun /* Flatten the array of targets into a space spearated list */ 96*4882a593Smuzhiyun if (targets instanceof Array){ 97*4882a593Smuzhiyun targets = targets.reduce(function(prevV, nextV){ 98*4882a593Smuzhiyun return prev + ' ' + next; 99*4882a593Smuzhiyun }); 100*4882a593Smuzhiyun } 101*4882a593Smuzhiyun 102*4882a593Smuzhiyun $.ajax( { 103*4882a593Smuzhiyun type: "POST", 104*4882a593Smuzhiyun url: url, 105*4882a593Smuzhiyun data: { 'targets' : targets }, 106*4882a593Smuzhiyun headers: { 'X-CSRFToken' : $.cookie('csrftoken')}, 107*4882a593Smuzhiyun success: function (_data) { 108*4882a593Smuzhiyun if (_data.error !== "ok") { 109*4882a593Smuzhiyun console.warn(_data.error); 110*4882a593Smuzhiyun } else { 111*4882a593Smuzhiyun if (onsuccess !== undefined) onsuccess(_data); 112*4882a593Smuzhiyun } 113*4882a593Smuzhiyun }, 114*4882a593Smuzhiyun error: function (_data) { 115*4882a593Smuzhiyun console.warn("Call failed"); 116*4882a593Smuzhiyun console.warn(_data); 117*4882a593Smuzhiyun if (onfail) onfail(data); 118*4882a593Smuzhiyun } }); 119*4882a593Smuzhiyun } 120*4882a593Smuzhiyun 121*4882a593Smuzhiyun /* cancelABuild: 122*4882a593Smuzhiyun * url: xhr_buildrequest url or null for current project 123*4882a593Smuzhiyun * buildRequestIds: space separated list of build request ids 124*4882a593Smuzhiyun * onsuccess: callback for successful execution 125*4882a593Smuzhiyun * onfail: callback for failed execution 126*4882a593Smuzhiyun */ 127*4882a593Smuzhiyun function _cancelABuild(url, buildRequestIds, onsuccess, onfail){ 128*4882a593Smuzhiyun if (!url) 129*4882a593Smuzhiyun url = libtoaster.ctx.xhrBuildRequestUrl; 130*4882a593Smuzhiyun 131*4882a593Smuzhiyun $.ajax( { 132*4882a593Smuzhiyun type: "POST", 133*4882a593Smuzhiyun url: url, 134*4882a593Smuzhiyun data: { 'buildCancel': buildRequestIds }, 135*4882a593Smuzhiyun headers: { 'X-CSRFToken' : $.cookie('csrftoken')}, 136*4882a593Smuzhiyun success: function (_data) { 137*4882a593Smuzhiyun if (_data.error !== "ok") { 138*4882a593Smuzhiyun console.warn(_data.error); 139*4882a593Smuzhiyun } else { 140*4882a593Smuzhiyun if (onsuccess) onsuccess(_data); 141*4882a593Smuzhiyun } 142*4882a593Smuzhiyun }, 143*4882a593Smuzhiyun error: function (_data) { 144*4882a593Smuzhiyun console.warn("Call failed"); 145*4882a593Smuzhiyun console.warn(_data); 146*4882a593Smuzhiyun if (onfail) onfail(_data); 147*4882a593Smuzhiyun } 148*4882a593Smuzhiyun }); 149*4882a593Smuzhiyun } 150*4882a593Smuzhiyun 151*4882a593Smuzhiyun function _getMostRecentBuilds(url, onsuccess, onfail) { 152*4882a593Smuzhiyun $.ajax({ 153*4882a593Smuzhiyun url: url, 154*4882a593Smuzhiyun type: 'GET', 155*4882a593Smuzhiyun data : {format: 'json'}, 156*4882a593Smuzhiyun headers: {'X-CSRFToken': $.cookie('csrftoken')}, 157*4882a593Smuzhiyun success: function (data) { 158*4882a593Smuzhiyun onsuccess ? onsuccess(data) : console.log(data); 159*4882a593Smuzhiyun }, 160*4882a593Smuzhiyun error: function (data) { 161*4882a593Smuzhiyun onfail ? onfail(data) : console.error(data); 162*4882a593Smuzhiyun } 163*4882a593Smuzhiyun }); 164*4882a593Smuzhiyun } 165*4882a593Smuzhiyun 166*4882a593Smuzhiyun /* Get a project's configuration info */ 167*4882a593Smuzhiyun function _getProjectInfo(url, onsuccess, onfail){ 168*4882a593Smuzhiyun $.ajax({ 169*4882a593Smuzhiyun type: "GET", 170*4882a593Smuzhiyun url: url, 171*4882a593Smuzhiyun headers: { 'X-CSRFToken' : $.cookie('csrftoken')}, 172*4882a593Smuzhiyun success: function (_data) { 173*4882a593Smuzhiyun if (_data.error !== "ok") { 174*4882a593Smuzhiyun console.warn(_data.error); 175*4882a593Smuzhiyun } else { 176*4882a593Smuzhiyun if (onsuccess !== undefined) onsuccess(_data); 177*4882a593Smuzhiyun } 178*4882a593Smuzhiyun }, 179*4882a593Smuzhiyun error: function (_data) { 180*4882a593Smuzhiyun console.warn(_data); 181*4882a593Smuzhiyun if (onfail) onfail(_data); 182*4882a593Smuzhiyun } 183*4882a593Smuzhiyun }); 184*4882a593Smuzhiyun } 185*4882a593Smuzhiyun 186*4882a593Smuzhiyun /* Properties for data can be: 187*4882a593Smuzhiyun * layerDel (csv) 188*4882a593Smuzhiyun * layerAdd (csv) 189*4882a593Smuzhiyun * projectName 190*4882a593Smuzhiyun * projectVersion 191*4882a593Smuzhiyun * machineName 192*4882a593Smuzhiyun */ 193*4882a593Smuzhiyun function _editCurrentProject(data, onSuccess, onFail){ 194*4882a593Smuzhiyun $.ajax({ 195*4882a593Smuzhiyun type: "POST", 196*4882a593Smuzhiyun url: libtoaster.ctx.xhrProjectUrl, 197*4882a593Smuzhiyun data: data, 198*4882a593Smuzhiyun headers: { 'X-CSRFToken' : $.cookie('csrftoken')}, 199*4882a593Smuzhiyun success: function (data) { 200*4882a593Smuzhiyun if (data.error != "ok") { 201*4882a593Smuzhiyun console.log(data.error); 202*4882a593Smuzhiyun if (onFail !== undefined) 203*4882a593Smuzhiyun onFail(data); 204*4882a593Smuzhiyun } else { 205*4882a593Smuzhiyun if (onSuccess !== undefined) 206*4882a593Smuzhiyun onSuccess(data); 207*4882a593Smuzhiyun } 208*4882a593Smuzhiyun }, 209*4882a593Smuzhiyun error: function (data) { 210*4882a593Smuzhiyun console.log("Call failed"); 211*4882a593Smuzhiyun console.log(data); 212*4882a593Smuzhiyun } 213*4882a593Smuzhiyun }); 214*4882a593Smuzhiyun } 215*4882a593Smuzhiyun 216*4882a593Smuzhiyun function _getLayerDepsForProject(url, onSuccess, onFail){ 217*4882a593Smuzhiyun /* Check for dependencies not in the current project */ 218*4882a593Smuzhiyun $.getJSON(url, 219*4882a593Smuzhiyun { format: 'json' }, 220*4882a593Smuzhiyun function(data) { 221*4882a593Smuzhiyun if (data.error != "ok") { 222*4882a593Smuzhiyun console.log(data.error); 223*4882a593Smuzhiyun if (onFail !== undefined) 224*4882a593Smuzhiyun onFail(data); 225*4882a593Smuzhiyun } else { 226*4882a593Smuzhiyun var deps = {}; 227*4882a593Smuzhiyun /* Filter out layer dep ids which are in the 228*4882a593Smuzhiyun * project already. 229*4882a593Smuzhiyun */ 230*4882a593Smuzhiyun deps.list = data.layerdeps.list.filter(function(layerObj){ 231*4882a593Smuzhiyun return (data.projectlayers.lastIndexOf(layerObj.id) < 0); 232*4882a593Smuzhiyun }); 233*4882a593Smuzhiyun 234*4882a593Smuzhiyun onSuccess(deps); 235*4882a593Smuzhiyun } 236*4882a593Smuzhiyun }, function() { 237*4882a593Smuzhiyun console.log("E: Failed to make request"); 238*4882a593Smuzhiyun }); 239*4882a593Smuzhiyun } 240*4882a593Smuzhiyun 241*4882a593Smuzhiyun /* parses the query string of the current window.location to an object */ 242*4882a593Smuzhiyun function _parseUrlParams() { 243*4882a593Smuzhiyun var string = window.location.search; 244*4882a593Smuzhiyun string = string.substr(1); 245*4882a593Smuzhiyun var stringArray = string.split ("&"); 246*4882a593Smuzhiyun var obj = {}; 247*4882a593Smuzhiyun 248*4882a593Smuzhiyun for (var i in stringArray) { 249*4882a593Smuzhiyun var keyVal = stringArray[i].split ("="); 250*4882a593Smuzhiyun obj[keyVal[0]] = keyVal[1]; 251*4882a593Smuzhiyun } 252*4882a593Smuzhiyun 253*4882a593Smuzhiyun return obj; 254*4882a593Smuzhiyun } 255*4882a593Smuzhiyun 256*4882a593Smuzhiyun /* takes a flat object and outputs it as a query string 257*4882a593Smuzhiyun * e.g. the output of dumpsUrlParams 258*4882a593Smuzhiyun */ 259*4882a593Smuzhiyun function _dumpsUrlParams(obj) { 260*4882a593Smuzhiyun var str = "?"; 261*4882a593Smuzhiyun 262*4882a593Smuzhiyun for (var key in obj){ 263*4882a593Smuzhiyun if (!obj[key]) 264*4882a593Smuzhiyun continue; 265*4882a593Smuzhiyun 266*4882a593Smuzhiyun str += key+ "="+obj[key].toString(); 267*4882a593Smuzhiyun str += "&"; 268*4882a593Smuzhiyun } 269*4882a593Smuzhiyun 270*4882a593Smuzhiyun /* Maintain the current hash */ 271*4882a593Smuzhiyun str += window.location.hash; 272*4882a593Smuzhiyun 273*4882a593Smuzhiyun return str; 274*4882a593Smuzhiyun } 275*4882a593Smuzhiyun 276*4882a593Smuzhiyun function _addRmLayer(layerObj, add, doneCb){ 277*4882a593Smuzhiyun if (layerObj.xhrLayerUrl === undefined){ 278*4882a593Smuzhiyun alert("ERROR: missing xhrLayerUrl object. Please file a bug."); 279*4882a593Smuzhiyun return; 280*4882a593Smuzhiyun } 281*4882a593Smuzhiyun 282*4882a593Smuzhiyun if (add === true) { 283*4882a593Smuzhiyun /* If adding get the deps for this layer */ 284*4882a593Smuzhiyun libtoaster.getLayerDepsForProject(layerObj.xhrLayerUrl, 285*4882a593Smuzhiyun function (layers) { 286*4882a593Smuzhiyun 287*4882a593Smuzhiyun /* got result for dependencies */ 288*4882a593Smuzhiyun if (layers.list.length === 0){ 289*4882a593Smuzhiyun var editData = { layerAdd : layerObj.id }; 290*4882a593Smuzhiyun libtoaster.editCurrentProject(editData, function() { 291*4882a593Smuzhiyun doneCb([]); 292*4882a593Smuzhiyun }); 293*4882a593Smuzhiyun return; 294*4882a593Smuzhiyun } else { 295*4882a593Smuzhiyun try { 296*4882a593Smuzhiyun showLayerDepsModal(layerObj, layers.list, null, null, true, doneCb); 297*4882a593Smuzhiyun } catch (e) { 298*4882a593Smuzhiyun $.getScript(libtoaster.ctx.jsUrl + "layerDepsModal.js", function(){ 299*4882a593Smuzhiyun showLayerDepsModal(layerObj, layers.list, null, null, true, doneCb); 300*4882a593Smuzhiyun }, function(){ 301*4882a593Smuzhiyun console.warn("Failed to load layerDepsModal"); 302*4882a593Smuzhiyun }); 303*4882a593Smuzhiyun } 304*4882a593Smuzhiyun } 305*4882a593Smuzhiyun }, null); 306*4882a593Smuzhiyun } else if (add === false) { 307*4882a593Smuzhiyun var editData = { layerDel : layerObj.id }; 308*4882a593Smuzhiyun 309*4882a593Smuzhiyun libtoaster.editCurrentProject(editData, function () { 310*4882a593Smuzhiyun doneCb([]); 311*4882a593Smuzhiyun }, function () { 312*4882a593Smuzhiyun console.warn ("Removing layer from project failed"); 313*4882a593Smuzhiyun doneCb(null); 314*4882a593Smuzhiyun }); 315*4882a593Smuzhiyun } 316*4882a593Smuzhiyun } 317*4882a593Smuzhiyun 318*4882a593Smuzhiyun function _makeLayerAddRmAlertMsg(layer, layerDepsList, add) { 319*4882a593Smuzhiyun var alertMsg; 320*4882a593Smuzhiyun 321*4882a593Smuzhiyun if (layerDepsList.length > 0 && add === true) { 322*4882a593Smuzhiyun alertMsg = $("<span>You have added <strong>"+(layerDepsList.length+1)+"</strong> layers to your project: <a class=\"alert-link\" id=\"layer-affected-name\"></a> and its dependencies </span>"); 323*4882a593Smuzhiyun 324*4882a593Smuzhiyun /* Build the layer deps list */ 325*4882a593Smuzhiyun layerDepsList.map(function(layer, i){ 326*4882a593Smuzhiyun var link = $("<a class=\"alert-link\"></a>"); 327*4882a593Smuzhiyun 328*4882a593Smuzhiyun link.attr("href", layer.layerdetailurl); 329*4882a593Smuzhiyun link.text(layer.name); 330*4882a593Smuzhiyun link.tooltip({title: layer.tooltip}); 331*4882a593Smuzhiyun 332*4882a593Smuzhiyun if (i !== 0) 333*4882a593Smuzhiyun alertMsg.append(", "); 334*4882a593Smuzhiyun 335*4882a593Smuzhiyun alertMsg.append(link); 336*4882a593Smuzhiyun }); 337*4882a593Smuzhiyun } else if (layerDepsList.length === 0 && add === true) { 338*4882a593Smuzhiyun alertMsg = $("<span>You have added <strong>1</strong> layer to your project: <a class=\"alert-link\" id=\"layer-affected-name\"></a></span></span>"); 339*4882a593Smuzhiyun } else if (add === false) { 340*4882a593Smuzhiyun alertMsg = $("<span>You have removed <strong>1</strong> layer from your project: <a class=\"alert-link\" id=\"layer-affected-name\"></a></span>"); 341*4882a593Smuzhiyun } 342*4882a593Smuzhiyun 343*4882a593Smuzhiyun alertMsg.children("#layer-affected-name").text(layer.name); 344*4882a593Smuzhiyun alertMsg.children("#layer-affected-name").attr("href", layer.layerdetailurl); 345*4882a593Smuzhiyun 346*4882a593Smuzhiyun return alertMsg.html(); 347*4882a593Smuzhiyun } 348*4882a593Smuzhiyun 349*4882a593Smuzhiyun function _showChangeNotification(message){ 350*4882a593Smuzhiyun $(".alert-dismissible").fadeOut().promise().done(function(){ 351*4882a593Smuzhiyun var alertMsg = $("#change-notification-msg"); 352*4882a593Smuzhiyun 353*4882a593Smuzhiyun alertMsg.html(message); 354*4882a593Smuzhiyun $("#change-notification, #change-notification *").fadeIn(); 355*4882a593Smuzhiyun }); 356*4882a593Smuzhiyun } 357*4882a593Smuzhiyun 358*4882a593Smuzhiyun function _createCustomRecipe(name, baseRecipeId, doneCb){ 359*4882a593Smuzhiyun var data = { 360*4882a593Smuzhiyun 'name' : name, 361*4882a593Smuzhiyun 'project' : libtoaster.ctx.projectId, 362*4882a593Smuzhiyun 'base' : baseRecipeId, 363*4882a593Smuzhiyun }; 364*4882a593Smuzhiyun 365*4882a593Smuzhiyun $.ajax({ 366*4882a593Smuzhiyun type: "POST", 367*4882a593Smuzhiyun url: libtoaster.ctx.xhrCustomRecipeUrl, 368*4882a593Smuzhiyun data: data, 369*4882a593Smuzhiyun headers: { 'X-CSRFToken' : $.cookie('csrftoken')}, 370*4882a593Smuzhiyun success: function (ret) { 371*4882a593Smuzhiyun if (doneCb){ 372*4882a593Smuzhiyun doneCb(ret); 373*4882a593Smuzhiyun } else if (ret.error !== "ok") { 374*4882a593Smuzhiyun console.warn(ret.error); 375*4882a593Smuzhiyun } 376*4882a593Smuzhiyun }, 377*4882a593Smuzhiyun error: function (ret) { 378*4882a593Smuzhiyun console.warn("Call failed"); 379*4882a593Smuzhiyun console.warn(ret); 380*4882a593Smuzhiyun } 381*4882a593Smuzhiyun }); 382*4882a593Smuzhiyun } 383*4882a593Smuzhiyun 384*4882a593Smuzhiyun /* Validate project names. Use unique project names 385*4882a593Smuzhiyun 386*4882a593Smuzhiyun All arguments accepted by this function are JQeury objects. 387*4882a593Smuzhiyun 388*4882a593Smuzhiyun For example if the HTML element has "hint-error-project-name", then 389*4882a593Smuzhiyun it is passed to this function as $("#hint-error-project-name"). 390*4882a593Smuzhiyun 391*4882a593Smuzhiyun Arg1 - projectName : This is a string object. In the HTML, project name will be entered here. 392*4882a593Smuzhiyun Arg2 - hintEerror : This is a jquery object which will accept span which throws error for 393*4882a593Smuzhiyun duplicate project 394*4882a593Smuzhiyun Arg3 - ctrlGrpValidateProjectName : This object holds the div with class "control-group" 395*4882a593Smuzhiyun Arg4 - enableOrDisableBtn : This object will help the API to enable or disable the form. 396*4882a593Smuzhiyun For example in the new project the create project button will be hidden if the 397*4882a593Smuzhiyun duplicate project exist. Similarly in the projecttopbar the save button will be 398*4882a593Smuzhiyun disabled if the project name already exist. 399*4882a593Smuzhiyun 400*4882a593Smuzhiyun Return - This function doesn't return anything. It sets/unsets the behavior of the elements. 401*4882a593Smuzhiyun */ 402*4882a593Smuzhiyun 403*4882a593Smuzhiyun function _makeProjectNameValidation(projectName, hintError, 404*4882a593Smuzhiyun ctrlGrpValidateProjectName, enableOrDisableBtn ) { 405*4882a593Smuzhiyun 406*4882a593Smuzhiyun function checkProjectName(projectName){ 407*4882a593Smuzhiyun $.ajax({ 408*4882a593Smuzhiyun type: "GET", 409*4882a593Smuzhiyun url: libtoaster.ctx.projectsTypeAheadUrl, 410*4882a593Smuzhiyun data: { 'search' : projectName }, 411*4882a593Smuzhiyun headers: { 'X-CSRFToken' : $.cookie('csrftoken')}, 412*4882a593Smuzhiyun success: function(data){ 413*4882a593Smuzhiyun if (data.results.length > 0 && 414*4882a593Smuzhiyun data.results[0].name === projectName) { 415*4882a593Smuzhiyun // This project name exists hence show the error and disable 416*4882a593Smuzhiyun // the save button 417*4882a593Smuzhiyun ctrlGrpValidateProjectName.addClass('has-error'); 418*4882a593Smuzhiyun hintError.show(); 419*4882a593Smuzhiyun enableOrDisableBtn.attr('disabled', 'disabled'); 420*4882a593Smuzhiyun } else { 421*4882a593Smuzhiyun ctrlGrpValidateProjectName.removeClass('has-error'); 422*4882a593Smuzhiyun hintError.hide(); 423*4882a593Smuzhiyun enableOrDisableBtn.removeAttr('disabled'); 424*4882a593Smuzhiyun } 425*4882a593Smuzhiyun }, 426*4882a593Smuzhiyun error: function (data) { 427*4882a593Smuzhiyun console.log(data); 428*4882a593Smuzhiyun }, 429*4882a593Smuzhiyun }); 430*4882a593Smuzhiyun } 431*4882a593Smuzhiyun 432*4882a593Smuzhiyun /* The moment user types project name remove the error */ 433*4882a593Smuzhiyun projectName.on("input", function() { 434*4882a593Smuzhiyun var projectName = $(this).val(); 435*4882a593Smuzhiyun checkProjectName(projectName) 436*4882a593Smuzhiyun }); 437*4882a593Smuzhiyun 438*4882a593Smuzhiyun /* Validate new project name */ 439*4882a593Smuzhiyun projectName.on("blur", function(){ 440*4882a593Smuzhiyun var projectName = $(this).val(); 441*4882a593Smuzhiyun checkProjectName(projectName) 442*4882a593Smuzhiyun }); 443*4882a593Smuzhiyun } 444*4882a593Smuzhiyun 445*4882a593Smuzhiyun // if true, the loading spinner for Ajax requests will be displayed 446*4882a593Smuzhiyun // if requests take more than 1200ms 447*4882a593Smuzhiyun var ajaxLoadingTimerEnabled = true; 448*4882a593Smuzhiyun 449*4882a593Smuzhiyun // turn on the page-level loading spinner for Ajax requests 450*4882a593Smuzhiyun function _enableAjaxLoadingTimer() { 451*4882a593Smuzhiyun ajaxLoadingTimerEnabled = true; 452*4882a593Smuzhiyun } 453*4882a593Smuzhiyun 454*4882a593Smuzhiyun // turn off the page-level loading spinner for Ajax requests 455*4882a593Smuzhiyun function _disableAjaxLoadingTimer() { 456*4882a593Smuzhiyun ajaxLoadingTimerEnabled = false; 457*4882a593Smuzhiyun } 458*4882a593Smuzhiyun 459*4882a593Smuzhiyun /* Utility function to set a notification for the next page load */ 460*4882a593Smuzhiyun function _setNotification(name, message){ 461*4882a593Smuzhiyun var data = { 462*4882a593Smuzhiyun name: name, 463*4882a593Smuzhiyun message: message 464*4882a593Smuzhiyun }; 465*4882a593Smuzhiyun 466*4882a593Smuzhiyun $.cookie('toaster-notification', JSON.stringify(data), { path: '/'}); 467*4882a593Smuzhiyun } 468*4882a593Smuzhiyun 469*4882a593Smuzhiyun /* _updateProject: 470*4882a593Smuzhiyun * url: xhrProjectUpdateUrl or null for current project 471*4882a593Smuzhiyun * onsuccess: callback for successful execution 472*4882a593Smuzhiyun * onfail: callback for failed execution 473*4882a593Smuzhiyun */ 474*4882a593Smuzhiyun function _updateProject (url, targets, default_image, onsuccess, onfail) { 475*4882a593Smuzhiyun 476*4882a593Smuzhiyun if (!url) 477*4882a593Smuzhiyun url = libtoaster.ctx.xhrProjectUpdateUrl; 478*4882a593Smuzhiyun 479*4882a593Smuzhiyun /* Flatten the array of targets into a space spearated list */ 480*4882a593Smuzhiyun if (targets instanceof Array){ 481*4882a593Smuzhiyun targets = targets.reduce(function(prevV, nextV){ 482*4882a593Smuzhiyun return prev + ' ' + next; 483*4882a593Smuzhiyun }); 484*4882a593Smuzhiyun } 485*4882a593Smuzhiyun 486*4882a593Smuzhiyun $.ajax( { 487*4882a593Smuzhiyun type: "POST", 488*4882a593Smuzhiyun url: url, 489*4882a593Smuzhiyun data: { 'do_update' : 'True' , 'targets' : targets , 'default_image' : default_image , }, 490*4882a593Smuzhiyun headers: { 'X-CSRFToken' : $.cookie('csrftoken')}, 491*4882a593Smuzhiyun success: function (_data) { 492*4882a593Smuzhiyun if (_data.error !== "ok") { 493*4882a593Smuzhiyun console.warn(_data.error); 494*4882a593Smuzhiyun } else { 495*4882a593Smuzhiyun if (onsuccess !== undefined) onsuccess(_data); 496*4882a593Smuzhiyun } 497*4882a593Smuzhiyun }, 498*4882a593Smuzhiyun error: function (_data) { 499*4882a593Smuzhiyun console.warn("Call failed"); 500*4882a593Smuzhiyun console.warn(_data); 501*4882a593Smuzhiyun if (onfail) onfail(data); 502*4882a593Smuzhiyun } }); 503*4882a593Smuzhiyun } 504*4882a593Smuzhiyun 505*4882a593Smuzhiyun /* _cancelProject: 506*4882a593Smuzhiyun * url: xhrProjectUpdateUrl or null for current project 507*4882a593Smuzhiyun * onsuccess: callback for successful execution 508*4882a593Smuzhiyun * onfail: callback for failed execution 509*4882a593Smuzhiyun */ 510*4882a593Smuzhiyun function _cancelProject (url, onsuccess, onfail) { 511*4882a593Smuzhiyun 512*4882a593Smuzhiyun if (!url) 513*4882a593Smuzhiyun url = libtoaster.ctx.xhrProjectCancelUrl; 514*4882a593Smuzhiyun 515*4882a593Smuzhiyun $.ajax( { 516*4882a593Smuzhiyun type: "POST", 517*4882a593Smuzhiyun url: url, 518*4882a593Smuzhiyun data: { 'do_cancel' : 'True' }, 519*4882a593Smuzhiyun headers: { 'X-CSRFToken' : $.cookie('csrftoken')}, 520*4882a593Smuzhiyun success: function (_data) { 521*4882a593Smuzhiyun if (_data.error !== "ok") { 522*4882a593Smuzhiyun console.warn(_data.error); 523*4882a593Smuzhiyun } else { 524*4882a593Smuzhiyun if (onsuccess !== undefined) onsuccess(_data); 525*4882a593Smuzhiyun } 526*4882a593Smuzhiyun }, 527*4882a593Smuzhiyun error: function (_data) { 528*4882a593Smuzhiyun console.warn("Call failed"); 529*4882a593Smuzhiyun console.warn(_data); 530*4882a593Smuzhiyun if (onfail) onfail(data); 531*4882a593Smuzhiyun } }); 532*4882a593Smuzhiyun } 533*4882a593Smuzhiyun 534*4882a593Smuzhiyun /* _setDefaultImage: 535*4882a593Smuzhiyun * url: xhrSetDefaultImageUrl or null for current project 536*4882a593Smuzhiyun * targets: an array or space separated list of targets to set as default 537*4882a593Smuzhiyun * onsuccess: callback for successful execution 538*4882a593Smuzhiyun * onfail: callback for failed execution 539*4882a593Smuzhiyun */ 540*4882a593Smuzhiyun function _setDefaultImage (url, targets, onsuccess, onfail) { 541*4882a593Smuzhiyun 542*4882a593Smuzhiyun if (!url) 543*4882a593Smuzhiyun url = libtoaster.ctx.xhrSetDefaultImageUrl; 544*4882a593Smuzhiyun 545*4882a593Smuzhiyun /* Flatten the array of targets into a space spearated list */ 546*4882a593Smuzhiyun if (targets instanceof Array){ 547*4882a593Smuzhiyun targets = targets.reduce(function(prevV, nextV){ 548*4882a593Smuzhiyun return prev + ' ' + next; 549*4882a593Smuzhiyun }); 550*4882a593Smuzhiyun } 551*4882a593Smuzhiyun 552*4882a593Smuzhiyun $.ajax( { 553*4882a593Smuzhiyun type: "POST", 554*4882a593Smuzhiyun url: url, 555*4882a593Smuzhiyun data: { 'targets' : targets }, 556*4882a593Smuzhiyun headers: { 'X-CSRFToken' : $.cookie('csrftoken')}, 557*4882a593Smuzhiyun success: function (_data) { 558*4882a593Smuzhiyun if (_data.error !== "ok") { 559*4882a593Smuzhiyun console.warn(_data.error); 560*4882a593Smuzhiyun } else { 561*4882a593Smuzhiyun if (onsuccess !== undefined) onsuccess(_data); 562*4882a593Smuzhiyun } 563*4882a593Smuzhiyun }, 564*4882a593Smuzhiyun error: function (_data) { 565*4882a593Smuzhiyun console.warn("Call failed"); 566*4882a593Smuzhiyun console.warn(_data); 567*4882a593Smuzhiyun if (onfail) onfail(data); 568*4882a593Smuzhiyun } }); 569*4882a593Smuzhiyun } 570*4882a593Smuzhiyun 571*4882a593Smuzhiyun return { 572*4882a593Smuzhiyun enableAjaxLoadingTimer: _enableAjaxLoadingTimer, 573*4882a593Smuzhiyun disableAjaxLoadingTimer: _disableAjaxLoadingTimer, 574*4882a593Smuzhiyun reload_params : reload_params, 575*4882a593Smuzhiyun startABuild : _startABuild, 576*4882a593Smuzhiyun cancelABuild : _cancelABuild, 577*4882a593Smuzhiyun getMostRecentBuilds: _getMostRecentBuilds, 578*4882a593Smuzhiyun makeTypeahead : _makeTypeahead, 579*4882a593Smuzhiyun getProjectInfo: _getProjectInfo, 580*4882a593Smuzhiyun getLayerDepsForProject : _getLayerDepsForProject, 581*4882a593Smuzhiyun editCurrentProject : _editCurrentProject, 582*4882a593Smuzhiyun debug: false, 583*4882a593Smuzhiyun parseUrlParams : _parseUrlParams, 584*4882a593Smuzhiyun dumpsUrlParams : _dumpsUrlParams, 585*4882a593Smuzhiyun addRmLayer : _addRmLayer, 586*4882a593Smuzhiyun makeLayerAddRmAlertMsg : _makeLayerAddRmAlertMsg, 587*4882a593Smuzhiyun showChangeNotification : _showChangeNotification, 588*4882a593Smuzhiyun createCustomRecipe: _createCustomRecipe, 589*4882a593Smuzhiyun makeProjectNameValidation: _makeProjectNameValidation, 590*4882a593Smuzhiyun setNotification: _setNotification, 591*4882a593Smuzhiyun updateProject : _updateProject, 592*4882a593Smuzhiyun cancelProject : _cancelProject, 593*4882a593Smuzhiyun setDefaultImage : _setDefaultImage, 594*4882a593Smuzhiyun }; 595*4882a593Smuzhiyun})(); 596*4882a593Smuzhiyun 597*4882a593Smuzhiyun/* keep this in the global scope for compatability */ 598*4882a593Smuzhiyunfunction reload_params(params) { 599*4882a593Smuzhiyun var uri = window.location.href; 600*4882a593Smuzhiyun var splitlist = uri.split("?"); 601*4882a593Smuzhiyun var url = splitlist[0]; 602*4882a593Smuzhiyun var parameters = splitlist[1]; 603*4882a593Smuzhiyun // deserialize the call parameters 604*4882a593Smuzhiyun var cparams = []; 605*4882a593Smuzhiyun if(parameters) 606*4882a593Smuzhiyun cparams = parameters.split("&"); 607*4882a593Smuzhiyun 608*4882a593Smuzhiyun var nparams = {}; 609*4882a593Smuzhiyun for (var i = 0; i < cparams.length; i++) { 610*4882a593Smuzhiyun var temp = cparams[i].split("="); 611*4882a593Smuzhiyun nparams[temp[0]] = temp[1]; 612*4882a593Smuzhiyun } 613*4882a593Smuzhiyun // update parameter values 614*4882a593Smuzhiyun for (i in params) { 615*4882a593Smuzhiyun nparams[encodeURIComponent(i)] = encodeURIComponent(params[i]); 616*4882a593Smuzhiyun } 617*4882a593Smuzhiyun // serialize the structure 618*4882a593Smuzhiyun var callparams = []; 619*4882a593Smuzhiyun for (i in nparams) { 620*4882a593Smuzhiyun callparams.push(i+"="+nparams[i]); 621*4882a593Smuzhiyun } 622*4882a593Smuzhiyun window.location.href = url+"?"+callparams.join('&'); 623*4882a593Smuzhiyun} 624*4882a593Smuzhiyun 625*4882a593Smuzhiyun/* Things that happen for all pages */ 626*4882a593Smuzhiyun$(document).ready(function() { 627*4882a593Smuzhiyun 628*4882a593Smuzhiyun (function showNotificationRequest(){ 629*4882a593Smuzhiyun var cookie = $.cookie('toaster-notification'); 630*4882a593Smuzhiyun 631*4882a593Smuzhiyun if (!cookie) 632*4882a593Smuzhiyun return; 633*4882a593Smuzhiyun 634*4882a593Smuzhiyun var notificationData = JSON.parse(cookie); 635*4882a593Smuzhiyun 636*4882a593Smuzhiyun libtoaster.showChangeNotification(notificationData.message); 637*4882a593Smuzhiyun 638*4882a593Smuzhiyun $.removeCookie('toaster-notification', { path: "/"}); 639*4882a593Smuzhiyun })(); 640*4882a593Smuzhiyun 641*4882a593Smuzhiyun 642*4882a593Smuzhiyun 643*4882a593Smuzhiyun var ajaxLoadingTimer; 644*4882a593Smuzhiyun 645*4882a593Smuzhiyun /* If we don't have a console object which might be the case in some 646*4882a593Smuzhiyun * browsers, no-op it to avoid undefined errors. 647*4882a593Smuzhiyun */ 648*4882a593Smuzhiyun if (!window.console) { 649*4882a593Smuzhiyun window.console = {}; 650*4882a593Smuzhiyun window.console.warn = function() {}; 651*4882a593Smuzhiyun window.console.error = function() {}; 652*4882a593Smuzhiyun } 653*4882a593Smuzhiyun 654*4882a593Smuzhiyun /* 655*4882a593Smuzhiyun * highlight plugin. 656*4882a593Smuzhiyun */ 657*4882a593Smuzhiyun hljs.initHighlightingOnLoad(); 658*4882a593Smuzhiyun 659*4882a593Smuzhiyun // Prevent invalid links from jumping page scroll 660*4882a593Smuzhiyun $('a[href=#]').click(function() { 661*4882a593Smuzhiyun return false; 662*4882a593Smuzhiyun }); 663*4882a593Smuzhiyun 664*4882a593Smuzhiyun 665*4882a593Smuzhiyun /* START TODO Delete this section now redundant */ 666*4882a593Smuzhiyun /* Belen's additions */ 667*4882a593Smuzhiyun 668*4882a593Smuzhiyun // turn Edit columns dropdown into a multiselect menu 669*4882a593Smuzhiyun $('.dropdown-menu input, .dropdown-menu label').click(function(e) { 670*4882a593Smuzhiyun e.stopPropagation(); 671*4882a593Smuzhiyun }); 672*4882a593Smuzhiyun 673*4882a593Smuzhiyun // enable popovers in any table cells that contain an anchor with the 674*4882a593Smuzhiyun // .btn class applied, and make sure popovers work on click, are mutually 675*4882a593Smuzhiyun // exclusive and they close when your click outside their area 676*4882a593Smuzhiyun 677*4882a593Smuzhiyun $('html').click(function(){ 678*4882a593Smuzhiyun $('td > a.btn').popover('hide'); 679*4882a593Smuzhiyun }); 680*4882a593Smuzhiyun 681*4882a593Smuzhiyun $('td > a.btn').popover({ 682*4882a593Smuzhiyun html:true, 683*4882a593Smuzhiyun placement:'left', 684*4882a593Smuzhiyun container:'body', 685*4882a593Smuzhiyun trigger:'manual' 686*4882a593Smuzhiyun }).click(function(e){ 687*4882a593Smuzhiyun $('td > a.btn').not(this).popover('hide'); 688*4882a593Smuzhiyun // ideally we would use 'toggle' here 689*4882a593Smuzhiyun // but it seems buggy in our Bootstrap version 690*4882a593Smuzhiyun $(this).popover('show'); 691*4882a593Smuzhiyun e.stopPropagation(); 692*4882a593Smuzhiyun }); 693*4882a593Smuzhiyun 694*4882a593Smuzhiyun // enable tooltips for applied filters 695*4882a593Smuzhiyun $('th a.btn-primary').tooltip({container:'body', html:true, placement:'bottom', delay:{hide:1500}}); 696*4882a593Smuzhiyun 697*4882a593Smuzhiyun // hide applied filter tooltip when you click on the filter button 698*4882a593Smuzhiyun $('th a.btn-primary').click(function () { 699*4882a593Smuzhiyun $('.tooltip').hide(); 700*4882a593Smuzhiyun }); 701*4882a593Smuzhiyun 702*4882a593Smuzhiyun /* Initialise bootstrap tooltips */ 703*4882a593Smuzhiyun $(".get-help, [data-toggle=tooltip]").tooltip({ 704*4882a593Smuzhiyun container : 'body', 705*4882a593Smuzhiyun html : true, 706*4882a593Smuzhiyun delay: { show : 300 } 707*4882a593Smuzhiyun }); 708*4882a593Smuzhiyun 709*4882a593Smuzhiyun // show help bubble on hover inside tables 710*4882a593Smuzhiyun $("table").on("mouseover", "th, td", function () { 711*4882a593Smuzhiyun $(this).find(".hover-help").css("visibility","visible"); 712*4882a593Smuzhiyun }); 713*4882a593Smuzhiyun 714*4882a593Smuzhiyun $("table").on("mouseleave", "th, td", function () { 715*4882a593Smuzhiyun $(this).find(".hover-help").css("visibility","hidden"); 716*4882a593Smuzhiyun }); 717*4882a593Smuzhiyun 718*4882a593Smuzhiyun /* END TODO Delete this section now redundant */ 719*4882a593Smuzhiyun 720*4882a593Smuzhiyun // show task type and outcome in task details pages 721*4882a593Smuzhiyun $(".task-info").tooltip({ container: 'body', html: true, delay: {show: 200}, placement: 'right' }); 722*4882a593Smuzhiyun 723*4882a593Smuzhiyun // initialise the tooltips for the edit icons 724*4882a593Smuzhiyun $(".glyphicon-edit").tooltip({ container: 'body', html: true, delay: {show: 400}, title: "Change" }); 725*4882a593Smuzhiyun 726*4882a593Smuzhiyun // initialise the tooltips for the download icons 727*4882a593Smuzhiyun $(".icon-download-alt").tooltip({ container: 'body', html: true, delay: { show: 200 } }); 728*4882a593Smuzhiyun 729*4882a593Smuzhiyun // initialise popover for debug information 730*4882a593Smuzhiyun $(".glyphicon-info-sign").popover( { placement: 'bottom', html: true, container: 'body' }); 731*4882a593Smuzhiyun 732*4882a593Smuzhiyun // linking directly to tabs 733*4882a593Smuzhiyun $(function(){ 734*4882a593Smuzhiyun var hash = window.location.hash; 735*4882a593Smuzhiyun $('ul.nav a[href="' + hash + '"]').tab('show'); 736*4882a593Smuzhiyun 737*4882a593Smuzhiyun $('.nav-tabs a').click(function () { 738*4882a593Smuzhiyun $(this).tab('show'); 739*4882a593Smuzhiyun $('body').scrollTop(); 740*4882a593Smuzhiyun }); 741*4882a593Smuzhiyun }); 742*4882a593Smuzhiyun 743*4882a593Smuzhiyun // toggle for long content (variables, python stack trace, etc) 744*4882a593Smuzhiyun $('.full, .full-hide').hide(); 745*4882a593Smuzhiyun $('.full-show').click(function(){ 746*4882a593Smuzhiyun $('.full').slideDown(function(){ 747*4882a593Smuzhiyun $('.full-hide').show(); 748*4882a593Smuzhiyun }); 749*4882a593Smuzhiyun $(this).hide(); 750*4882a593Smuzhiyun }); 751*4882a593Smuzhiyun $('.full-hide').click(function(){ 752*4882a593Smuzhiyun $(this).hide(); 753*4882a593Smuzhiyun $('.full').slideUp(function(){ 754*4882a593Smuzhiyun $('.full-show').show(); 755*4882a593Smuzhiyun }); 756*4882a593Smuzhiyun }); 757*4882a593Smuzhiyun 758*4882a593Smuzhiyun //toggle the errors and warnings sections 759*4882a593Smuzhiyun $('.show-errors').click(function() { 760*4882a593Smuzhiyun $('#collapse-errors').addClass('in'); 761*4882a593Smuzhiyun }); 762*4882a593Smuzhiyun $('.toggle-errors').click(function() { 763*4882a593Smuzhiyun $('#collapse-errors').toggleClass('in'); 764*4882a593Smuzhiyun }); 765*4882a593Smuzhiyun $('.show-warnings').click(function() { 766*4882a593Smuzhiyun $('#collapse-warnings').addClass('in'); 767*4882a593Smuzhiyun }); 768*4882a593Smuzhiyun $('.toggle-warnings').click(function() { 769*4882a593Smuzhiyun $('#collapse-warnings').toggleClass('in'); 770*4882a593Smuzhiyun }); 771*4882a593Smuzhiyun $('.show-exceptions').click(function() { 772*4882a593Smuzhiyun $('#collapse-exceptions').addClass('in'); 773*4882a593Smuzhiyun }); 774*4882a593Smuzhiyun $('.toggle-exceptions').click(function() { 775*4882a593Smuzhiyun $('#collapse-exceptions').toggleClass('in'); 776*4882a593Smuzhiyun }); 777*4882a593Smuzhiyun 778*4882a593Smuzhiyun 779*4882a593Smuzhiyun $("#hide-alert").click(function(){ 780*4882a593Smuzhiyun $(this).parent().fadeOut(); 781*4882a593Smuzhiyun }); 782*4882a593Smuzhiyun 783*4882a593Smuzhiyun //show warnings section when requested from the previous page 784*4882a593Smuzhiyun if (location.href.search('#warnings') > -1) { 785*4882a593Smuzhiyun $('#collapse-warnings').addClass('in'); 786*4882a593Smuzhiyun } 787*4882a593Smuzhiyun 788*4882a593Smuzhiyun /* Show the loading notification if nothing has happend after 1.5 789*4882a593Smuzhiyun * seconds 790*4882a593Smuzhiyun */ 791*4882a593Smuzhiyun $(document).bind("ajaxStart", function(){ 792*4882a593Smuzhiyun if (ajaxLoadingTimer) 793*4882a593Smuzhiyun window.clearTimeout(ajaxLoadingTimer); 794*4882a593Smuzhiyun 795*4882a593Smuzhiyun ajaxLoadingTimer = window.setTimeout(function() { 796*4882a593Smuzhiyun if (libtoaster.ajaxLoadingTimerEnabled) { 797*4882a593Smuzhiyun $("#loading-notification").fadeIn(); 798*4882a593Smuzhiyun } 799*4882a593Smuzhiyun }, 1200); 800*4882a593Smuzhiyun }); 801*4882a593Smuzhiyun 802*4882a593Smuzhiyun $(document).bind("ajaxStop", function(){ 803*4882a593Smuzhiyun if (ajaxLoadingTimer) 804*4882a593Smuzhiyun window.clearTimeout(ajaxLoadingTimer); 805*4882a593Smuzhiyun 806*4882a593Smuzhiyun $("#loading-notification").fadeOut(); 807*4882a593Smuzhiyun }); 808*4882a593Smuzhiyun 809*4882a593Smuzhiyun $(document).ajaxError(function(event, jqxhr, settings, errMsg){ 810*4882a593Smuzhiyun if (errMsg === 'abort') 811*4882a593Smuzhiyun return; 812*4882a593Smuzhiyun 813*4882a593Smuzhiyun console.warn("Problem with xhr call"); 814*4882a593Smuzhiyun console.warn(errMsg); 815*4882a593Smuzhiyun console.warn(jqxhr.responseText); 816*4882a593Smuzhiyun }); 817*4882a593Smuzhiyun 818*4882a593Smuzhiyun function check_for_duplicate_ids () { 819*4882a593Smuzhiyun /* warn about duplicate element ids */ 820*4882a593Smuzhiyun var ids = {}; 821*4882a593Smuzhiyun $("[id]").each(function() { 822*4882a593Smuzhiyun if (this.id && ids[this.id]) { 823*4882a593Smuzhiyun console.warn('Duplicate element id #'+this.id); 824*4882a593Smuzhiyun } 825*4882a593Smuzhiyun ids[this.id] = true; 826*4882a593Smuzhiyun }); 827*4882a593Smuzhiyun } 828*4882a593Smuzhiyun 829*4882a593Smuzhiyun /* Make sure we don't have a notification overlay a modal */ 830*4882a593Smuzhiyun $(".modal").on('show.bs.modal', function(){ 831*4882a593Smuzhiyun $(".alert-dismissible").fadeOut(); 832*4882a593Smuzhiyun }); 833*4882a593Smuzhiyun 834*4882a593Smuzhiyun if (libtoaster.debug) { 835*4882a593Smuzhiyun check_for_duplicate_ids(); 836*4882a593Smuzhiyun } else { 837*4882a593Smuzhiyun /* Debug is false so supress warnings by overriding the functions */ 838*4882a593Smuzhiyun window.console.warn = function () {}; 839*4882a593Smuzhiyun window.console.error = function () {}; 840*4882a593Smuzhiyun } 841*4882a593Smuzhiyun}); 842