21 changed files with 1224 additions and 0 deletions
@ -0,0 +1,35 @@ |
|||||
|
================= |
||||
|
Time Picker Field |
||||
|
================= |
||||
|
|
||||
|
Time picker for fields, using Wickedpicker. |
||||
|
|
||||
|
Installation & Configuration |
||||
|
============================ |
||||
|
|
||||
|
After installing the module, you can use character fields for reading time input with the help of a time picker. |
||||
|
When you define the fields in xml, use 'widget="timepicker"' for those fields which you need to use as time fields. |
||||
|
|
||||
|
|
||||
|
Known issues / Roadmap |
||||
|
====================== |
||||
|
|
||||
|
* ... |
||||
|
|
||||
|
Bug Tracker |
||||
|
=========== |
||||
|
|
||||
|
Contact odoo@cybrosys.com |
||||
|
|
||||
|
|
||||
|
Contributors |
||||
|
------------ |
||||
|
|
||||
|
* Linto CT <linto@cybrosys.in> |
||||
|
|
||||
|
Maintainer |
||||
|
---------- |
||||
|
|
||||
|
This module is maintained by Cybrosys Technologies. |
||||
|
|
||||
|
For support and more information, please visit https://www.cybrosys.com. |
@ -0,0 +1,23 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
|
||||
|
############################################################################## |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# Copyright (C) 2018-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
||||
|
# Author: LINTO C T(<https://www.cybrosys.com>) |
||||
|
# you can modify it under the terms of the GNU LESSER |
||||
|
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. |
||||
|
# |
||||
|
# It is forbidden to publish, distribute, sublicense, or sell copies |
||||
|
# of the Software or modified copies of the Software. |
||||
|
# |
||||
|
# 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE |
||||
|
# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. |
||||
|
# If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
@ -0,0 +1,43 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
|
||||
|
############################################################################## |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# Copyright (C) 2018-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
||||
|
# Author: LINTO C T(<https://www.cybrosys.com>) |
||||
|
# you can modify it under the terms of the GNU LESSER |
||||
|
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. |
||||
|
# |
||||
|
# It is forbidden to publish, distribute, sublicense, or sell copies |
||||
|
# of the Software or modified copies of the Software. |
||||
|
# |
||||
|
# 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE |
||||
|
# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. |
||||
|
# If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
{ |
||||
|
'name': 'Time Picker Field', |
||||
|
'version': '11.0.1.0.0', |
||||
|
'summary': 'Time Picker Using Wickedpicker', |
||||
|
'category': 'Tools', |
||||
|
'author': 'Cybrosys Techno Solutions', |
||||
|
'company': 'Cybrosys Techno Solutions', |
||||
|
'maintainer': 'Cybrosys Techno Solutions', |
||||
|
'depends': ['base'], |
||||
|
'website': 'https://www.cybrosys.com/', |
||||
|
'data': [ |
||||
|
'views/templates.xml', |
||||
|
], |
||||
|
'qweb': ["static/src/xml/*.xml"], |
||||
|
'images': ['static/description/banner.jpg'], |
||||
|
'license': 'LGPL-3', |
||||
|
'installable': True, |
||||
|
'auto_install': False, |
||||
|
'application': False, |
||||
|
} |
After Width: | Height: | Size: 70 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 14 KiB |
@ -0,0 +1,82 @@ |
|||||
|
<section class="oe_container"> |
||||
|
<div class="oe_row oe_spaced"> |
||||
|
<h2 class="oe_slogan">Time Picker Field</h2> |
||||
|
<h3 class="oe_slogan">Time Picker Widget For Fields</h3> |
||||
|
<h4 class="oe_slogan"><a href="https://www.cybrosys.com">Cybrosys Technologies</a> </h4> |
||||
|
</div> |
||||
|
<div class="oe_row oe_spaced" style="padding-left:65px;"> |
||||
|
<h4>Features:</h4> |
||||
|
<div> |
||||
|
<span style="color:green;"> ☑ </span> Time picker for character fields.<br/> |
||||
|
<span style="color:green;"> ☑ </span> Time picker in 24 hour format.<br/> |
||||
|
<br/> |
||||
|
</div> |
||||
|
</div> |
||||
|
</section> |
||||
|
|
||||
|
<section class="oe_container oe_dark"> |
||||
|
<div class="oe_row oe_spaced"> |
||||
|
<div class="oe_picture"> |
||||
|
<h3 class="oe_slogan">Overview</h3> |
||||
|
<p class="oe_mt32 text-justify" > |
||||
|
Time picker widget that can be used with character type fields in Odoo using the jQuery |
||||
|
plugin 'Wickedpicker'. |
||||
|
</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
</section> |
||||
|
|
||||
|
<section class="oe_container"> |
||||
|
<div class="oe_row oe_spaced"> |
||||
|
<div style="text-align: center"> |
||||
|
<p> |
||||
|
<h4>Configuration</h4> |
||||
|
<p> |
||||
|
</div> |
||||
|
<div class="oe_picture" style="text-align: center"> |
||||
|
<p class="oe_mt32 text-justify" > |
||||
|
After installation, go to the field definition in the view and add "widget='timepicker'". |
||||
|
<br /> |
||||
|
</div> |
||||
|
</div> |
||||
|
</section> |
||||
|
|
||||
|
<section class="oe_container oe_dark"> |
||||
|
<div class="oe_row oe_spaced"> |
||||
|
<div class="oe_picture" style="text-align: center"> |
||||
|
<p class="oe_mt32 text-justify" > |
||||
|
Once the widget is linked with the field, you will see a picker for time selection. |
||||
|
Note that the picker will be in 24 hours format. |
||||
|
</p> |
||||
|
<div class="oe_demo oe_picture oe_screenshot"> |
||||
|
<img style="width: 58%;border:10px solid white;" src="picker.png"> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</section> |
||||
|
|
||||
|
<section class="oe_container"> |
||||
|
<h2 class="oe_slogan" style="margin-top:20px;" >Need Any Help?</h2> |
||||
|
<div class="oe_slogan" style="margin-top:10px !important;"> |
||||
|
<div> |
||||
|
<a class="btn btn-primary btn-lg mt8" |
||||
|
style="color: #FFFFFF !important;border-radius: 0;" href="https://www.cybrosys.com"><i |
||||
|
class="fa fa-envelope"></i> Email </a> <a |
||||
|
class="btn btn-primary btn-lg mt8" style="color: #FFFFFF !important;border-radius: 0;" |
||||
|
href="https://www.cybrosys.com/contact/"><i |
||||
|
class="fa fa-phone"></i> Contact Us </a> <a |
||||
|
class="btn btn-primary btn-lg mt8" style="color: #FFFFFF !important;border-radius: 0;" |
||||
|
href="https://www.cybrosys.com/odoo-customization-and-installation/"><i |
||||
|
class="fa fa-check-square"></i> Request Customization </a> |
||||
|
</div> |
||||
|
<br> |
||||
|
<img src="cybro_logo.png" style="width: 190px; margin-bottom: 20px;" class="center-block"> |
||||
|
<div> |
||||
|
<a href="https://twitter.com/cybrosys" target="_blank"><i class="fa fa-2x fa-twitter" style="color:white;background: #00a0d1;width:35px;"></i></a></td> |
||||
|
<a href="https://www.linkedin.com/company/cybrosys-technologies-pvt-ltd" target="_blank"><i class="fa fa-2x fa-linkedin" style="color:white;background: #31a3d6;width:35px;padding-left: 3px;"></i></a></td> |
||||
|
<a href="https://www.facebook.com/cybrosystechnologies" target="_blank"><i class="fa fa-2x fa-facebook" style="color:white;background: #3b5998;width:35px;padding-left: 8px;"></i></a></td> |
||||
|
<a href="https://plus.google.com/106641282743045431892/about" target="_blank"><i class="fa fa-2x fa-google-plus" style="color:white;background: #c53c2c;width:35px;padding-left: 3px;"></i></a></td> |
||||
|
<a href="https://in.pinterest.com/cybrosys" target="_blank"><i class="fa fa-2x fa-pinterest" style="color:white;background: #ac0f18;width:35px;padding-left: 3px;"></i></a></td> |
||||
|
</div> |
||||
|
</div> |
||||
|
</section> |
After Width: | Height: | Size: 5.3 KiB |
@ -0,0 +1,140 @@ |
|||||
|
odoo.define('field_timepicker.timepicker', function(require) { |
||||
|
"use strict"; |
||||
|
|
||||
|
var field_registry = require('web.field_registry'); |
||||
|
var Field = field_registry.get('char'); |
||||
|
|
||||
|
var global_show_time = null; |
||||
|
|
||||
|
var FieldTimePicker = Field.extend({ |
||||
|
|
||||
|
template: 'FieldTimePicker', |
||||
|
widget_class: 'oe_form_field_time', |
||||
|
|
||||
|
_renderReadonly: function () { |
||||
|
var show_value = this._formatValue(this.value); |
||||
|
this.$el.text(show_value); |
||||
|
global_show_time = show_value; |
||||
|
}, |
||||
|
|
||||
|
_getValue: function () { |
||||
|
var $input = this.$el.find('input'); |
||||
|
return $input.val(); |
||||
|
}, |
||||
|
|
||||
|
_renderEdit: function () { |
||||
|
var $input = this.$el.find('input'); |
||||
|
var options = { |
||||
|
twentyFour: true, |
||||
|
title: 'Timepicker' |
||||
|
}; |
||||
|
if(global_show_time){ |
||||
|
options['now'] = global_show_time; |
||||
|
} |
||||
|
$input.wickedpicker(options); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
field_registry.add('timepicker', FieldTimePicker); |
||||
|
|
||||
|
return { |
||||
|
FieldTimePicker: FieldTimePicker |
||||
|
}; |
||||
|
|
||||
|
}); |
||||
|
|
||||
|
odoo.define('field_timepicker.time_picker_add_exception', function(require){ |
||||
|
"use_strict"; |
||||
|
|
||||
|
var BasicModel = require('web.BasicModel'); |
||||
|
|
||||
|
BasicModel.include({ |
||||
|
_applyChange: function (recordID, changes, options) { |
||||
|
var self = this; |
||||
|
var record = this.localData[recordID]; |
||||
|
var field; |
||||
|
var defs = []; |
||||
|
options = options || {}; |
||||
|
record._changes = record._changes || {}; |
||||
|
if (!options.doNotSetDirty) { |
||||
|
record._isDirty = true; |
||||
|
} |
||||
|
var initialData = {}; |
||||
|
this._visitChildren(record, function (elem) { |
||||
|
initialData[elem.id] = $.extend(true, {}, _.pick(elem, 'data', '_changes')); |
||||
|
}); |
||||
|
|
||||
|
// apply changes to local data
|
||||
|
for (var fieldName in changes) { |
||||
|
field = record.fields[fieldName]; |
||||
|
if (field.type === 'one2many' || field.type === 'many2many') { |
||||
|
defs.push(this._applyX2ManyChange(record, fieldName, changes[fieldName], options.viewType)); |
||||
|
} else if (field.type === 'many2one' || field.type === 'reference') { |
||||
|
defs.push(this._applyX2OneChange(record, fieldName, changes[fieldName])); |
||||
|
} else { |
||||
|
record._changes[fieldName] = changes[fieldName]; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (options.notifyChange === false) { |
||||
|
return $.Deferred().resolve(_.keys(changes)); |
||||
|
} |
||||
|
|
||||
|
return $.when.apply($, defs).then(function () { |
||||
|
var onChangeFields = []; // the fields that have changed and that have an on_change
|
||||
|
for (var fieldName in changes) { |
||||
|
field = record.fields[fieldName]; |
||||
|
if (field.onChange) { |
||||
|
var isX2Many = field.type === 'one2many' || field.type === 'many2many'; |
||||
|
if (!isX2Many || (self._isX2ManyValid(record._changes[fieldName] || record.data[fieldName]))) { |
||||
|
onChangeFields.push(fieldName); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
var onchangeDef = $.Deferred(); |
||||
|
if (onChangeFields.length) { |
||||
|
self._performOnChange(record, onChangeFields, options.viewType) |
||||
|
.then(function (result) { |
||||
|
delete record._warning; |
||||
|
onchangeDef.resolve(_.keys(changes).concat(Object.keys(result && result.value || {}))); |
||||
|
}).fail(function () { |
||||
|
self._visitChildren(record, function (elem) { |
||||
|
_.extend(elem, initialData[elem.id]); |
||||
|
}); |
||||
|
onchangeDef.resolve({}); |
||||
|
}); |
||||
|
} else { |
||||
|
onchangeDef = $.Deferred().resolve(_.keys(changes)); |
||||
|
} |
||||
|
return onchangeDef.then(function (fieldNames) { |
||||
|
_.each(fieldNames, function (name) { |
||||
|
var excpet = {}; |
||||
|
if(record && record['fieldsInfo'] && record['fieldsInfo']['form'] && record['fieldsInfo']['form'][name]){ |
||||
|
var curr_el = record['fieldsInfo']['form'][name]; |
||||
|
if(curr_el['widget'] == 'timepicker'){ |
||||
|
excpet[name] = true; |
||||
|
} |
||||
|
} |
||||
|
if (record._changes && record._changes[name] === record.data[name]) { |
||||
|
delete record._changes[name]; |
||||
|
record._isDirty = !_.isEmpty(record._changes); |
||||
|
} |
||||
|
else if(record._changes && record._changes[name] != record.data[name]){ |
||||
|
if(excpet[name] && excpet[name] == true){ |
||||
|
//delete record._changes[name];
|
||||
|
fieldNames.splice( fieldNames.indexOf(name), 1 ); |
||||
|
record._isDirty = !_.isEmpty(fieldNames); |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
return self._fetchSpecialData(record).then(function (fieldNames2) { |
||||
|
// Return the names of the fields that changed (onchange or
|
||||
|
// associated special data change)
|
||||
|
return _.union(fieldNames, fieldNames2); |
||||
|
}); |
||||
|
}); |
||||
|
}); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
}); |
@ -0,0 +1,22 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<templates id="timepicker"> |
||||
|
<t t-name="FieldTimePicker"> |
||||
|
|
||||
|
<span t-if="widget.mode !== 'readonly'"> |
||||
|
<div class="input-group timepicker-component"> |
||||
|
<input type="text" |
||||
|
t-att-id="widget.id_for_label" |
||||
|
t-att-tabindex="widget.attrs.tabindex" |
||||
|
t-att-autofocus="widget.attrs.autofocus" |
||||
|
t-att-placeholder="widget.attrs.placeholder" |
||||
|
t-att-maxlength="widget.field.size" |
||||
|
class="timepickerg form-control" |
||||
|
/> |
||||
|
<span class="input-group-addon" style="display:none;"><i></i></span> |
||||
|
</div> |
||||
|
|
||||
|
</span> |
||||
|
<span t-if="widget.mode === 'readonly'"/> |
||||
|
|
||||
|
</t> |
||||
|
</templates> |
@ -0,0 +1,11 @@ |
|||||
|
.sass-cache |
||||
|
*.html |
||||
|
jquery-1.11.3.min.js |
||||
|
.idea |
||||
|
sass |
||||
|
jasmine |
||||
|
spec |
||||
|
node_modules |
||||
|
node_module/* |
||||
|
gulpfile.js |
||||
|
package.json |
@ -0,0 +1,21 @@ |
|||||
|
The MIT License |
||||
|
|
||||
|
Copyright (c) 2015-2016 Eric Gagnon http://ericjgagnon.github.io/wickedpicker/ |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), to deal |
||||
|
in the Software without restriction, including without limitation the rights |
||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
|
copies of the Software, and to permit persons to whom the Software is |
||||
|
furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included in |
||||
|
all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
||||
|
THE SOFTWARE. |
@ -0,0 +1,79 @@ |
|||||
|
# Wickedpicker |
||||
|
|
||||
|
## wickedpicker.js - A simple jQuery timepicker |
||||
|
|
||||
|
## Requirements |
||||
|
|
||||
|
* [jQuery](http://jquery.com/download/) (>= 1.9) |
||||
|
|
||||
|
## Installation |
||||
|
```shell |
||||
|
$ bower install wickedpicker |
||||
|
``` |
||||
|
|
||||
|
## Usage |
||||
|
|
||||
|
#### In your HTML |
||||
|
```html |
||||
|
<body> |
||||
|
.... |
||||
|
<input type="text" name="timepicker" class="timepicker"/> |
||||
|
.... |
||||
|
<script type="text/javascript" src="jquery-1.11.3.min.js"></script> |
||||
|
<script type="text/javascript" src="wickedpicker.js"></script> |
||||
|
</body> |
||||
|
``` |
||||
|
|
||||
|
#### In your JavaScript file |
||||
|
```javascript |
||||
|
$('.timepicker').wickedpicker(); |
||||
|
``` |
||||
|
|
||||
|
#### Options |
||||
|
```javascript |
||||
|
var options = { |
||||
|
now: "12:35", //hh:mm 24 hour format only, defaults to current time |
||||
|
twentyFour: false, //Display 24 hour format, defaults to false |
||||
|
upArrow: 'wickedpicker__controls__control-up', //The up arrow class selector to use, for custom CSS |
||||
|
downArrow: 'wickedpicker__controls__control-down', //The down arrow class selector to use, for custom CSS |
||||
|
close: 'wickedpicker__close', //The close class selector to use, for custom CSS |
||||
|
hoverState: 'hover-state', //The hover state class to use, for custom CSS |
||||
|
title: 'Timepicker', //The Wickedpicker's title, |
||||
|
showSeconds: false, //Whether or not to show seconds, |
||||
|
timeSeparator: ' : ', // The string to put in between hours and minutes (and seconds) |
||||
|
secondsInterval: 1, //Change interval for seconds, defaults to 1, |
||||
|
minutesInterval: 1, //Change interval for minutes, defaults to 1 |
||||
|
beforeShow: null, //A function to be called before the Wickedpicker is shown |
||||
|
afterShow: null, //A function to be called after the Wickedpicker is closed/hidden |
||||
|
show: null, //A function to be called when the Wickedpicker is shown |
||||
|
clearable: false, //Make the picker's input clearable (has clickable "x") |
||||
|
}; |
||||
|
$('.timepicker').wickedpicker(options); |
||||
|
``` |
||||
|
|
||||
|
#### Methods |
||||
|
|
||||
|
'time' get the current time inside of the input element that has a wickedpicker attached to it. |
||||
|
```javascript |
||||
|
$('.timepicker').wickedpicker('time'); |
||||
|
``` |
||||
|
|
||||
|
If multiple input fields have the same class and instantiate a wickedpicker then pass the index of the timepicker |
||||
|
you'd like to select |
||||
|
```javascript |
||||
|
$('.timepicker').wickedpicker('time', 0); |
||||
|
``` |
||||
|
|
||||
|
#### Functionality |
||||
|
The Wickedpicker opens when the bound input is clicked, or focused on (try tabbing), and it can be closed by either |
||||
|
clicking the X, by clicking outside of it, or by pressing esc. The arrows icons increase or decrease their |
||||
|
associated time values or toggle the meridiem. The values can also be changed using the up and down keys when |
||||
|
focused on. To move to the next value just press the left or right arrow key. |
||||
|
|
||||
|
For more checkout |
||||
|
[Wickedpicker gh-pages](http://ericjgagnon.github.io/wickedpicker/) |
||||
|
|
||||
|
## License |
||||
|
|
||||
|
Copyright (c) 2015-2016 Eric Gagnon Licensed under the MIT license. |
||||
|
|
@ -0,0 +1,29 @@ |
|||||
|
{ |
||||
|
"name": "wickedpicker", |
||||
|
"version": "0.0.4", |
||||
|
"description": "A simple jQuery timepicker plugin.", |
||||
|
"main": [ |
||||
|
"./dist/wickedpicker.min.js", |
||||
|
"./dist/wickedpicker.min.css" |
||||
|
], |
||||
|
"authors": [ |
||||
|
"Eric Gagnon", |
||||
|
"Ruben Seyferth" |
||||
|
], |
||||
|
"moduleType": "globals", |
||||
|
"license": "MIT", |
||||
|
"keywords": [ |
||||
|
"jQuery", |
||||
|
"timepicker", |
||||
|
"wickedpicker" |
||||
|
], |
||||
|
"homepage": "http://ericjgagnon.github.io/wickedpicker/", |
||||
|
"repository": { |
||||
|
"type": "git", |
||||
|
"url": "git://github.com/ericjgagnon/wickedpicker.git" |
||||
|
}, |
||||
|
"dependencies": { |
||||
|
"jquery": ">= 1.9.0" |
||||
|
}, |
||||
|
"private": false |
||||
|
} |
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
Binary file not shown.
Binary file not shown.
@ -0,0 +1,624 @@ |
|||||
|
/** |
||||
|
* wickedpicker v0.4.1 - A simple jQuery timepicker. |
||||
|
* Copyright (c) 2015-2016 Eric Gagnon - http://github.com/wickedRidge/wickedpicker
|
||||
|
* License: MIT |
||||
|
*/ |
||||
|
|
||||
|
(function ($, window, document) { |
||||
|
|
||||
|
"use strict"; |
||||
|
|
||||
|
if (typeof String.prototype.endsWith != 'function') { |
||||
|
/* |
||||
|
* Checks if this string end ends with another string |
||||
|
* |
||||
|
* @param {string} the string to be checked |
||||
|
* |
||||
|
* @return {bool} |
||||
|
*/ |
||||
|
String.prototype.endsWith = function (string) { |
||||
|
return string.length > 0 && this.substring(this.length - string.length, this.length) === string; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* Returns if the user agent is mobile |
||||
|
* |
||||
|
* @return {bool} |
||||
|
*/ |
||||
|
var isMobile = function () { |
||||
|
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent); |
||||
|
}; |
||||
|
|
||||
|
var today = new Date(); |
||||
|
|
||||
|
var pluginName = "wickedpicker", |
||||
|
defaults = { |
||||
|
now: today.getHours() + ':' + today.getMinutes(), |
||||
|
twentyFour: false, |
||||
|
upArrow: 'wickedpicker__controls__control-up', |
||||
|
downArrow: 'wickedpicker__controls__control-down', |
||||
|
close: 'wickedpicker__close', |
||||
|
hoverState: 'hover-state', |
||||
|
title: 'Timepicker', |
||||
|
showSeconds: false, |
||||
|
timeSeparator: ' : ', |
||||
|
secondsInterval: 1, |
||||
|
minutesInterval: 1, |
||||
|
beforeShow: null, |
||||
|
afterShow: null, |
||||
|
show: null, |
||||
|
clearable: false, |
||||
|
closeOnClickOutside: true, |
||||
|
onClickOutside: function() {}, |
||||
|
}; |
||||
|
|
||||
|
/* |
||||
|
* @param {object} The input object the timepicker is attached to. |
||||
|
* @param {object} The object containing options |
||||
|
*/ |
||||
|
function Wickedpicker(element, options) { |
||||
|
this.element = $(element); |
||||
|
this.options = $.extend({}, defaults, options); |
||||
|
|
||||
|
this.element.addClass('hasWickedpicker'); |
||||
|
this.element.attr('onkeypress', 'return false;'); |
||||
|
this.element.attr('aria-showingpicker', 'false'); |
||||
|
this.createPicker(); |
||||
|
this.timepicker = $('.wickedpicker'); |
||||
|
this.up = $('.' + this.options.upArrow.split(/\s+/).join('.')); |
||||
|
this.down = $('.' + this.options.downArrow.split(/\s+/).join('.')); |
||||
|
this.separator = $('.wickedpicker__controls__control--separator'); |
||||
|
this.hoursElem = $('.wickedpicker__controls__control--hours'); |
||||
|
this.minutesElem = $('.wickedpicker__controls__control--minutes'); |
||||
|
this.secondsElem = $('.wickedpicker__controls__control--seconds'); |
||||
|
this.meridiemElem = $('.wickedpicker__controls__control--meridiem'); |
||||
|
this.close = $('.' + this.options.close.split(/\s+/).join('.')); |
||||
|
|
||||
|
//Create a new Date object based on the default or passing in now value
|
||||
|
var time = this.timeArrayFromString(this.options.now); |
||||
|
this.options.now = new Date(today.getFullYear(), today.getMonth(), today.getDate(), time[0], time[1], time[2]); |
||||
|
this.selectedHour = this.parseHours(this.options.now.getHours()); |
||||
|
this.selectedMin = this.parseSecMin(this.options.now.getMinutes()); |
||||
|
this.selectedSec = this.parseSecMin(this.options.now.getSeconds()); |
||||
|
this.selectedMeridiem = this.parseMeridiem(this.options.now.getHours()); |
||||
|
this.setHoverState(); |
||||
|
this.attach(element); |
||||
|
this.setText(element); |
||||
|
} |
||||
|
|
||||
|
$.extend(Wickedpicker.prototype, { |
||||
|
|
||||
|
/* |
||||
|
* Show given input's timepicker |
||||
|
* |
||||
|
* @param {object} The input being clicked |
||||
|
*/ |
||||
|
showPicker: function (element) { |
||||
|
//If there is a beforeShow function, then call it with the input calling the timepicker and the
|
||||
|
// timepicker itself
|
||||
|
if (typeof this.options.beforeShow === 'function') { |
||||
|
this.options.beforeShow(element, this.timepicker); |
||||
|
} |
||||
|
var timepickerPos = $(element).offset(); |
||||
|
|
||||
|
$(element).attr({'aria-showingpicker': 'true', 'tabindex': -1}); |
||||
|
this.setText(element); |
||||
|
this.showHideMeridiemControl(); |
||||
|
if (this.getText(element) !== this.getTime()) { |
||||
|
|
||||
|
// Check meridiem
|
||||
|
var text = this.getText(element); |
||||
|
var re = /\s[ap]m$/i; |
||||
|
var meridiem = re.test(text) ? text.substr(-2, 2) : null; |
||||
|
var inputTime = text.replace(re, '').split(this.options.timeSeparator); |
||||
|
var newTime = {}; |
||||
|
newTime.hours = inputTime[0]; |
||||
|
newTime.minutes = inputTime[1]; |
||||
|
newTime.meridiem = meridiem; |
||||
|
if (this.options.showSeconds) { |
||||
|
newTime.seconds = inputTime[2]; |
||||
|
} |
||||
|
this.setTime(newTime); |
||||
|
} |
||||
|
this.timepicker.css({ |
||||
|
'z-index': this.element.css('z-index') + 1, |
||||
|
position: 'absolute', |
||||
|
left: timepickerPos.left, |
||||
|
top: timepickerPos.top + $(element)[0].offsetHeight |
||||
|
}).show(); |
||||
|
//If there is a show function, then call it with the input calling the timepicker and the
|
||||
|
// timepicker itself
|
||||
|
if (typeof this.options.show === 'function') { |
||||
|
this.options.show(element, this.timepicker); |
||||
|
} |
||||
|
|
||||
|
this.handleTimeAdjustments(element); |
||||
|
}, |
||||
|
|
||||
|
/* |
||||
|
* Hides the timepicker that is currently shown if it is not part of the timepicker |
||||
|
* |
||||
|
* @param {Object} The DOM object being clicked on the page |
||||
|
* |
||||
|
* BeinnLora: added trigger function to call on closing/hiding timepicker. |
||||
|
*/ |
||||
|
hideTimepicker: function (element) { |
||||
|
this.timepicker.hide(); |
||||
|
if (typeof this.options.afterShow === 'function') { |
||||
|
this.options.afterShow(element, this.timepicker); |
||||
|
} |
||||
|
var pickerHidden = { |
||||
|
start: function () { |
||||
|
var setShowPickerFalse = $.Deferred(); |
||||
|
$('[aria-showingpicker="true"]').attr('aria-showingpicker', 'false'); |
||||
|
return setShowPickerFalse.promise(); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
function setTabIndex(index) { |
||||
|
setTimeout(function () { |
||||
|
$('[aria-showingpicker="false"]').attr('tabindex', index); |
||||
|
}, 400); |
||||
|
} |
||||
|
|
||||
|
pickerHidden.start().then(setTabIndex(0)); |
||||
|
}, |
||||
|
|
||||
|
/* |
||||
|
* Create a new timepicker. A single timepicker per page |
||||
|
*/ |
||||
|
createPicker: function () { |
||||
|
if ($('.wickedpicker').length === 0) { |
||||
|
var picker = '<div class="wickedpicker"><p class="wickedpicker__title">' + this.options.title + '<span class="wickedpicker__close"></span></p><ul class="wickedpicker__controls"><li class="wickedpicker__controls__control"><span class="' + this.options.upArrow + '"></span><span class="wickedpicker__controls__control--hours" tabindex="-1">00</span><span class="' + this.options.downArrow + '"></span></li><li class="wickedpicker__controls__control--separator"><span class="wickedpicker__controls__control--separator-inner">:</span></li><li class="wickedpicker__controls__control"><span class="' + this.options.upArrow + '"></span><span class="wickedpicker__controls__control--minutes" tabindex="-1">00</span><span class="' + this.options.downArrow + '"></span></li>'; |
||||
|
if (this.options.showSeconds) { |
||||
|
picker += '<li class="wickedpicker__controls__control--separator"><span class="wickedpicker__controls__control--separator-inner">:</span></li><li class="wickedpicker__controls__control"><span class="' + this.options.upArrow + '"></span><span class="wickedpicker__controls__control--seconds" tabindex="-1">00</span><span class="' + this.options.downArrow + '"></span> </li>'; |
||||
|
} |
||||
|
picker += '<li class="wickedpicker__controls__control"><span class="' + this.options.upArrow + '"></span><span class="wickedpicker__controls__control--meridiem" tabindex="-1">AM</span><span class="' + this.options.downArrow + '"></span></li></ul></div>'; |
||||
|
$('body').append(picker); |
||||
|
this.attachKeyboardEvents(); |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
/* |
||||
|
* Hides the meridiem control if this timepicker is a 24 hour clock |
||||
|
*/ |
||||
|
showHideMeridiemControl: function () { |
||||
|
if (this.options.twentyFour === false) { |
||||
|
$(this.meridiemElem).parent().show(); |
||||
|
} |
||||
|
else { |
||||
|
$(this.meridiemElem).parent().hide(); |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
/* |
||||
|
* Hides the seconds control if this timepicker has showSeconds set to true |
||||
|
*/ |
||||
|
showHideSecondsControl: function () { |
||||
|
if (this.options.showSeconds) { |
||||
|
$(this.secondsElem).parent().show(); |
||||
|
} |
||||
|
else { |
||||
|
$(this.secondsElem).parent().hide(); |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
/* |
||||
|
* Bind the click events to the input |
||||
|
* |
||||
|
* @param {object} The input element |
||||
|
*/ |
||||
|
attach: function (element) { |
||||
|
var self = this; |
||||
|
|
||||
|
if (this.options.clearable) { |
||||
|
self.makePickerInputClearable(element); |
||||
|
} |
||||
|
|
||||
|
$(element).attr('tabindex', 0); |
||||
|
$(element).on('click focus', function (event) { |
||||
|
//Prevent multiple firings
|
||||
|
if ($(self.timepicker).is(':hidden')) { |
||||
|
self.showPicker($(this)); |
||||
|
window.lastTimePickerControl = $(this); //Put the reference on this timepicker into global scope for unsing that in afterShow function
|
||||
|
$(self.hoursElem).focus(); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
|
||||
|
//Handle click events for closing Wickedpicker
|
||||
|
var clickHandler = function (event) { //TODO: Fix double firing
|
||||
|
//Only fire the hide event when you have to
|
||||
|
if ($(self.timepicker).is(':visible')) { |
||||
|
//Clicking the X
|
||||
|
if ($(event.target).is(self.close)) { |
||||
|
self.hideTimepicker(window.lastTimePickerControl); |
||||
|
} else if ($(event.target).closest(self.timepicker).length || $(event.target).closest($('.hasWickedpicker')).length) { //Clicking the Wickedpicker or one of it's inputs
|
||||
|
event.stopPropagation(); |
||||
|
} else { //Everything else
|
||||
|
if (typeof self.options.onClickOutside === 'function') { |
||||
|
self.options.onClickOutside(); |
||||
|
} |
||||
|
else { |
||||
|
console.warn("Type of onClickOutside must be a function"); |
||||
|
} |
||||
|
|
||||
|
if (!self.options.closeOnClickOutside) { |
||||
|
return; |
||||
|
} |
||||
|
self.hideTimepicker(window.lastTimePickerControl); |
||||
|
} |
||||
|
window.lastTimePickerControl = null; |
||||
|
} |
||||
|
}; |
||||
|
$(document).off('click', clickHandler).on('click', clickHandler); |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* Added keyboard functionality to improve usabil |
||||
|
*/ |
||||
|
attachKeyboardEvents: function () { |
||||
|
$(document).on('keydown', $.proxy(function (event) { |
||||
|
switch (event.keyCode) { |
||||
|
case 9: |
||||
|
if (event.target.className !== 'hasWickedpicker') { |
||||
|
$(this.close).trigger('click'); |
||||
|
} |
||||
|
break; |
||||
|
case 27: |
||||
|
$(this.close).trigger('click'); |
||||
|
break; |
||||
|
case 37: //Left arrow
|
||||
|
if (event.target.className !== this.hoursElem[0].className) { |
||||
|
$(event.target).parent().prevAll('li').not(this.separator.selector).first().children()[1].focus(); |
||||
|
} else { |
||||
|
$(event.target).parent().siblings(':last').children()[1].focus(); |
||||
|
} |
||||
|
break; |
||||
|
case 39: //Right arrow
|
||||
|
if (event.target.className !== this.meridiemElem[0].className) { |
||||
|
$(event.target).parent().nextAll('li').not(this.separator.selector).first().children()[1].focus(); |
||||
|
} else { |
||||
|
$(event.target).parent().siblings(':first').children()[1].focus(); |
||||
|
} |
||||
|
break; |
||||
|
case 38: //Up arrow
|
||||
|
$(':focus').prev().trigger('click'); |
||||
|
break; |
||||
|
case 40: //Down arrow
|
||||
|
$(':focus').next().trigger('click'); |
||||
|
break; |
||||
|
default: |
||||
|
break; |
||||
|
} |
||||
|
}, this)); |
||||
|
}, |
||||
|
|
||||
|
/* |
||||
|
* Set the time on the timepicker |
||||
|
* |
||||
|
* @param {object} The date being set |
||||
|
*/ |
||||
|
setTime: function (time) { |
||||
|
this.setHours(time.hours); |
||||
|
this.setMinutes(time.minutes); |
||||
|
this.setMeridiem(time.meridiem); |
||||
|
if (this.options.showSeconds) { |
||||
|
this.setSeconds(time.seconds); |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
/* |
||||
|
* Get the time from the timepicker |
||||
|
*/ |
||||
|
getTime: function () { |
||||
|
return [this.formatTime(this.getHours(), this.getMinutes(), this.getMeridiem(), this.getSeconds())]; |
||||
|
}, |
||||
|
|
||||
|
/* |
||||
|
* Set the timpicker's hour(s) value |
||||
|
* |
||||
|
* @param {string} hours |
||||
|
*/ |
||||
|
setHours: function (hours) { |
||||
|
var hour = new Date(); |
||||
|
hour.setHours(hours); |
||||
|
var hoursText = this.parseHours(hour.getHours()); |
||||
|
this.hoursElem.text(hoursText); |
||||
|
this.selectedHour = hoursText; |
||||
|
}, |
||||
|
|
||||
|
/* |
||||
|
* Get the hour(s) value from the timepicker |
||||
|
* |
||||
|
* @return {integer} |
||||
|
*/ |
||||
|
getHours: function () { |
||||
|
var hours = new Date(); |
||||
|
hours.setHours(this.hoursElem.text()); |
||||
|
return hours.getHours(); |
||||
|
}, |
||||
|
|
||||
|
/* |
||||
|
* Returns the correct hour value based on the type of clock, 12 or 24 hour |
||||
|
* |
||||
|
* @param {integer} The hours value before parsing |
||||
|
* |
||||
|
* @return {string|integer} |
||||
|
*/ |
||||
|
parseHours: function (hours) { |
||||
|
return (this.options.twentyFour === false) ? ((hours + 11) % 12) + 1 : (hours < 10) ? '0' + hours : hours; |
||||
|
}, |
||||
|
|
||||
|
/* |
||||
|
* Sets the timpicker's minutes value |
||||
|
* |
||||
|
* @param {string} minutes |
||||
|
*/ |
||||
|
setMinutes: function (minutes) { |
||||
|
var minute = new Date(); |
||||
|
minute.setMinutes(minutes); |
||||
|
var minutesText = minute.getMinutes(); |
||||
|
var min = this.parseSecMin(minutesText); |
||||
|
this.minutesElem.text(min); |
||||
|
this.selectedMin = min; |
||||
|
}, |
||||
|
|
||||
|
/* |
||||
|
* Get the minutes value from the timepicker |
||||
|
* |
||||
|
* @return {integer} |
||||
|
*/ |
||||
|
getMinutes: function () { |
||||
|
var minutes = new Date(); |
||||
|
minutes.setMinutes(this.minutesElem.text()); |
||||
|
return minutes.getMinutes(); |
||||
|
}, |
||||
|
|
||||
|
|
||||
|
/* |
||||
|
* Return a human-readable minutes/seconds value |
||||
|
* |
||||
|
* @param {string} value seconds or minutes |
||||
|
* |
||||
|
* @return {string|integer} |
||||
|
*/ |
||||
|
parseSecMin: function (value) { |
||||
|
return ((value < 10) ? '0' : '') + value; |
||||
|
}, |
||||
|
|
||||
|
/* |
||||
|
* Set the timepicker's meridiem value, AM or PM |
||||
|
* |
||||
|
* @param {string} The new meridiem |
||||
|
*/ |
||||
|
setMeridiem: function (inputMeridiem) { |
||||
|
var newMeridiem = ''; |
||||
|
if (inputMeridiem === undefined) { |
||||
|
var meridiem = this.getMeridiem(); |
||||
|
newMeridiem = (meridiem === 'PM') ? 'AM' : 'PM'; |
||||
|
} else { |
||||
|
newMeridiem = inputMeridiem; |
||||
|
} |
||||
|
this.meridiemElem.text(newMeridiem); |
||||
|
this.selectedMeridiem = newMeridiem; |
||||
|
}, |
||||
|
|
||||
|
/* |
||||
|
* Get the timepicker's meridiem value, AM or PM |
||||
|
* |
||||
|
* @return {string} |
||||
|
*/ |
||||
|
getMeridiem: function () { |
||||
|
return this.meridiemElem.text(); |
||||
|
}, |
||||
|
|
||||
|
/* |
||||
|
* Set the timepicker's seconds value |
||||
|
* |
||||
|
* @param {string} seconds |
||||
|
*/ |
||||
|
setSeconds: function (seconds) { |
||||
|
var second = new Date(); |
||||
|
second.setSeconds(seconds); |
||||
|
var secondsText = second.getSeconds(); |
||||
|
var sec = this.parseSecMin(secondsText); |
||||
|
this.secondsElem.text(sec); |
||||
|
this.selectedSec = sec; |
||||
|
}, |
||||
|
|
||||
|
/* |
||||
|
* Get the timepicker's seconds value |
||||
|
* |
||||
|
* return {string} |
||||
|
*/ |
||||
|
getSeconds: function () { |
||||
|
var seconds = new Date(); |
||||
|
seconds.setSeconds(this.secondsElem.text()); |
||||
|
return seconds.getSeconds(); |
||||
|
}, |
||||
|
|
||||
|
/* |
||||
|
* Get the correct meridiem based on the hours given |
||||
|
* |
||||
|
* @param {string|integer} hours |
||||
|
* |
||||
|
* @return {string} |
||||
|
*/ |
||||
|
parseMeridiem: function (hours) { |
||||
|
return (hours > 11) ? 'PM' : 'AM'; |
||||
|
}, |
||||
|
|
||||
|
/* |
||||
|
* Handles time incrementing and decrementing and passes |
||||
|
* the operator, '+' or '-', the input to be set after the change |
||||
|
* and the current arrow clicked, to decipher if hours, ninutes, or meridiem. |
||||
|
* |
||||
|
* @param {object} The input element |
||||
|
*/ |
||||
|
handleTimeAdjustments: function (element) { |
||||
|
var timeOut = 0; |
||||
|
//Click and click and hold timepicker incrementer and decrementer
|
||||
|
$(this.up).add(this.down).off('mousedown click touchstart').on('mousedown click', { |
||||
|
'Wickedpicker': this, |
||||
|
'input': element |
||||
|
}, function (event) { |
||||
|
if(event.which!=1) return false; |
||||
|
var operator = (this.className.indexOf('up') > -1) ? '+' : '-'; |
||||
|
var passedData = event.data; |
||||
|
if (event.type == 'mousedown') { |
||||
|
timeOut = setInterval($.proxy(function (args) { |
||||
|
args.Wickedpicker.changeValue(operator, args.input, this); |
||||
|
}, this, {'Wickedpicker': passedData.Wickedpicker, 'input': passedData.input}), 200); |
||||
|
} else { |
||||
|
passedData.Wickedpicker.changeValue(operator, passedData.input, this); |
||||
|
} |
||||
|
}).bind('mouseup touchend', function () { |
||||
|
clearInterval(timeOut); |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
/* |
||||
|
* Change the timepicker's time base on what is clicked |
||||
|
* |
||||
|
* @param {string} The + or - operator |
||||
|
* @param {object} The timepicker's associated input to be set post change |
||||
|
* @param {object} The DOM arrow object clicked, determines if it is hours, |
||||
|
* minutes, or meridiem base on the operator and its siblings |
||||
|
*/ |
||||
|
changeValue: function (operator, input, clicked) { |
||||
|
var target = (operator === '+') ? clicked.nextSibling : clicked.previousSibling; |
||||
|
var targetClass = $(target).attr('class'); |
||||
|
if (targetClass.endsWith('hours')) { |
||||
|
this.setHours(eval(this.getHours() + operator + 1)); |
||||
|
} else if (targetClass.endsWith('minutes')) { |
||||
|
this.setMinutes(eval(this.getMinutes() + operator + this.options.minutesInterval)); |
||||
|
} else if (targetClass.endsWith('seconds')) { |
||||
|
this.setSeconds(eval(this.getSeconds() + operator + this.options.secondsInterval)); |
||||
|
} else { |
||||
|
this.setMeridiem(); |
||||
|
} |
||||
|
this.setText(input); |
||||
|
}, |
||||
|
|
||||
|
|
||||
|
/* |
||||
|
* Sets the give input's text to the current timepicker's time |
||||
|
* |
||||
|
* @param {object} The input element |
||||
|
*/ |
||||
|
setText: function (input) { |
||||
|
$(input).val(this.formatTime(this.selectedHour, this.selectedMin, this.selectedMeridiem, this.selectedSec)).change(); |
||||
|
}, |
||||
|
|
||||
|
/* |
||||
|
* Get the given input's value |
||||
|
* |
||||
|
* @param {object} The input element |
||||
|
* |
||||
|
* @return {string} |
||||
|
*/ |
||||
|
getText: function (input) { |
||||
|
return $(input).val(); |
||||
|
}, |
||||
|
|
||||
|
/* |
||||
|
* Returns the correct time format as a string |
||||
|
* |
||||
|
* @param {string} hour |
||||
|
* @param {string} minutes |
||||
|
* @param {string} meridiem |
||||
|
* |
||||
|
* @return {string} |
||||
|
*/ |
||||
|
formatTime: function (hour, min, meridiem, seconds) { |
||||
|
var formattedTime = hour + this.options.timeSeparator + min; |
||||
|
if (this.options.showSeconds) { |
||||
|
formattedTime += this.options.timeSeparator + seconds; |
||||
|
} |
||||
|
if (this.options.twentyFour === false) { |
||||
|
formattedTime += ' ' + meridiem; |
||||
|
} |
||||
|
return formattedTime; |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* Apply the hover class to the arrows and close icon fonts |
||||
|
*/ |
||||
|
setHoverState: function () { |
||||
|
var self = this; |
||||
|
if (!isMobile()) { |
||||
|
$(this.up).add(this.down).add(this.close).hover(function () { |
||||
|
$(this).toggleClass(self.options.hoverState); |
||||
|
}); |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* Wrapping the given input field with the clearable container |
||||
|
* , add a span that will contain the x, and bind the clear |
||||
|
* input event to the span |
||||
|
* |
||||
|
* @param input |
||||
|
*/ |
||||
|
makePickerInputClearable: function(input) { |
||||
|
$(input).wrap('<div class="clearable-picker"></div>').after('<span data-clear-picker>×</span>'); |
||||
|
|
||||
|
//When the x is clicked, clear its sibling input field
|
||||
|
$('[data-clear-picker]').on('click', function(event) { |
||||
|
$(this).siblings('.hasWickedpicker').val(''); |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* Convert the options time string format |
||||
|
* to an array |
||||
|
* |
||||
|
* returns => [hours, minutes, seconds] |
||||
|
* |
||||
|
* @param stringTime |
||||
|
* @returns {*} |
||||
|
*/ |
||||
|
timeArrayFromString: function (stringTime) { |
||||
|
if (stringTime.length) { |
||||
|
var time = stringTime.split(':'); |
||||
|
time[2] = (time.length < 3) ? '00' : time[2]; |
||||
|
return time; |
||||
|
} |
||||
|
return false; |
||||
|
}, |
||||
|
|
||||
|
//public functions
|
||||
|
/* |
||||
|
* Returns the requested input element's value |
||||
|
*/ |
||||
|
_time: function () { |
||||
|
var inputValue = $(this.element).val(); |
||||
|
return (inputValue === '') ? this.formatTime(this.selectedHour, this.selectedMin, this.selectedMeridiem, this.selectedSec) : inputValue; |
||||
|
}, |
||||
|
_hide: function() { |
||||
|
this.hideTimepicker(this.element); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
//optional index if multiple inputs share the same class
|
||||
|
$.fn[pluginName] = function (options, index) { |
||||
|
if (!$.isFunction(Wickedpicker.prototype['_' + options])) { |
||||
|
return this.each(function () { |
||||
|
if (!$.data(this, "plugin_" + pluginName)) { |
||||
|
$.data(this, "plugin_" + pluginName, new Wickedpicker(this, options)); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
else if ($(this).hasClass('hasWickedpicker')) { |
||||
|
if (index !== undefined) { |
||||
|
return $.data($(this)[index], 'plugin_' + pluginName)['_' + options](); |
||||
|
} |
||||
|
else { |
||||
|
return $.data($(this)[0], 'plugin_' + pluginName)['_' + options](); |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
})(jQuery, window, document); |
@ -0,0 +1,90 @@ |
|||||
|
.wickedpicker { |
||||
|
-webkit-user-select: none; |
||||
|
-moz-user-select: none; |
||||
|
-ms-user-select: none; |
||||
|
user-select: none; |
||||
|
box-shadow: 0 0 0 1px rgba(14, 41, 57, 0.12), 0 2px 5px rgba(14, 41, 57, 0.44), inset 0 -1px 2px rgba(14, 41, 57, 0.15); |
||||
|
background: #fefefe; |
||||
|
margin: 0 auto; |
||||
|
border-radius: 0.1px; |
||||
|
width: 270px; |
||||
|
height: 130px; |
||||
|
font-size: 14px; |
||||
|
display: none; } |
||||
|
.wickedpicker__title { |
||||
|
background-image: -webkit-linear-gradient(top, #ffffff 0%, #f2f2f2 100%); |
||||
|
background-image: linear-gradient(to bottom, #ffffff 0%, #f2f2f2 100%); |
||||
|
position: relative; |
||||
|
background: #f2f2f2; |
||||
|
margin: 0 auto; |
||||
|
border-bottom: 1px solid #e5e5e5; |
||||
|
padding: 12px 11px 10px 15px; |
||||
|
color: #4C4C4C; |
||||
|
font-size: inherit; } |
||||
|
.wickedpicker__close { |
||||
|
-webkit-transform: translateY(-25%); |
||||
|
-moz-transform: translateY(-25%); |
||||
|
-ms-transform: translateY(-25%); |
||||
|
-o-transform: translateY(-25%); |
||||
|
transform: translateY(-25%); |
||||
|
position: absolute; |
||||
|
top: 25%; |
||||
|
right: 10px; |
||||
|
color: #34495e; |
||||
|
cursor: pointer; } |
||||
|
.wickedpicker__close:before { |
||||
|
content: '\00d7'; } |
||||
|
.wickedpicker__controls { |
||||
|
padding: 10px 0; |
||||
|
line-height: normal; |
||||
|
margin: 0; } |
||||
|
.wickedpicker__controls__control, .wickedpicker__controls__control--separator { |
||||
|
vertical-align: middle; |
||||
|
display: inline-block; |
||||
|
font-size: inherit; |
||||
|
margin: 0 auto; |
||||
|
width: 35px; |
||||
|
letter-spacing: 1.3px; } |
||||
|
.wickedpicker__controls__control-up, .wickedpicker__controls__control-down { |
||||
|
color: #34495e; |
||||
|
position: relative; |
||||
|
display: block; |
||||
|
margin: 3px auto; |
||||
|
font-size: 18px; |
||||
|
cursor: pointer; } |
||||
|
.wickedpicker__controls__control-up:before { |
||||
|
content: '\e800'; } |
||||
|
.wickedpicker__controls__control-down:after { |
||||
|
content: '\e801'; } |
||||
|
.wickedpicker__controls__control--separator { |
||||
|
width: 5px; } |
||||
|
|
||||
|
.text-center, .wickedpicker__title, .wickedpicker__controls, .wickedpicker__controls__control, .wickedpicker__controls__control--separator, .wickedpicker__controls__control-up, .wickedpicker__controls__control-down { |
||||
|
text-align: center; } |
||||
|
|
||||
|
.hover-state { |
||||
|
color: #3498db; } |
||||
|
|
||||
|
@font-face { |
||||
|
font-family: 'fontello'; |
||||
|
src: url("../fonts/fontello.eot?52602240"); |
||||
|
src: url("../fonts/fontello.eot?52602240#iefix") format("embedded-opentype"), url("../fonts/fontello.woff?52602240") format("woff"), url("../fonts/fontello.ttf?52602240") format("truetype"), url("../fonts/fontello.svg?52602240#fontello") format("svg"); |
||||
|
font-weight: normal; |
||||
|
font-style: normal; } |
||||
|
|
||||
|
.fontello:before, .wickedpicker__controls__control-up:before, .fontello-after:after, .wickedpicker__controls__control-down:after { |
||||
|
font-family: 'fontello'; |
||||
|
font-style: normal; |
||||
|
font-weight: normal; |
||||
|
speak: none; |
||||
|
display: inline-block; |
||||
|
text-decoration: inherit; |
||||
|
width: 1em; |
||||
|
margin-right: .2em; |
||||
|
text-align: center; |
||||
|
font-variant: normal; |
||||
|
text-transform: none; |
||||
|
line-height: 1em; |
||||
|
margin-left: .2em; |
||||
|
-webkit-font-smoothing: antialiased; |
||||
|
-moz-osx-font-smoothing: grayscale; } |
@ -0,0 +1,11 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8" ?> |
||||
|
<odoo> |
||||
|
<template id="assets1" inherit_id="web.assets_backend"> |
||||
|
<xpath expr="." position="inside"> |
||||
|
<link href='/field_timepicker/static/wickedpicker/dist/wickedpicker.min.css' rel='stylesheet' /> |
||||
|
<script type="text/javascript" src='/field_timepicker/static/wickedpicker/dist/wickedpicker.min.js' /> |
||||
|
<script type="text/javascript" src='/field_timepicker/static/wickedpicker/src/wickedpicker.js' /> |
||||
|
<script type="text/javascript" src='/field_timepicker/static/src/js/time_widget.js' /> |
||||
|
</xpath> |
||||
|
</template> |
||||
|
</odoo> |
Loading…
Reference in new issue