moonfire-nvr/ui/src/lib/views/DatePickerView.js

304 lines
8.0 KiB
JavaScript

// vim: set et sw=2 ts=2:
//
// This file is part of Moonfire NVR, a security camera network video recorder.
// Copyright (C) 2018 The Moonfire NVR Authors
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations including
// the two.
//
// You must obey the GNU General Public License in all respects for all
// of the code used other than OpenSSL. If you modify file(s) with this
// exception, you may extend this exception to your version of the
// file(s), but you are not obligated to do so. If you do not wish to do
// so, delete this exception statement from your version. If you delete
// this exception statement from all source files in the program, then
// also delete it here.
//
// 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import $ from 'jquery';
import 'jquery-ui/themes/base/core.css';
import 'jquery-ui/themes/base/datepicker.css';
import 'jquery-ui/themes/base/theme.css';
import 'jquery-ui/ui/widgets/datepicker';
/**
* Class to encapsulate datepicker UI widget from jQuery.
*/
export default class DatePickerView {
/**
* Get the singleton datepicker instance.
*
* This is useful for accessing implementation constants, such as
* date formats etc.
*
* @return {jQuery.datepicker} JQuery datepicker instance
*/
static get datepicker() {
return $.datepicker;
}
/**
* Construct wapper an attach to a specified parent DOM node.
*
* @param {Node} parent Note to serve for attachign datepicker
* @param {Object} options Options to pass to datepicker
*/
constructor(parent, options = null) {
this.pickerElement_ = $(parent);
/*
* The widget is somewhat peculiar in that its functionality does
* not exist until it has been called with a settings/options argument
* as the only parameter to the datepicker() function.
* So, unless some are passed in here explicitly, we create a default
* and disabled date picker.
*/
this.initWithOptions_(options);
}
/**
* Initialize the date picker with a set of options.
*
* Attach the datepicker function to its parent and set the specified options.
* If the options are not specified a minimum set of options just enabling the
* datepicker with defaults is used.
*
* @param {Object} options Options for datepicker, or null to just enable
*/
initWithOptions_(options = null) {
this.alive_ = true;
options =
options !== null ?
options :
{
disabled: true,
};
this.pickerElement_.datepicker(options);
}
/**
* Execute a specified datepicker function, passing the arguments.
*
* This function exists to catch the cases where functions are called when
* the picker is not attached (alive).
*
* The first argument to this function should be the name of the desired
* datepicker function, followed by the correct arguments for that function.
*
* @return {Any} Function result
*/
apply_(...args) {
if (!this.alive_) {
console.warn('datepicker not constructed yet [%s]', this.domId);
}
return this.pickerElement_.datepicker(...args);
}
/**
* Activate the datepicker if not already attached.
*
* Basically calls initWithOptions_({disabled: disabled}), but only if not
* already attached. Otherwise just sets the disabled status.
*
* @param {Boolean} disabled True if datepicker needs to be disabled
*/
activate(disabled = true) {
if (this.alive_) {
this.disabled = disabled;
} else {
this.initWithOptions_({
disabled: disabled,
});
}
}
/**
* Get the element the datepicker is attached to.
*
* @return {jQuery} jQuery element
*/
get element() {
return this.pickerElement_;
}
/**
* Set option or options to the datepicker, like the 'option' call with
* various arguments.
*
* Special case is when the datepicker is not (yet) attached. In that case
* we need to initialze the datepicker with the options instead.
*
* @param {object} arg0 First parameter or undefined if not given
* @param {array} args Rest of the parameters (might be empty)
* @return {object} Result of the 'option' call.
*/
option(arg0, ...args) {
/*
* Special case the scenario of calling option setting with just a map of
* settings, when the picker is not alive. That really should translate
* to a constructor call to the datepicker.
*/
if (!this.alive_ && args.length === 0 && typeof arg0 === 'object') {
return this.initWithOptions_(arg0);
}
return this.apply_('option', arg0, ...args);
}
/**
* Return current set of options.
*
* This is special cased here vs. documentation. We need to ask for 'all'.
*
* @return {Object} Datepicker options
*/
options() {
return this.option('all');
}
/**
* Determine whether datepicker is disabled.
*
* @return {Boolean}
*/
get isDisabled() {
return this.apply_('isDisabled');
}
/**
* Set disabled status of picker.
*
* @param {Boolean} disabled True to disable
*/
set disabled(disabled) {
this.option('disabled', disabled);
}
/**
* Get picker's currently selected date.
*
* @return {Date} Selected date
*/
get date() {
return this.apply_('getDate');
}
/**
* Set the datepicker to a specific date.
*
* @param {String|Date} date Desired date as string or Date
*/
set date(date) {
this.apply_('setDate', date);
}
/**
* Get the picker's current date in ISO format.
*
* This will return just the date portion of the ISO-8601 format, or in other
* words: YYYY-MM-DD
*
* @return {String} Date portion of ISO-8601 formatted selected date
*/
get dateISO() {
const year = this.date.getYear() + 1900;
const month = (this.date.getMonth() + 1).toString().padStart(2, '0');
const day = this.date.getDate().toString().padStart(2, '0');
return [year, month, day].join('-');
}
/**
* Get currently set minimum date.
*
* @return {Date} Minimum date
*/
get minDate() {
return this.option('minDate');
}
/**
* Set a new minimum date.
*
* @param {String|Date} value Desired minimum date
*/
set minDate(value) {
this.option('minDate', value);
}
/**
* Get currently set maximum date.
*
* @return {Date} Maximum date
*/
get maxDate() {
return this.option('maxDate');
}
/**
* Set a new maximum date.
*
* @param {String|Date} value Desired maximum date
*/
set maxDate(value) {
this.option('maxDate', value);
}
/**
* Set the picker to open up in a dialog.
*
* This takes a variable number of arguments, like the native dialog function.
*
* @param {varargs} dialogArgs Variable argument list
*/
dialog(...dialogArgs) {
this.apply_('option', dialogArgs);
}
/**
* Make the picker visible.
*/
show() {
this.apply_('show');
}
/**
* Hide the picker.
*/
hide() {
this.apply_('hide');
}
/**
* Refresh the picker.
*/
refresh() {
this.apply_('refresh');
}
/**
* Destroy the picker.
*
* Destroy means detach it from its element and dispose of everything.
* Sets the status in this object to !alive.
*/
destroy() {
this.alive_ = true;
this.apply_('destroy');
this.alive_ = false;
}
}