aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMilo Casagrande <milo.casagrande@linaro.org>2014-12-04 13:47:29 +0100
committerMilo Casagrande <milo.casagrande@linaro.org>2014-12-04 13:47:29 +0100
commit6dce991c6dd749d270fff04b373df99f20001c31 (patch)
treecc3efd369a6b5d2b7841572bb37220005b986ced
parent3971650c9fb3f65ec56bc8a7fe83a4db858e29ee (diff)
Merge libraries into single one.
* Merge removed libraries into the base one. * Use a revealing module pattern. Change-Id: I221d1be6eebc1db9a9eca57dcdc67c40c1d15da6
-rw-r--r--app/dashboard/static/js/linaro-base-1.0.2.js501
1 files changed, 404 insertions, 97 deletions
diff --git a/app/dashboard/static/js/linaro-base-1.0.2.js b/app/dashboard/static/js/linaro-base-1.0.2.js
index e99d4f8..9b470e8 100644
--- a/app/dashboard/static/js/linaro-base-1.0.2.js
+++ b/app/dashboard/static/js/linaro-base-1.0.2.js
@@ -1,64 +1,181 @@
-var csrftoken = $('meta[name=csrf-token]').attr('content');
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
-function setErrorAlert(id, code, reason) {
- /*
- * Pass code (int) and id (string) to alert an error on the page.
- * Optionally pass a reason (string) for the error.
- */
+var JSBase = (function() {
'use strict';
- var localId = id,
- text = '';
+ var csrftoken = $('meta[name=csrf-token]').attr('content'),
+ errorsContainer = $('#errors-container'),
+ defaultErrorReason = 'Data call failed',
+ defaultTimeout = 10000;
+
+ // Make sure the element ID starts with #.
+ // `elementID`: The element ID to check.
+ function checkIfID(elementID) {
+ var localElement = elementID;
- if (id[0] !== '#') {
- localId = '#' + id;
+ if (localElement[0] !== '#') {
+ localElement = '#' + localElement;
+ }
+ return localElement;
}
- text = '<div id="' + localId + '" ' +
- 'class="alert alert-danger alert-dismissable">' +
- '<button type="button" class="close" ' +
- 'data-dismiss="alert" aria-hidden="true">&times;</button>';
+ // Make sure the class name starts with a dot.
+ // `className`: The name of the class to check.
+ function checkIfClass(className) {
+ var localName = className;
- if (reason !== undefined) {
- text += reason + '<br/>';
+ if (localName[0] !== '.') {
+ localName = '.' + localName;
+ }
+ return localName;
}
- text += 'Error while loading data from the server (error code:&nbsp;' +
- code + ').&nbsp;' +
- 'Please contact the website administrators.';
+ // Add error alerts at the top of the page in the default container.
+ // `id`: The id of the element to add.
+ // `code`: The error code (int).
+ // `reason`: Option reason that will be added to the error message.
+ function setErrorAlert(id, code, reason) {
+ var localId = checkIfID(id),
+ text = '';
- text += '</div>';
+ text = '<div id="' + localId + '" ' +
+ 'class="alert alert-danger alert-dismissable">' +
+ '<button type="button" class="close" ' +
+ 'data-dismiss="alert" aria-hidden="true">&times;</button>';
- $('#errors-container').append(text);
- $(localId).alert();
-}
+ if (reason !== null || reason !== undefined) {
+ text = text + reason + '<br/>';
+ }
-function setXhrHeader(xhr) {
- /*
- Set the CSRF token header for ajax request.
- xhr: The xhr object to add the header to.
- */
- 'use strict';
- xhr.setRequestHeader('X-CSRFToken', csrftoken);
-}
+ text = text +
+ 'Error while loading data from the server (error code:&nbsp;' +
+ code + ').&nbsp;' +
+ 'Please contact the website administrators.';
-function loadContent(elementId, staticContent) {
- /*
- Load some static content replacing what is inside the provided element.
- elementId: The ID of the element to empty and re-populate.
- staticContent: URI of the static content HTML to load.
- */
- 'use strict';
- var localId = elementId;
+ text = text + '</div>';
- if (elementId[0] !== '#') {
- localId = '#' + elementId;
+ errorsContainer.append(text);
+ $(localId).alert();
}
- $(localId).empty().load(staticContent);
-}
+ // Load static HTML content from an URL.
+ // `elementID`: The ID of the element.
+ // `contentURL`: The URL where the static content will be taken.
+ function loadHTMLContent(elementID, contentURL) {
+ var realID = checkIfID(elementID);
+ $(realID).empty().load(contentURL);
+ }
+
+ // Create a simple bash script for git bisection.
+ // `badCommit`: The starting point for the bisect script.
+ // `goodCommit`: The end point.
+ function createBisectShellScript(badCommit, goodCommit) {
+ var bisectScript = '';
+
+ if (badCommit !== null && goodCommit !== null) {
+ bisectScript = '#!/bin/bash\ngit bisect start ' +
+ badCommit + ' ' + goodCommit + '\n';
+ }
+ return 'data:text/plain;charset=UTF-8,' +
+ encodeURIComponent(bisectScript);
+ }
+
+ // Replace content of an element based on its id.
+ // `elementID`: The ID of the element to search.
+ // `staticContent`: The content that the element will be replaced with.
+ function replaceContentByID(elementID, staticContent) {
+ var realID = checkIfID(elementID);
+ $(realID).empty().append(staticContent);
+ }
+
+ // Replace content of elements based on their class name.
+ // It loops through all the elements removing their content and appending
+ // the provided one.
+ // `className`: The name of the class to search.
+ // `staticContent`: The content that the elements will be replaced with.
+ function replaceContentByClass(className, staticContent) {
+ var realClass = checkIfClass(className);
+ $(realClass).each(function() {
+ $(this).empty().append(staticContent);
+ });
+ }
+
+ // Return an ajax promise.
+ // `url`: The URL for the ajax call.
+ // `method`: The type of ajax call, default to 'GET'.
+ // `data`: The data to be passed to the ajax call.
+ // `successFunction`: Optional function, or array of functions,
+ // to be called on success.
+ // `errorFunction`: Optional function to be call on error.
+ // `errorReason`: Error message to be displayed.
+ // `headers`: Optional headers to set for the ajax call.
+ function createDeferredCall(url, method, data, successFunction,
+ errorFunction, errorReason, headers) {
+
+ var ajaxSettings, ajaxCall;
+
+ if (method === null || method === undefined) {
+ method = 'GET';
+ }
+
+ if (errorReason === null || errorReason === undefined) {
+ errorReason = defaultErrorReason;
+ }
+
+ ajaxSettings = {
+ 'type': method,
+ 'traditional': true,
+ 'cache': true,
+ 'dataType': 'json',
+ 'data': data,
+ 'beforeSend': function(jqXHR) {
+ jqXHR.setRequestHeader('X-CSRFToken', csrftoken);
+ },
+ 'timeout': defaultTimeout,
+ 'statusCode': {
+ 403: function() {
+ setErrorAlert('error-403', 403, errorReason);
+ },
+ 404: function() {
+ setErrorAlert('error-404', 404, errorReason);
+ },
+ 408: function() {
+ errorReason = errorReason + 'nbsp;(timeout)';
+ setErrorAlert('error-408', 408, errorReason);
+ },
+ 500: function() {
+ setErrorAlert('error-500', 500, errorReason);
+ }
+ }
+ };
+
+ if (successFunction !== null || successFunction !== undefined) {
+ ajaxSettings.success = successFunction;
+ }
+
+ if (errorFunction !== null || errorFunction !== undefined) {
+ ajaxSettings.error = errorFunction;
+ }
+
+ if (headers !== null || headers !== undefined) {
+ ajaxSettings.headers = headers;
+ }
+
+ ajaxCall = $.ajax(url, ajaxSettings);
+ return ajaxCall;
+ }
-function populateSideBarNav(elements) {
/*
Populate the sidebar navigation with the provided elements.
The "Top" link, is already populated since it's available in the base
@@ -68,71 +185,261 @@ function populateSideBarNav(elements) {
attributes set. An optional subnav attribute can be defined, and must
be another array of similar objects, to add a navigation sub-level.
*/
- 'use strict';
+ function populateSideBarNav(elements) {
+ if (elements === undefined || elements === null) {
+ return;
+ }
- if (elements === undefined || elements === null) {
- return;
- }
+ var sidebarNav = '',
+ arrayLen = elements.length,
+ element = null,
+ i = 0,
+ j = 0,
+ subNav = null,
+ subNavLen;
- function checkHref(href) {
- if (href[0] !== '#') {
- href = '#' + href;
- }
- return href;
- }
-
- var sidebarNav = '',
- arrayLen = elements.length,
- element = null,
- i = 0,
- j = 0,
- subNav = null,
- subNavLen;
-
- // Append the stuff only if we have the element.
- // On mobile platforms the element is not available.
- if ($('#sidebar-nav').length !== 0) {
- sidebarNav = '<ul class="nav sidenav">' +
- '<li class="active"><a href="#top">Top</a></li>';
-
- for (i; i < arrayLen; i = i + 1) {
- element = elements[i];
-
- sidebarNav += '<li><a href="' + checkHref(element.href) +
- '">' + element.name + '</a>';
-
- // Add subnav links (only if really available).
- if (element.hasOwnProperty('subnav') && element.subnav !== null) {
- subNav = element.subnav;
- subNavLen = subNav.length;
-
- sidebarNav += '<ul class="nav">';
- for (j; j < subNavLen; j = j + 1) {
- sidebarNav += '<li><a href="' +
- checkHref(subNav[j].href) +
- '">' + subNav[j].name +
- '</a></li>';
+ // Append the stuff only if we have the element.
+ // On mobile platforms the element is not available.
+ if ($('#sidebar-nav').length !== 0) {
+ sidebarNav = '<ul class="nav sidenav">' +
+ '<li class="active"><a href="#top">Top</a></li>';
+
+ for (i; i < arrayLen; i = i + 1) {
+ element = elements[i];
+
+ sidebarNav += '<li><a href="' + checkIfID(element.href) +
+ '">' + element.name + '</a>';
+
+ // Add subnav links (only if really available).
+ if (element.hasOwnProperty('subnav') &&
+ element.subnav !== null) {
+ subNav = element.subnav;
+ subNavLen = subNav.length;
+
+ sidebarNav += '<ul class="nav">';
+ for (j; j < subNavLen; j = j + 1) {
+ sidebarNav += '<li><a href="' +
+ checkIfID(subNav[j].href) +
+ '">' + subNav[j].name +
+ '</a></li>';
+ }
+
+ sidebarNav += '</ul></li>';
}
- sidebarNav += '</ul></li>';
+ sidebarNav += '</li>';
}
- sidebarNav += '</li>';
+ sidebarNav += '</ul>';
+
+ $('#sidebar-nav').empty().append(sidebarNav);
+ $('[data-spy="scroll"]').each(function() {
+ $(this).scrollspy('refresh');
+ });
+ }
+ }
+
+ /*
+ Concatenate objects together in one single object.
+ */
+ function collectObjects() {
+ var returnObject = {},
+ len = arguments.length,
+ arg,
+ i = 0,
+ key;
+
+ for (i = 0; i < len; i++) {
+ arg = arguments[i];
+
+ if (typeof arg === 'object') {
+ for (key in arg) {
+ if (arg.hasOwnProperty(key)) {
+ returnObject[key] = arg[key];
+ }
+ }
+ }
}
- sidebarNav += '</ul>';
+ return returnObject;
+ }
+
+ // Enable keyboard hotkeys/shortcuts.
+ function setHotKeys() {
+ var selectSearch = function() {
+ $('.input-sm').focus();
+ },
+ selectTableLength = function() {
+ $('.length-menu .input-sm').focus();
+ },
+ goToHome = function() {
+ window.location = $('#home-l')[0].href;
+ },
+ goToJob = function() {
+ window.location = $('#job-l')[0].href;
+ },
+ goToBuild = function() {
+ window.location = $('#build-l')[0].href;
+ },
+ goToBoot = function() {
+ window.location = $('#boot-l')[0].href;
+ },
+ goToInfo = function() {
+ window.location = $('#info-l')[0].href;
+ },
+ showHelp = function() {
+ $('#modal-hotkeys').modal('show');
+ };
+
+ $(document).mapHotKeys(
+ [{
+ key: '/',
+ action: selectSearch
+ }, {
+ key: 'l',
+ action: selectTableLength
+ },
+ $.mapHotKeys.createSequence('s', 'h', $(document), showHelp),
+ $.mapHotKeys.createSequence('g', 'h', $(document), goToHome),
+ $.mapHotKeys.createSequence('g', 'j', $(document), goToJob),
+ $.mapHotKeys.createSequence('g', 'b', $(document), goToBuild),
+ $.mapHotKeys.createSequence('g', 't', $(document), goToBoot),
+ $.mapHotKeys.createSequence('g', 'i', $(document), goToInfo)
+ ]
+ );
+ }
+
+ // Set up the base functionalities common to (almost) all pages.
+ function init() {
+ setHotKeys();
+
+ var body = $('body');
+
+ body.tooltip({
+ 'selector': '[rel=tooltip]',
+ 'placement': 'auto top'
+ });
+
+ body.scrollspy({
+ target: '#sidebar-nav'
+ });
+
+ $('.clickable-table tbody').on('click', 'tr', function() {
+ var url = $(this).data('url');
+ if (url) {
+ window.location = url;
+ }
+ });
- $('#sidebar-nav').empty().append(sidebarNav);
- $('[data-spy="scroll"]').each(function() {
- $(this).scrollspy('refresh');
+ $('.btn-group > .btn').click(function() {
+ $(this).addClass('active').siblings().removeClass('active');
});
}
+
+ return {
+ collectObjects: collectObjects,
+ createBisectShellScript: createBisectShellScript,
+ createDeferredCall: createDeferredCall,
+ init: init,
+ loadHTMLContent: loadHTMLContent,
+ populateSideBarNav: populateSideBarNav,
+ replaceContentByClass: replaceContentByClass,
+ replaceContentByID: replaceContentByID,
+ setErrorAlert: setErrorAlert
+ };
+})();
+
+var setErrorAlert = JSBase.setErrorAlert;
+var createBisectScriptURI = JSBase.createBisectShellScript;
+var loadContent = JSBase.loadContent;
+var populateSideBarNav = JSBase.populateSideBarNav;
+var collectObjects = JSBase.collectObjects;
+var csrftoken = $('meta[name=csrf-token]').attr('content');
+
+function setXhrHeader(xhr) {
+ /*
+ Set the CSRF token header for ajax request.
+ xhr: The xhr object to add the header to.
+ */
+ 'use strict';
+ xhr.setRequestHeader('X-CSRFToken', csrftoken);
}
-function createBisectScriptURI(badCommit, goodCommit) {
+/*
+ Return a custom date in ISO format.
+ The format returned is: YYYY-MM-DD
+*/
+Date.prototype.getCustomISODate = function() {
'use strict';
- var bisectScript = '#!/bin/bash\n' +
- 'git bisect start ' + badCommit + ' ' + goodCommit + '\n';
+ var year = this.getUTCFullYear().toString(),
+ month = (this.getUTCMonth() + 1).toString(),
+ day = this.getUTCDate().toString();
- return 'data:text/plain;charset=UTF-8,' + encodeURIComponent(bisectScript);
-}
+ month = month[1] ? month : '0' + month[0];
+ day = day[1] ? day : '0' + day[0];
+
+ return year + '-' + month + '-' + day;
+};
+
+/*
+ Return a custom date in ISO format, based on UTC time.
+ The format returned is: YYYY-MM-DD HH:MM:SS UTC
+*/
+Date.prototype.getCustomISOFormat = function() {
+ 'use strict';
+ var year = this.getUTCFullYear().toString(),
+ month = (this.getUTCMonth() + 1).toString(),
+ day = this.getUTCDate().toString(),
+ hour = this.getUTCHours().toString(),
+ minute = this.getUTCMinutes().toString(),
+ seconds = this.getUTCSeconds().toString();
+
+ month = month[1] ? month : '0' + month[0];
+ day = day[1] ? day : '0' + day[0];
+
+ hour = hour[1] ? hour : '0' + hour[0];
+ minute = minute[1] ? minute : '0' + minute[0];
+ seconds = seconds[1] ? seconds : '0' + seconds[0];
+
+ return year + '-' + month + '-' + day + ' ' + hour + ':' + minute +
+ ':' + seconds + ' UTC';
+};
+
+/*
+ Return a custom time representation. This is mostly useful to calulate
+ elapsed time.
+ The full format returned is: X hours Y min. Z sec. T mill.
+
+ If one of the values for hours, minutes, seconds or milliseconds is 0,
+ it will not be returned.
+*/
+Date.prototype.getCustomTime = function() {
+ 'use strict';
+ var localHours = this.getUTCHours(),
+ localMinutes = this.getUTCMinutes(),
+ localSeconds = this.getUTCSeconds(),
+ localMilliseconds = this.getMilliseconds(),
+ localTime = '';
+
+ if (localHours !== 0) {
+ localTime += localHours.toString() + ' hours ';
+ }
+
+ if (localMinutes !== 0) {
+ localTime += localMinutes.toString() + ' min. ';
+ }
+
+ if (localSeconds !== 0) {
+ localTime += localSeconds.toString() + ' sec. ';
+ }
+
+ if (localMilliseconds !== 0) {
+ localTime += localMilliseconds.toString() + ' mill.';
+ }
+
+ if (!localTime) {
+ localTime = '0';
+ }
+
+ return localTime.trim();
+};