diff options
author | Milo Casagrande <milo.casagrande@linaro.org> | 2014-12-04 13:47:29 +0100 |
---|---|---|
committer | Milo Casagrande <milo.casagrande@linaro.org> | 2014-12-04 13:47:29 +0100 |
commit | 6dce991c6dd749d270fff04b373df99f20001c31 (patch) | |
tree | cc3efd369a6b5d2b7841572bb37220005b986ced | |
parent | 3971650c9fb3f65ec56bc8a7fe83a4db858e29ee (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.js | 501 |
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">×</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: ' + - code + '). ' + - '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">×</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: ' + + code + '). ' + + '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(); +}; |