xref: /OK3568_Linux_fs/yocto/bitbake/lib/toaster/toastergui/static/js/libtoaster.js (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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