123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685 |
- "use strict";
- /* All shared functionality to go in libtoaster object.
- * This object really just helps readability since we can then have
- * a traceable namespace.
- */
- var libtoaster = (function () {
- // prevent conflicts with Bootstrap 2's typeahead (required during
- // transition from v2 to v3)
- var typeahead = jQuery.fn.typeahead.noConflict();
- jQuery.fn._typeahead = typeahead;
- /* Make a typeahead from an input element
- *
- * _makeTypeahead parameters
- * jQElement: input element as selected by $('selector')
- * xhrUrl: the url to get the JSON from; this URL should return JSON in the
- * format:
- * { "results": [ { "name": "test", "detail" : "a test thing" }, ... ] }
- * xhrParams: the data/parameters to pass to the getJSON url e.g.
- * { 'type' : 'projects' }; the text typed will be passed as 'search'.
- * selectedCB: function to call once an item has been selected; has
- * signature selectedCB(item), where item is an item in the format shown
- * in the JSON list above, i.e.
- * { "name": "name", "detail": "detail" }.
- */
- function _makeTypeahead(jQElement, xhrUrl, xhrParams, selectedCB) {
- if (!xhrUrl || xhrUrl.length === 0) {
- throw("No url supplied for typeahead");
- }
- var xhrReq;
- jQElement._typeahead(
- {
- highlight: true,
- classNames: {
- open: "dropdown-menu",
- cursor: "active"
- }
- },
- {
- source: function (query, syncResults, asyncResults) {
- xhrParams.search = query;
- // if we have a request in progress, cancel it and start another
- if (xhrReq) {
- xhrReq.abort();
- }
- xhrReq = $.getJSON(xhrUrl, xhrParams, function (data) {
- if (data.error !== "ok") {
- console.error("Error getting data from server: " + data.error);
- return;
- }
- xhrReq = null;
- asyncResults(data.results);
- });
- },
- // how the selected item is shown in the input
- display: function (item) {
- return item.name;
- },
- templates: {
- // how the item is displayed in the dropdown
- suggestion: function (item) {
- var elt = document.createElement("div");
- elt.innerHTML = item.name + " " + item.detail;
- return elt;
- }
- }
- }
- );
- // when an item is selected using the typeahead, invoke the callback
- jQElement.on("typeahead:select", function (event, item) {
- selectedCB(item);
- });
- }
- /* startABuild:
- * url: xhr_buildrequest or null for current project
- * targets: an array or space separated list of targets to build
- * onsuccess: callback for successful execution
- * onfail: callback for failed execution
- */
- function _startABuild (url, targets, onsuccess, onfail) {
- if (!url)
- url = libtoaster.ctx.xhrBuildRequestUrl;
- /* Flatten the array of targets into a space spearated list */
- if (targets instanceof Array){
- targets = targets.reduce(function(prevV, nextV){
- return prev + ' ' + next;
- });
- }
- $.ajax( {
- type: "POST",
- url: url,
- data: { 'targets' : targets },
- headers: { 'X-CSRFToken' : $.cookie('csrftoken')},
- success: function (_data) {
- if (_data.error !== "ok") {
- console.warn(_data.error);
- } else {
- if (onsuccess !== undefined) onsuccess(_data);
- }
- },
- error: function (_data) {
- console.warn("Call failed");
- console.warn(_data);
- if (onfail) onfail(data);
- } });
- }
- /* cancelABuild:
- * url: xhr_buildrequest url or null for current project
- * buildRequestIds: space separated list of build request ids
- * onsuccess: callback for successful execution
- * onfail: callback for failed execution
- */
- function _cancelABuild(url, buildRequestIds, onsuccess, onfail){
- if (!url)
- url = libtoaster.ctx.xhrBuildRequestUrl;
- $.ajax( {
- type: "POST",
- url: url,
- data: { 'buildCancel': buildRequestIds },
- headers: { 'X-CSRFToken' : $.cookie('csrftoken')},
- success: function (_data) {
- if (_data.error !== "ok") {
- console.warn(_data.error);
- } else {
- if (onsuccess) onsuccess(_data);
- }
- },
- error: function (_data) {
- console.warn("Call failed");
- console.warn(_data);
- if (onfail) onfail(_data);
- }
- });
- }
- function _getMostRecentBuilds(url, onsuccess, onfail) {
- $.ajax({
- url: url,
- type: 'GET',
- data : {format: 'json'},
- headers: {'X-CSRFToken': $.cookie('csrftoken')},
- success: function (data) {
- onsuccess ? onsuccess(data) : console.log(data);
- },
- error: function (data) {
- onfail ? onfail(data) : console.error(data);
- }
- });
- }
- /* Get a project's configuration info */
- function _getProjectInfo(url, onsuccess, onfail){
- $.ajax({
- type: "GET",
- data : { format: "json" },
- url: url,
- headers: { 'X-CSRFToken' : $.cookie('csrftoken')},
- success: function (_data) {
- if (_data.error !== "ok") {
- console.warn(_data.error);
- } else {
- if (onsuccess !== undefined) onsuccess(_data);
- }
- },
- error: function (_data) {
- console.warn(_data);
- if (onfail) onfail(_data);
- }
- });
- }
- /* Properties for data can be:
- * layerDel (csv)
- * layerAdd (csv)
- * projectName
- * projectVersion
- * machineName
- */
- function _editCurrentProject(data, onSuccess, onFail){
- $.ajax({
- type: "POST",
- url: libtoaster.ctx.projectPageUrl + "?format=json",
- data: data,
- headers: { 'X-CSRFToken' : $.cookie('csrftoken')},
- success: function (data) {
- if (data.error != "ok") {
- console.log(data.error);
- if (onFail !== undefined)
- onFail(data);
- } else {
- if (onSuccess !== undefined)
- onSuccess(data);
- }
- },
- error: function (data) {
- console.log("Call failed");
- console.log(data);
- }
- });
- }
- function _getLayerDepsForProject(url, onSuccess, onFail){
- /* Check for dependencies not in the current project */
- $.getJSON(url,
- { format: 'json' },
- function(data) {
- if (data.error != "ok") {
- console.log(data.error);
- if (onFail !== undefined)
- onFail(data);
- } else {
- var deps = {};
- /* Filter out layer dep ids which are in the
- * project already.
- */
- deps.list = data.layerdeps.list.filter(function(layerObj){
- return (data.projectlayers.lastIndexOf(layerObj.id) < 0);
- });
- onSuccess(deps);
- }
- }, function() {
- console.log("E: Failed to make request");
- });
- }
- /* parses the query string of the current window.location to an object */
- function _parseUrlParams() {
- var string = window.location.search;
- string = string.substr(1);
- var stringArray = string.split ("&");
- var obj = {};
- for (var i in stringArray) {
- var keyVal = stringArray[i].split ("=");
- obj[keyVal[0]] = keyVal[1];
- }
- return obj;
- }
- /* takes a flat object and outputs it as a query string
- * e.g. the output of dumpsUrlParams
- */
- function _dumpsUrlParams(obj) {
- var str = "?";
- for (var key in obj){
- if (!obj[key])
- continue;
- str += key+ "="+obj[key].toString();
- str += "&";
- }
- /* Maintain the current hash */
- str += window.location.hash;
- return str;
- }
- function _addRmLayer(layerObj, add, doneCb){
- if (add === true) {
- /* If adding get the deps for this layer */
- libtoaster.getLayerDepsForProject(layerObj.layerdetailurl,
- function (layers) {
- /* got result for dependencies */
- if (layers.list.length === 0){
- var editData = { layerAdd : layerObj.id };
- libtoaster.editCurrentProject(editData, function() {
- doneCb([]);
- });
- return;
- } else {
- try {
- showLayerDepsModal(layerObj, layers.list, null, null, true, doneCb);
- } catch (e) {
- $.getScript(libtoaster.ctx.jsUrl + "layerDepsModal.js", function(){
- showLayerDepsModal(layerObj, layers.list, null, null, true, doneCb);
- }, function(){
- console.warn("Failed to load layerDepsModal");
- });
- }
- }
- }, null);
- } else if (add === false) {
- var editData = { layerDel : layerObj.id };
- libtoaster.editCurrentProject(editData, function () {
- doneCb([]);
- }, function () {
- console.warn ("Removing layer from project failed");
- doneCb(null);
- });
- }
- }
- function _makeLayerAddRmAlertMsg(layer, layerDepsList, add) {
- var alertMsg;
- if (layerDepsList.length > 0 && add === true) {
- 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>");
- /* Build the layer deps list */
- layerDepsList.map(function(layer, i){
- var link = $("<a class=\"alert-link\"></a>");
- link.attr("href", layer.layerdetailurl);
- link.text(layer.name);
- link.tooltip({title: layer.tooltip});
- if (i !== 0)
- alertMsg.append(", ");
- alertMsg.append(link);
- });
- } else if (layerDepsList.length === 0 && add === true) {
- alertMsg = $("<span>You have added <strong>1</strong> layer to your project: <a class=\"alert-link\" id=\"layer-affected-name\"></a></span></span>");
- } else if (add === false) {
- alertMsg = $("<span>You have removed <strong>1</strong> layer from your project: <a class=\"alert-link\" id=\"layer-affected-name\"></a></span>");
- }
- alertMsg.children("#layer-affected-name").text(layer.name);
- alertMsg.children("#layer-affected-name").attr("href", layer.layerdetailurl);
- return alertMsg.html();
- }
- function _showChangeNotification(message){
- var alertMsg = $("#change-notification-msg");
- alertMsg.html(message);
- $("#change-notification, #change-notification *").fadeIn();
- }
- function _createCustomRecipe(name, baseRecipeId, doneCb){
- var data = {
- 'name' : name,
- 'project' : libtoaster.ctx.projectId,
- 'base' : baseRecipeId,
- };
- $.ajax({
- type: "POST",
- url: libtoaster.ctx.xhrCustomRecipeUrl,
- data: data,
- headers: { 'X-CSRFToken' : $.cookie('csrftoken')},
- success: function (ret) {
- if (doneCb){
- doneCb(ret);
- } else if (ret.error !== "ok") {
- console.warn(ret.error);
- }
- },
- error: function (ret) {
- console.warn("Call failed");
- console.warn(ret);
- }
- });
- }
- /* Validate project names. Use unique project names
- All arguments accepted by this function are JQeury objects.
- For example if the HTML element has "hint-error-project-name", then
- it is passed to this function as $("#hint-error-project-name").
- Arg1 - projectName : This is a string object. In the HTML, project name will be entered here.
- Arg2 - hintEerror : This is a jquery object which will accept span which throws error for
- duplicate project
- Arg3 - ctrlGrpValidateProjectName : This object holds the div with class "control-group"
- Arg4 - enableOrDisableBtn : This object will help the API to enable or disable the form.
- For example in the new project the create project button will be hidden if the
- duplicate project exist. Similarly in the projecttopbar the save button will be
- disabled if the project name already exist.
- Return - This function doesn't return anything. It sets/unsets the behavior of the elements.
- */
- function _makeProjectNameValidation(projectName, hintError,
- ctrlGrpValidateProjectName, enableOrDisableBtn ) {
- function checkProjectName(projectName){
- $.ajax({
- type: "GET",
- url: libtoaster.ctx.projectsTypeAheadUrl,
- data: { 'search' : projectName },
- headers: { 'X-CSRFToken' : $.cookie('csrftoken')},
- success: function(data){
- if (data.results.length > 0 &&
- data.results[0].name === projectName) {
- // This project name exists hence show the error and disable
- // the save button
- ctrlGrpValidateProjectName.addClass('has-error');
- hintError.show();
- enableOrDisableBtn.attr('disabled', 'disabled');
- } else {
- ctrlGrpValidateProjectName.removeClass('has-error');
- hintError.hide();
- enableOrDisableBtn.removeAttr('disabled');
- }
- },
- error: function (data) {
- console.log(data);
- },
- });
- }
- /* The moment user types project name remove the error */
- projectName.on("input", function() {
- var projectName = $(this).val();
- checkProjectName(projectName)
- });
- /* Validate new project name */
- projectName.on("blur", function(){
- var projectName = $(this).val();
- checkProjectName(projectName)
- });
- }
- return {
- reload_params : reload_params,
- startABuild : _startABuild,
- cancelABuild : _cancelABuild,
- getMostRecentBuilds: _getMostRecentBuilds,
- makeTypeahead : _makeTypeahead,
- getProjectInfo: _getProjectInfo,
- getLayerDepsForProject : _getLayerDepsForProject,
- editCurrentProject : _editCurrentProject,
- debug: false,
- parseUrlParams : _parseUrlParams,
- dumpsUrlParams : _dumpsUrlParams,
- addRmLayer : _addRmLayer,
- makeLayerAddRmAlertMsg : _makeLayerAddRmAlertMsg,
- showChangeNotification : _showChangeNotification,
- createCustomRecipe: _createCustomRecipe,
- makeProjectNameValidation: _makeProjectNameValidation,
- };
- })();
- /* keep this in the global scope for compatability */
- function reload_params(params) {
- var uri = window.location.href;
- var splitlist = uri.split("?");
- var url = splitlist[0];
- var parameters = splitlist[1];
- // deserialize the call parameters
- var cparams = [];
- if(parameters)
- cparams = parameters.split("&");
- var nparams = {};
- for (var i = 0; i < cparams.length; i++) {
- var temp = cparams[i].split("=");
- nparams[temp[0]] = temp[1];
- }
- // update parameter values
- for (i in params) {
- nparams[encodeURIComponent(i)] = encodeURIComponent(params[i]);
- }
- // serialize the structure
- var callparams = [];
- for (i in nparams) {
- callparams.push(i+"="+nparams[i]);
- }
- window.location.href = url+"?"+callparams.join('&');
- }
- /* Things that happen for all pages */
- $(document).ready(function() {
- var ajaxLoadingTimer;
- /* If we don't have a console object which might be the case in some
- * browsers, no-op it to avoid undefined errors.
- */
- if (!window.console) {
- window.console = {};
- window.console.warn = function() {};
- window.console.error = function() {};
- }
- /*
- * PrettyPrint plugin.
- *
- */
- // Init
- prettyPrint();
- // Prevent invalid links from jumping page scroll
- $('a[href=#]').click(function() {
- return false;
- });
- /* START TODO Delete this section now redundant */
- /* Belen's additions */
- // turn Edit columns dropdown into a multiselect menu
- $('.dropdown-menu input, .dropdown-menu label').click(function(e) {
- e.stopPropagation();
- });
- // enable popovers in any table cells that contain an anchor with the
- // .btn class applied, and make sure popovers work on click, are mutually
- // exclusive and they close when your click outside their area
- $('html').click(function(){
- $('td > a.btn').popover('hide');
- });
- $('td > a.btn').popover({
- html:true,
- placement:'left',
- container:'body',
- trigger:'manual'
- }).click(function(e){
- $('td > a.btn').not(this).popover('hide');
- // ideally we would use 'toggle' here
- // but it seems buggy in our Bootstrap version
- $(this).popover('show');
- e.stopPropagation();
- });
- // enable tooltips for applied filters
- $('th a.btn-primary').tooltip({container:'body', html:true, placement:'bottom', delay:{hide:1500}});
- // hide applied filter tooltip when you click on the filter button
- $('th a.btn-primary').click(function () {
- $('.tooltip').hide();
- });
- /* Initialise bootstrap tooltips */
- $(".get-help, [data-toggle=tooltip]").tooltip({
- container : 'body',
- html : true,
- delay: { show : 300 }
- });
- // show help bubble on hover inside tables
- $("table").on("mouseover", "th, td", function () {
- $(this).find(".hover-help").css("visibility","visible");
- });
- $("table").on("mouseleave", "th, td", function () {
- $(this).find(".hover-help").css("visibility","hidden");
- });
- /* END TODO Delete this section now redundant */
- // show task type and outcome in task details pages
- $(".task-info").tooltip({ container: 'body', html: true, delay: {show: 200}, placement: 'right' });
- // initialise the tooltips for the edit icons
- $(".glyphicon-edit").tooltip({ container: 'body', html: true, delay: {show: 400}, title: "Change" });
- // initialise the tooltips for the download icons
- $(".icon-download-alt").tooltip({ container: 'body', html: true, delay: { show: 200 } });
- // initialise popover for debug information
- $(".glyphicon-info-sign").popover( { placement: 'bottom', html: true, container: 'body' });
- // linking directly to tabs
- $(function(){
- var hash = window.location.hash;
- $('ul.nav a[href="' + hash + '"]').tab('show');
- $('.nav-tabs a').click(function () {
- $(this).tab('show');
- $('body').scrollTop();
- });
- });
- // toggle for long content (variables, python stack trace, etc)
- $('.full, .full-hide').hide();
- $('.full-show').click(function(){
- $('.full').slideDown(function(){
- $('.full-hide').show();
- });
- $(this).hide();
- });
- $('.full-hide').click(function(){
- $(this).hide();
- $('.full').slideUp(function(){
- $('.full-show').show();
- });
- });
- //toggle the errors and warnings sections
- $('.show-errors').click(function() {
- $('#collapse-errors').addClass('in');
- });
- $('.toggle-errors').click(function() {
- $('#collapse-errors').toggleClass('in');
- });
- $('.show-warnings').click(function() {
- $('#collapse-warnings').addClass('in');
- });
- $('.toggle-warnings').click(function() {
- $('#collapse-warnings').toggleClass('in');
- });
- $('.show-exceptions').click(function() {
- $('#collapse-exceptions').addClass('in');
- });
- $('.toggle-exceptions').click(function() {
- $('#collapse-exceptions').toggleClass('in');
- });
- $("#hide-alert").click(function(){
- $(this).parent().fadeOut();
- });
- //show warnings section when requested from the previous page
- if (location.href.search('#warnings') > -1) {
- $('#collapse-warnings').addClass('in');
- }
- /* Show the loading notification if nothing has happend after 1.5
- * seconds
- */
- $(document).bind("ajaxStart", function(){
- if (ajaxLoadingTimer)
- window.clearTimeout(ajaxLoadingTimer);
- ajaxLoadingTimer = window.setTimeout(function() {
- $("#loading-notification").fadeIn();
- }, 1200);
- });
- $(document).bind("ajaxStop", function(){
- if (ajaxLoadingTimer)
- window.clearTimeout(ajaxLoadingTimer);
- $("#loading-notification").fadeOut();
- });
- $(document).ajaxError(function(event, jqxhr, settings, errMsg){
- if (errMsg === 'abort')
- return;
- console.warn("Problem with xhr call");
- console.warn(errMsg);
- console.warn(jqxhr.responseText);
- });
- function check_for_duplicate_ids () {
- /* warn about duplicate element ids */
- var ids = {};
- $("[id]").each(function() {
- if (this.id && ids[this.id]) {
- console.warn('Duplicate element id #'+this.id);
- }
- ids[this.id] = true;
- });
- }
- if (libtoaster.debug) {
- check_for_duplicate_ids();
- } else {
- /* Debug is false so supress warnings by overriding the functions */
- window.console.warn = function () {};
- window.console.error = function () {};
- }
- });
|