mirror of
https://github.com/dkmstr/openuds.git
synced 2024-12-22 13:34:04 +03:00
Added gui basic elements
refactoring of existint javascript translations of buttons moved to better place added css class that will made button text dissapear for smaller displays
This commit is contained in:
parent
6144eb2f6a
commit
4b2eae58b1
@ -36,7 +36,7 @@ from django.utils.translation import ugettext, ugettext_lazy as _
|
||||
from uds.models import Provider
|
||||
from uds.core import services
|
||||
|
||||
from uds.REST import Handler, HandlerError
|
||||
from uds.REST import Handler, NotFound
|
||||
from uds.REST.mixins import ModelHandlerMixin, ModelTypeHandlerMixin, ModelTableHandlerMixin
|
||||
|
||||
import logging
|
||||
@ -62,12 +62,18 @@ class Types(ModelTypeHandlerMixin, Handler):
|
||||
def enum_types(self):
|
||||
return services.factory().providers().values()
|
||||
|
||||
def getGui(self, type_):
|
||||
try:
|
||||
return services.factory().lookup(type_).guiDescription()
|
||||
except:
|
||||
raise NotFound('type not found')
|
||||
|
||||
class TableInfo(ModelTableHandlerMixin, Handler):
|
||||
path = 'providers'
|
||||
title = _('Current service providers')
|
||||
fields = [
|
||||
{ 'name': {'title': _('Name'), 'type': 'iconType' } },
|
||||
{ 'comments': {'title': _('Comments')}},
|
||||
{ 'services_count': {'title': _('Services'), 'type': 'numeric', 'width': '5em'}}
|
||||
{ 'services_count': {'title': _('Services'), 'type': 'numeric', 'width': '5em'}},
|
||||
]
|
||||
|
||||
|
@ -145,6 +145,41 @@ class ModelTypeHandlerMixin(object):
|
||||
|
||||
if self._args[1] == 'gui':
|
||||
gui = self.getGui(self._args[0])
|
||||
# Add name default description, at top of form
|
||||
gui.insert(0, {
|
||||
'name': 'name',
|
||||
'value':'',
|
||||
'gui': {
|
||||
'required':True,
|
||||
'defvalue':'',
|
||||
'value':'',
|
||||
'label': _('Name'),
|
||||
'length': 128,
|
||||
'multiline': 0,
|
||||
'tooltip': _('Name of this element'),
|
||||
'rdonly': False,
|
||||
'type': 'text',
|
||||
'order': 1
|
||||
}
|
||||
})
|
||||
# And comments
|
||||
gui.insert(1, {
|
||||
'name': 'comments',
|
||||
'value':'',
|
||||
'gui': {
|
||||
'required':True,
|
||||
'defvalue':'',
|
||||
'value':'',
|
||||
'label': _('Comments'),
|
||||
'length': 256,
|
||||
'multiline': 0,
|
||||
'tooltip': _('Comments for this element'),
|
||||
'rdonly': False,
|
||||
'type': 'text',
|
||||
'order': 1
|
||||
}
|
||||
})
|
||||
|
||||
logger.debug("GUI: {0}".format(gui))
|
||||
return gui
|
||||
|
||||
|
@ -92,7 +92,9 @@ table.tablesorter thead tr th:hover {
|
||||
margin-bottom:12px;
|
||||
}
|
||||
|
||||
|
||||
.label-tbl-button {
|
||||
display: none;
|
||||
}
|
||||
/* Edit Below to Customize Widths > 768px */
|
||||
@media (min-width:768px) {
|
||||
|
||||
@ -166,4 +168,9 @@ table.tablesorter thead tr th:hover {
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.label-tbl-button {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -34,8 +34,8 @@ gui.providers.link = function(event) {
|
||||
|
||||
var tableId = gui.providers.table({
|
||||
rowSelect : 'multi',
|
||||
rowSelectFnc : function(nodes) {
|
||||
gui.doLog(nodes);
|
||||
rowSelectFnc : function(data) {
|
||||
gui.doLog(data);
|
||||
gui.doLog(this);
|
||||
gui.doLog(this.fnGetSelectedData());
|
||||
},
|
||||
@ -65,15 +65,15 @@ gui.authenticators.link = function(event) {
|
||||
container : 'auths-placeholder',
|
||||
rowSelect : 'single',
|
||||
buttons : [ 'edit', 'refresh', 'delete', 'xls' ],
|
||||
onRowSelect : function(nodes) {
|
||||
onRowSelect : function(selected) {
|
||||
api.tools.blockUI();
|
||||
var id = this.fnGetSelectedData()[0].id;
|
||||
var id = selected[0].id;
|
||||
var user = new GuiElement(api.authenticators.detail(id, 'users'), 'users');
|
||||
user.table({
|
||||
container : 'users-placeholder',
|
||||
rowSelect : 'multi',
|
||||
buttons : [ 'edit', 'refresh', 'delete', 'xls' ],
|
||||
scroll : true,
|
||||
scrollToTable : true,
|
||||
onLoad: function(k) {
|
||||
api.tools.unblockUI();
|
||||
},
|
||||
|
@ -13,8 +13,10 @@
|
||||
}
|
||||
};
|
||||
|
||||
// Several convenience "constants"
|
||||
gui.dataTablesLanguage = {
|
||||
gui.config = gui.config || {};
|
||||
|
||||
// Several convenience "constants" for tables
|
||||
gui.config.dataTablesLanguage = {
|
||||
"sLengthMenu" : gettext("_MENU_ records per page"),
|
||||
"sZeroRecords" : gettext("Empty"),
|
||||
"sInfo" : gettext("Records _START_ to _END_ of _TOTAL_"),
|
||||
@ -31,6 +33,14 @@
|
||||
}
|
||||
};
|
||||
|
||||
gui.config.dataTableButtonsText = {
|
||||
'new': '<span class="fa fa-pencil"></span> <span class="label-tbl-button">' + gettext('New') + '</span>',
|
||||
'edit': '<span class="fa fa-edit"></span> <span class="label-tbl-button">' + gettext('Edit') + '</span>',
|
||||
'delete': '<span class="fa fa-eraser"></span> <span class="label-tbl-button">' + gettext('Delete') + '</span>',
|
||||
'refresh': '<span class="fa fa-refresh"></span> <span class="label-tbl-button">' + gettext('Refresh') + '</span>',
|
||||
'xls': '<span class="fa fa-save"></span> <span class="label-tbl-button">' + gettext('Xls') + '</span>',
|
||||
};
|
||||
|
||||
gui.table = function(title, table_id, options) {
|
||||
if (options === undefined)
|
||||
options = {
|
||||
@ -158,19 +168,48 @@ GuiElement.prototype = {
|
||||
},
|
||||
});
|
||||
},
|
||||
// Options: dictionary
|
||||
// container: container ID of parent for the table. If undefined, table will be appended to workspace
|
||||
// buttons: array of visible buttons (strings), valid are [ 'new', 'edit', 'refresh', 'delete', 'xls' ],
|
||||
// rowSelect: type of allowed row selection, valid values are 'single' and 'multi'
|
||||
// scrollToTable: if True, will scroll page to show table
|
||||
//
|
||||
// onLoad: Event (function). If defined, will be invoked when table is fully loaded.
|
||||
// Receives 1 parameter, that is the gui element (GuiElement) used to render table
|
||||
// onRowSelect: Event (function). If defined, will be invoked when a row of table is selected
|
||||
// Receives 3 parameters:
|
||||
// 1.- the array of selected items data (objects, as got from api...get)
|
||||
// 2.- the DataTable that raised the event
|
||||
// 3.- the DataTableTools that raised the event
|
||||
// onRowDeselect: Event (function). If defined, will be invoked when a row of table is deselected
|
||||
// Receives 3 parameters:
|
||||
// 1.- the array of selected items data (objects, as got from api...get)
|
||||
// 2.- the DataTable that raised the event
|
||||
// 3.- the DataTableTools that raised the event
|
||||
// onNew: Event (function). If defined, will be invoked when "new" button is pressed
|
||||
// Receives 4 parameters:
|
||||
// 1.- the selected item data (single object, as got from api...get)
|
||||
// 2.- the event that fired this (new, delete, edit, ..)
|
||||
// 3.- the DataTable that raised the event
|
||||
// 4.- the DataTableTools that raised the event
|
||||
// onEdit: Event (function). If defined, will be invoked when "edit" button is pressed
|
||||
// Receives 4 parameters:
|
||||
// 1.- the selected item data (single object, as got from api...get)
|
||||
// 2.- the event that fired this (new, delete, edit, ..)
|
||||
// 3.- the DataTable that raised the event
|
||||
// 4.- the DataTableTools that raised the event
|
||||
// onDelete: Event (function). If defined, will be invoked when "delete" button is pressed
|
||||
// Receives 4 parameters:
|
||||
// 1.- the selected item data (single object, as got from api...get)
|
||||
// 2.- the event that fired this (new, delete, edit, ..)
|
||||
// 4.- the DataTable that raised the event
|
||||
// 5.- the DataTableTools that raised the event
|
||||
table : function(options) {
|
||||
"use strict";
|
||||
// Options (all are optionals)
|
||||
// rowSelect: 'single' or 'multi'
|
||||
// container: ID of the element that will hold this table (will be
|
||||
// emptied)
|
||||
// rowSelectFnc: function to invoke on row selection. receives 1 array -
|
||||
// node : TR elements that were selected
|
||||
// rowDeselectFnc: function to invoke on row deselection. receives 1
|
||||
// array - node : TR elements that were selected
|
||||
options = options || {};
|
||||
gui.doLog('Composing table for ' + this.name);
|
||||
var tableId = this.name + '-table';
|
||||
var $this = this;
|
||||
var $this = this; // Store this for child functions
|
||||
|
||||
// Empty cells transform
|
||||
var renderEmptyCell = function(data) {
|
||||
@ -212,21 +251,28 @@ GuiElement.prototype = {
|
||||
return dict[data] || renderEmptyCell('');
|
||||
};
|
||||
};
|
||||
|
||||
this.rest.tableInfo({
|
||||
success: function(data) {
|
||||
var title = data.title;
|
||||
var columns = [];
|
||||
$.each(data.fields, function(index, value) {
|
||||
for ( var v in value) {
|
||||
var options = value[v];
|
||||
var opts = value[v];
|
||||
var column = {
|
||||
mData : v,
|
||||
};
|
||||
column.sTitle = options.title;
|
||||
column.sTitle = opts.title;
|
||||
column.mRender = renderEmptyCell;
|
||||
if (options.type !== undefined) {
|
||||
switch(options.type) {
|
||||
if (opts.width)
|
||||
column.sWidth = opts.width;
|
||||
column.bVisible = opts.visible === undefined ? true : opts.visible;
|
||||
if (opts.sortable !== undefined)
|
||||
column.bSortable = opts.sortable;
|
||||
if (opts.searchable !== undefined)
|
||||
column.bSearchable = opts.searchable;
|
||||
|
||||
if (opts.type !== undefined && column.bVisible ) {
|
||||
switch(opts.type) {
|
||||
case 'date':
|
||||
column.sType = 'date';
|
||||
column.mRender = renderDate(api.tools.djangoFormat(get_format('SHORT_DATE_FORMAT')));
|
||||
@ -243,31 +289,23 @@ GuiElement.prototype = {
|
||||
column.mRender = renderTypeIcon;
|
||||
break;
|
||||
case 'icon':
|
||||
if( options.icon !== undefined ) {
|
||||
column.mRender = renderIcon(options.icon);
|
||||
if( opts.icon !== undefined ) {
|
||||
column.mRender = renderIcon(opts.icon);
|
||||
}
|
||||
break;
|
||||
case 'dict':
|
||||
if( options.dict !== undefined ) {
|
||||
column.mRender = renderTextTransform(options.dict);
|
||||
if( opts.dict !== undefined ) {
|
||||
column.mRender = renderTextTransform(opts.dict);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
column.sType = options.type;
|
||||
column.sType = opts.type;
|
||||
}
|
||||
}
|
||||
if (options.width)
|
||||
column.sWidth = options.width;
|
||||
if (options.visible !== undefined)
|
||||
column.bVisible = options.visible;
|
||||
if (options.sortable !== undefined)
|
||||
column.bSortable = options.sortable;
|
||||
if (options.searchable !== undefined)
|
||||
column.bSearchable = options.searchable;
|
||||
columns.push(column);
|
||||
}
|
||||
});
|
||||
// Generate styles for responsibe table, just the name of fields
|
||||
// Generate styles for responsible table, just the name of fields
|
||||
var respStyles = [];
|
||||
var counter = 0;
|
||||
$.each(columns, function(col, value) {
|
||||
@ -295,15 +333,16 @@ GuiElement.prototype = {
|
||||
var btns = [];
|
||||
|
||||
if (options.buttons) {
|
||||
|
||||
// methods for buttons click
|
||||
var editFnc = function() {
|
||||
gui.doLog('Edit');
|
||||
gui.doLog(this);
|
||||
var clickHandlerFor = function(handler, action) {
|
||||
var handleFnc = handler || function(val, action, tbl, tbltools) {gui.doLog('Default handler called for ' + action + ': ' + JSON.stringify(val));};
|
||||
return function(btn) {
|
||||
var tblTools = this;
|
||||
var table = $('#' + tableId).dataTable();
|
||||
var val = this.fnGetSelectedData()[0];
|
||||
setTimeout(function() {
|
||||
handleFnc(val, action, table, tblTools);
|
||||
}, 0);
|
||||
};
|
||||
var deleteFnc = function() {
|
||||
gui.doLog('Delete');
|
||||
gui.doLog(this);
|
||||
};
|
||||
|
||||
// What execute on refresh button push
|
||||
@ -354,28 +393,37 @@ GuiElement.prototype = {
|
||||
$.each(options.buttons, function(index, value) {
|
||||
var btn;
|
||||
switch (value) {
|
||||
case 'new':
|
||||
btn = {
|
||||
"sExtends" : "text",
|
||||
"sButtonText" : gui.config.dataTableButtonsText['new'],
|
||||
"fnSelect" : deleteSelected,
|
||||
"fnClick" : clickHandlerFor(options.onDelete, 'delete'),
|
||||
"sButtonClass" : "disabled btn3d btn3d-tables"
|
||||
};
|
||||
break;
|
||||
case 'edit':
|
||||
btn = {
|
||||
"sExtends" : "text",
|
||||
"sButtonText" : gettext('Edit'),
|
||||
"sButtonText" : gui.config.dataTableButtonsText['edit'],
|
||||
"fnSelect" : editSelected,
|
||||
"fnClick" : editFnc,
|
||||
"fnClick" : clickHandlerFor(options.onEdit, 'edit'),
|
||||
"sButtonClass" : "disabled btn3d btn3d-tables"
|
||||
};
|
||||
break;
|
||||
case 'delete':
|
||||
btn = {
|
||||
"sExtends" : "text",
|
||||
"sButtonText" : gettext('Delete'),
|
||||
"sButtonText" : gui.config.dataTableButtonsText['delete'],
|
||||
"fnSelect" : deleteSelected,
|
||||
"fnClick" : deleteFnc,
|
||||
"fnClick" : clickHandlerFor(options.onDelete, 'delete'),
|
||||
"sButtonClass" : "disabled btn3d btn3d-tables"
|
||||
};
|
||||
break;
|
||||
case 'refresh':
|
||||
btn = {
|
||||
"sExtends" : "text",
|
||||
"sButtonText" : gettext('Refresh'),
|
||||
"sButtonText" : gui.config.dataTableButtonsText['refresh'],
|
||||
"fnClick" : refreshFnc,
|
||||
"sButtonClass" : "btn3d-primary btn3d btn3d-tables"
|
||||
};
|
||||
@ -383,7 +431,7 @@ GuiElement.prototype = {
|
||||
case 'xls':
|
||||
btn = {
|
||||
"sExtends" : "text",
|
||||
"sButtonText" : 'xls',
|
||||
"sButtonText" : gui.config.dataTableButtonsText['xls'],
|
||||
"fnClick" : function(){
|
||||
api.templates.get('spreadsheet', function(tmpl) {
|
||||
var styles = { 'bold': 's21', };
|
||||
@ -417,7 +465,6 @@ GuiElement.prototype = {
|
||||
rows_count: rows.length,
|
||||
rows: rows.join('\n')
|
||||
};
|
||||
// window.location.href = uri + base64(api.templates.evaluate(tmpl, ctx));
|
||||
setTimeout( function() {
|
||||
saveAs(new Blob([api.templates.evaluate(tmpl, ctx)],
|
||||
{type: 'application/vnd.ms-excel'} ), title + '.xls');
|
||||
@ -437,20 +484,29 @@ GuiElement.prototype = {
|
||||
var oTableTools = {
|
||||
"aButtons" : btns
|
||||
};
|
||||
|
||||
// Type of row selection
|
||||
if (options.rowSelect) {
|
||||
oTableTools.sRowSelect = options.rowSelect;
|
||||
}
|
||||
|
||||
if (options.onRowSelect) {
|
||||
oTableTools.fnRowSelected = options.onRowSelect;
|
||||
var rowSelectedFnc = options.onRowSelect;
|
||||
oTableTools.fnRowSelected = function() {
|
||||
rowSelectedFnc(this.fnGetSelectedData(), $('#' + tableId).dataTable(), this);
|
||||
};
|
||||
}
|
||||
if (options.onRowDeselect) {
|
||||
oTableTools.fnRowDeselected = options.onRowDeselect;
|
||||
var rowDeselectedFnc = options.onRowDeselect;
|
||||
oTableTools.fnRowDeselected = function() {
|
||||
rowDeselectedFnc(this.fnGetSelectedData(), $('#' + tableId).dataTable(), this);
|
||||
};
|
||||
}
|
||||
|
||||
$('#' + tableId).dataTable({
|
||||
"aaData" : data,
|
||||
"aoColumns" : columns,
|
||||
"oLanguage" : gui.dataTablesLanguage,
|
||||
"oLanguage" : gui.config.dataTablesLanguage,
|
||||
"oTableTools" : oTableTools,
|
||||
// First is upper row,
|
||||
// second row is lower
|
||||
@ -462,7 +518,7 @@ GuiElement.prototype = {
|
||||
api.tools.fix3dButtons('#' + tableId + '_wrapper .btn-group-3d');
|
||||
// Fix form
|
||||
//$('#' + tableId + '_filter input').addClass('form-control');
|
||||
if (options.scroll !== undefined ) {
|
||||
if (options.scrollToTable === true ) {
|
||||
var tableTop = $('#' + tableId).offset().top;
|
||||
$('html, body').scrollTop(tableTop);
|
||||
}
|
||||
|
@ -1,392 +0,0 @@
|
||||
//
|
||||
// strftime
|
||||
// github.com/samsonjs/strftime
|
||||
// @_sjs
|
||||
//
|
||||
// Copyright 2010 - 2013 Sami Samhuri <sami@samhuri.net>
|
||||
//
|
||||
// MIT License
|
||||
// http://sjs.mit-license.org
|
||||
//
|
||||
|
||||
;(function() {
|
||||
|
||||
var namespace = api.tools;
|
||||
|
||||
var dayNames = [ gettext('Sunday'), gettext('Monday'), gettext('Tuesday'), gettext('Wednesday'),
|
||||
gettext('Thursday'), gettext('Friday'), gettext('Saturday') ];
|
||||
var monthNames = [ gettext('January'), gettext('February'), gettext('March'), gettext('April'), gettext('May'),
|
||||
gettext('June'), gettext('July'), gettext('August'), gettext('September'), gettext('October'),
|
||||
gettext('November'), gettext('December') ];
|
||||
|
||||
function initialsOf(arr) {
|
||||
var res = [];
|
||||
for ( var v in arr) {
|
||||
res.push(arr[v].substr(0, 3));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
var DefaultLocale = {
|
||||
days : dayNames,
|
||||
shortDays : initialsOf(dayNames),
|
||||
months : monthNames,
|
||||
shortMonths : initialsOf(monthNames),
|
||||
AM : 'AM',
|
||||
PM : 'PM',
|
||||
am : 'am',
|
||||
pm : 'pm',
|
||||
};
|
||||
|
||||
// Added this to convert django format strings to c format string
|
||||
// This is ofc, a "simplified" version, aimed to use date format used by
|
||||
// DJANGO
|
||||
namespace.djangoFormat = function(format) {
|
||||
return format.replace(/./g, function(c) {
|
||||
switch (c) {
|
||||
case 'a':
|
||||
case 'A':
|
||||
return '%p';
|
||||
case 'b':
|
||||
case 'd':
|
||||
case 'm':
|
||||
case 'w':
|
||||
case 'W':
|
||||
case 'y':
|
||||
case 'Y':
|
||||
return '%' + c;
|
||||
case 'c':
|
||||
return '%FT%TZ';
|
||||
case 'D':
|
||||
return '%a';
|
||||
case 'e':
|
||||
return '%z';
|
||||
case 'f':
|
||||
return '%I:%M';
|
||||
case 'F':
|
||||
return '%F';
|
||||
case 'h':
|
||||
case 'g':
|
||||
return '%I';
|
||||
case 'H':
|
||||
case 'G':
|
||||
return '%H';
|
||||
case 'i':
|
||||
return '%M';
|
||||
case 'I':
|
||||
return ''; // daylight saving
|
||||
case 'j':
|
||||
return '%d';
|
||||
case 'l':
|
||||
return '%A';
|
||||
case 'L':
|
||||
return ''; // if it is leap year
|
||||
case 'M':
|
||||
return '%b';
|
||||
case 'n':
|
||||
return '%m';
|
||||
case 'N':
|
||||
return '%b';
|
||||
case 'o':
|
||||
return '%W'; // Not so sure, not important i thing anyway :-)
|
||||
case 'O':
|
||||
return '%z';
|
||||
case 'P':
|
||||
return '%R %p';
|
||||
case 'r':
|
||||
return '%a, %d %b %Y %T %z';
|
||||
case 's':
|
||||
return '%S';
|
||||
case 'S':
|
||||
return ''; // english ordinal suffix for day of month
|
||||
case 't':
|
||||
return ''; // number of days of specified month, not important
|
||||
case 'T':
|
||||
return '%Z';
|
||||
case 'u':
|
||||
return '0'; // microseconds
|
||||
case 'U':
|
||||
return ''; // Seconds since EPOCH, not used
|
||||
case 'z':
|
||||
return '%j';
|
||||
case 'Z':
|
||||
return 'z'; // Time zone offset in seconds, replaced by offset
|
||||
// in ours/minutes :-)
|
||||
default:
|
||||
return c;
|
||||
}
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
namespace.strftime = strftime;
|
||||
function strftime(fmt, d, locale) {
|
||||
return _strftime(fmt, d, locale);
|
||||
}
|
||||
|
||||
// locale is optional
|
||||
namespace.strftimeTZ = strftime.strftimeTZ = strftimeTZ;
|
||||
function strftimeTZ(fmt, d, locale, timezone) {
|
||||
if (typeof locale == 'number' && timezone === null) {
|
||||
timezone = locale;
|
||||
locale = undefined;
|
||||
}
|
||||
return _strftime(fmt, d, locale, {
|
||||
timezone : timezone
|
||||
});
|
||||
}
|
||||
|
||||
namespace.strftimeUTC = strftime.strftimeUTC = strftimeUTC;
|
||||
function strftimeUTC(fmt, d, locale) {
|
||||
return _strftime(fmt, d, locale, {
|
||||
utc : true
|
||||
});
|
||||
}
|
||||
|
||||
namespace.localizedStrftime = strftime.localizedStrftime = localizedStrftime;
|
||||
function localizedStrftime(locale) {
|
||||
return function(fmt, d, options) {
|
||||
return strftime(fmt, d, locale, options);
|
||||
};
|
||||
}
|
||||
|
||||
// d, locale, and options are optional, but you can't leave
|
||||
// holes in the argument list. If you pass options you have to pass
|
||||
// in all the preceding args as well.
|
||||
//
|
||||
// options:
|
||||
// - locale [object] an object with the same structure as DefaultLocale
|
||||
// - timezone [number] timezone offset in minutes from GMT
|
||||
function _strftime(fmt, d, locale, options) {
|
||||
options = options || {};
|
||||
|
||||
// d and locale are optional so check if d is really the locale
|
||||
if (d && !quacksLikeDate(d)) {
|
||||
locale = d;
|
||||
d = undefined;
|
||||
}
|
||||
d = d || new Date();
|
||||
|
||||
locale = locale || DefaultLocale;
|
||||
locale.formats = locale.formats || {};
|
||||
|
||||
// Hang on to this Unix timestamp because we might mess with it directly
|
||||
// below.
|
||||
var timestamp = d.getTime();
|
||||
|
||||
if (options.utc || typeof options.timezone == 'number') {
|
||||
d = dateToUTC(d);
|
||||
}
|
||||
|
||||
if (typeof options.timezone == 'number') {
|
||||
d = new Date(d.getTime() + (options.timezone * 60000));
|
||||
}
|
||||
|
||||
// Most of the specifiers supported by C's strftime, and some from Ruby.
|
||||
// Some other syntax extensions from Ruby are supported: %-, %_, and %0
|
||||
// to pad with nothing, space, or zero (respectively).
|
||||
return fmt.replace(/%([-_0]?.)/g, function(_, c) {
|
||||
var mod, padding;
|
||||
if (c.length == 2) {
|
||||
mod = c[0];
|
||||
// omit padding
|
||||
if (mod == '-') {
|
||||
padding = '';
|
||||
}
|
||||
// pad with space
|
||||
else if (mod == '_') {
|
||||
padding = ' ';
|
||||
}
|
||||
// pad with zero
|
||||
else if (mod == '0') {
|
||||
padding = '0';
|
||||
} else {
|
||||
// unrecognized, return the format
|
||||
return _;
|
||||
}
|
||||
c = c[1];
|
||||
}
|
||||
switch (c) {
|
||||
case 'A':
|
||||
return locale.days[d.getDay()];
|
||||
case 'a':
|
||||
return locale.shortDays[d.getDay()];
|
||||
case 'B':
|
||||
return locale.months[d.getMonth()];
|
||||
case 'b':
|
||||
return locale.shortMonths[d.getMonth()];
|
||||
case 'C':
|
||||
return pad(Math.floor(d.getFullYear() / 100), padding);
|
||||
case 'D':
|
||||
return _strftime(locale.formats.D || '%m/%d/%y', d, locale);
|
||||
case 'd':
|
||||
return pad(d.getDate(), padding);
|
||||
case 'e':
|
||||
return d.getDate();
|
||||
case 'F':
|
||||
return _strftime(locale.formats.F || '%Y-%m-%d', d, locale);
|
||||
case 'H':
|
||||
return pad(d.getHours(), padding);
|
||||
case 'h':
|
||||
return locale.shortMonths[d.getMonth()];
|
||||
case 'I':
|
||||
return pad(hours12(d), padding);
|
||||
case 'j':
|
||||
var y = new Date(d.getFullYear(), 0, 1);
|
||||
var day = Math.ceil((d.getTime() - y.getTime()) / (1000 * 60 * 60 * 24));
|
||||
return pad(day, 3);
|
||||
case 'k':
|
||||
return pad(d.getHours(), padding === null ? ' ' : padding);
|
||||
case 'L':
|
||||
return pad(Math.floor(timestamp % 1000), 3);
|
||||
case 'l':
|
||||
return pad(hours12(d), padding === null ? ' ' : padding);
|
||||
case 'M':
|
||||
return pad(d.getMinutes(), padding);
|
||||
case 'm':
|
||||
return pad(d.getMonth() + 1, padding);
|
||||
case 'n':
|
||||
return '\n';
|
||||
case 'o':
|
||||
return String(d.getDate()) + ordinal(d.getDate());
|
||||
case 'P':
|
||||
return d.getHours() < 12 ? locale.am : locale.pm;
|
||||
case 'p':
|
||||
return d.getHours() < 12 ? locale.AM : locale.PM;
|
||||
case 'R':
|
||||
return _strftime(locale.formats.R || '%H:%M', d, locale);
|
||||
case 'r':
|
||||
return _strftime(locale.formats.r || '%I:%M:%S %p', d, locale);
|
||||
case 'S':
|
||||
return pad(d.getSeconds(), padding);
|
||||
case 's':
|
||||
return Math.floor(timestamp / 1000);
|
||||
case 'T':
|
||||
return _strftime(locale.formats.T || '%H:%M:%S', d, locale);
|
||||
case 't':
|
||||
return '\t';
|
||||
case 'U':
|
||||
return pad(weekNumber(d, 'sunday'), padding);
|
||||
case 'u':
|
||||
var dayu = d.getDay();
|
||||
return dayu === 0 ? 7 : dayu; // 1 - 7, Monday is first day of the
|
||||
// week
|
||||
case 'v':
|
||||
return _strftime(locale.formats.v || '%e-%b-%Y', d, locale);
|
||||
case 'W':
|
||||
return pad(weekNumber(d, 'monday'), padding);
|
||||
case 'w':
|
||||
return d.getDay(); // 0 - 6, Sunday is first day of the
|
||||
// week
|
||||
case 'Y':
|
||||
return d.getFullYear();
|
||||
case 'y':
|
||||
var yy = String(d.getFullYear());
|
||||
return yy.slice(yy.length - 2);
|
||||
case 'Z':
|
||||
if (options.utc) {
|
||||
return "GMT";
|
||||
} else {
|
||||
var tz = d.toString().match(/\((\w+)\)/);
|
||||
return tz && tz[1] || '';
|
||||
}
|
||||
break;
|
||||
case 'z':
|
||||
if (options.utc) {
|
||||
return "+0000";
|
||||
} else {
|
||||
var off = typeof options.timezone == 'number' ? options.timezone : -d.getTimezoneOffset();
|
||||
return (off < 0 ? '-' : '+') + pad(Math.abs(off / 60)) + pad(off % 60);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return c;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function dateToUTC(d) {
|
||||
var msDelta = (d.getTimezoneOffset() || 0) * 60000;
|
||||
return new Date(d.getTime() + msDelta);
|
||||
}
|
||||
|
||||
var RequiredDateMethods = [ 'getTime', 'getTimezoneOffset', 'getDay', 'getDate', 'getMonth', 'getFullYear',
|
||||
'getYear', 'getHours', 'getMinutes', 'getSeconds' ];
|
||||
function quacksLikeDate(x) {
|
||||
var i = 0, n = RequiredDateMethods.length;
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (typeof x[RequiredDateMethods[i]] != 'function') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Default padding is '0' and default length is 2, both are optional.
|
||||
function pad(n, padding, length) {
|
||||
// pad(n, <length>)
|
||||
if (typeof padding === 'number') {
|
||||
length = padding;
|
||||
padding = '0';
|
||||
}
|
||||
|
||||
// Defaults handle pad(n) and pad(n, <padding>)
|
||||
if (padding === null) {
|
||||
padding = '0';
|
||||
}
|
||||
length = length || 2;
|
||||
|
||||
var s = String(n);
|
||||
// padding may be an empty string, don't loop forever if it is
|
||||
if (padding) {
|
||||
while (s.length < length)
|
||||
s = padding + s;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
function hours12(d) {
|
||||
var hour = d.getHours();
|
||||
if (hour === 0)
|
||||
hour = 12;
|
||||
else if (hour > 12)
|
||||
hour -= 12;
|
||||
return hour;
|
||||
}
|
||||
|
||||
// Get the ordinal suffix for a number: st, nd, rd, or th
|
||||
function ordinal(n) {
|
||||
var i = n % 10, ii = n % 100;
|
||||
if ((ii >= 11 && ii <= 13) || i === 0 || i >= 4) {
|
||||
return 'th';
|
||||
}
|
||||
switch (i) {
|
||||
case 1:
|
||||
return 'st';
|
||||
case 2:
|
||||
return 'nd';
|
||||
case 3:
|
||||
return 'rd';
|
||||
}
|
||||
}
|
||||
|
||||
// firstWeekday: 'sunday' or 'monday', default is 'sunday'
|
||||
//
|
||||
// Pilfered & ported from Ruby's strftime implementation.
|
||||
function weekNumber(d, firstWeekday) {
|
||||
firstWeekday = firstWeekday || 'sunday';
|
||||
|
||||
// This works by shifting the weekday back by one day if we
|
||||
// are treating Monday as the first day of the week.
|
||||
var wday = d.getDay();
|
||||
if (firstWeekday == 'monday') {
|
||||
if (wday === 0) // Sunday
|
||||
wday = 6;
|
||||
else
|
||||
wday--;
|
||||
}
|
||||
var firstDayOfYear = new Date(d.getFullYear(), 0, 1), yday = (d - firstDayOfYear) / 86400000, weekNum = (yday + 7 - wday) / 7;
|
||||
return Math.floor(weekNum);
|
||||
}
|
||||
|
||||
}());
|
@ -55,10 +55,6 @@
|
||||
<script src="{% get_static_prefix %}adm/js/Blob.js"></script>
|
||||
<script src="{% get_static_prefix %}adm/js/FileSaver.js"></script>
|
||||
|
||||
|
||||
<!-- strftime -->
|
||||
<script src="{% get_static_prefix %}adm/js/strftime.js"></script>
|
||||
|
||||
<!-- <script src="{% get_static_prefix %}adm/js/ZeroClipboard.js"></script> -->
|
||||
|
||||
<script src="{% get_static_prefix %}adm/js/dataTables.bootstrap.js"></script>
|
||||
@ -81,17 +77,21 @@
|
||||
<!-- First all api related stuff -->
|
||||
<script src="{% get_static_prefix %}adm/js/api.js"></script>
|
||||
|
||||
<!-- utilities attached to api -->
|
||||
<script src="{% get_static_prefix %}adm/js/api-tools.js"></script>
|
||||
|
||||
<!-- templates related, inserts itself into api -->
|
||||
<script src="{% get_static_prefix %}adm/js/templates.js"></script>
|
||||
|
||||
<!-- export to xls, inserts itself into api -->
|
||||
<script src="{% get_static_prefix %}adm/js/spreadsheet.js"></script>
|
||||
<script src="{% get_static_prefix %}adm/js/api-spreadsheet.js"></script>
|
||||
|
||||
<!-- utilities attached to api -->
|
||||
<script src="{% get_static_prefix %}adm/js/tools.js"></script>
|
||||
|
||||
|
||||
<script src="{% get_static_prefix %}adm/js/gui.js"></script>
|
||||
<script src="{% get_static_prefix %}adm/js/gui-fields.js"></script>
|
||||
|
||||
<!-- user interface management -->
|
||||
<script src="{% get_static_prefix %}adm/js/gui-elements.js"></script>
|
||||
|
||||
<script>
|
||||
|
Loading…
Reference in New Issue
Block a user