diff --git a/field_timepicker/README.rst b/field_timepicker/README.rst new file mode 100644 index 000000000..1ef7bde74 --- /dev/null +++ b/field_timepicker/README.rst @@ -0,0 +1,66 @@ +.. image:: https://img.shields.io/badge/licence-LGPL--3-blue.svg + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: LGPL-3 +================= +Field Time Picker +================= + +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. + +Company +------- +* `Cybrosys Techno Solutions `__ + +License +------- +General Public License, Version 3 (LGPL v3). +(https://www.odoo.com/documentation/user/13.0/legal/licenses/licenses.html) + +Known issues / Roadmap +====================== + +* ... + +Credits +------- +Developers: Version 13 - Mruthul @cybrosys, +Version 12 - Mruthul @cybrosys, + +Contact: odoo@cybrosys.com + + +Bug Tracker +=========== + +Contact odoo@cybrosys.com + + +Contributors +------------ + +* Mruthul Raj + +Contacts +-------- +* Mail Contact : odoo@cybrosys.com +* Website : https://cybrosys.com + + +Maintainer +========== +.. image:: https://cybrosys.com/images/logo.png + :target: https://cybrosys.com + +This module is maintained by Cybrosys Technologies. + +For support and more information, please visit `Our Website `__ + +Further information +=================== +HTML Description: ``__ \ No newline at end of file diff --git a/field_timepicker/__init__.py b/field_timepicker/__init__.py new file mode 100644 index 000000000..cf9b4fbf4 --- /dev/null +++ b/field_timepicker/__init__.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2023-TODAY Cybrosys Technologies(). +# Author: Mruthu () +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. + +# 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 . +# +############################################################################## diff --git a/field_timepicker/__manifest__.py b/field_timepicker/__manifest__.py new file mode 100644 index 000000000..338e9fdd4 --- /dev/null +++ b/field_timepicker/__manifest__.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2023-TODAY Cybrosys Technologies(). +# Author: Mruthu () +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. + +# 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 . +# +############################################################################## +{ + 'name': 'Field Time Picker', + 'version': '13.0.1.0.0', + 'summary': 'Time Picker Using Wickedpicker', + 'description': 'Time picker for the char fields', + 'category': 'Extra 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.png'], + 'license': 'LGPL-3', + 'installable': True, + 'auto_install': True, + 'application': False, +} diff --git a/field_timepicker/doc/RELEASE_NOTES.md b/field_timepicker/doc/RELEASE_NOTES.md new file mode 100644 index 000000000..5677ffc9d --- /dev/null +++ b/field_timepicker/doc/RELEASE_NOTES.md @@ -0,0 +1,6 @@ +## Module + +#### 11.05.2023 +#### Version 13.0.1.0.0 +#### ADD +Initial Commit Field Time Picker \ No newline at end of file diff --git a/field_timepicker/static/description/assets/icons/check.png b/field_timepicker/static/description/assets/icons/check.png new file mode 100644 index 000000000..c8e85f51d Binary files /dev/null and b/field_timepicker/static/description/assets/icons/check.png differ diff --git a/field_timepicker/static/description/assets/icons/chevron.png b/field_timepicker/static/description/assets/icons/chevron.png new file mode 100644 index 000000000..2089293d6 Binary files /dev/null and b/field_timepicker/static/description/assets/icons/chevron.png differ diff --git a/field_timepicker/static/description/assets/icons/cogs.png b/field_timepicker/static/description/assets/icons/cogs.png new file mode 100644 index 000000000..95d0bad62 Binary files /dev/null and b/field_timepicker/static/description/assets/icons/cogs.png differ diff --git a/field_timepicker/static/description/assets/icons/consultation.png b/field_timepicker/static/description/assets/icons/consultation.png new file mode 100644 index 000000000..8319d4baa Binary files /dev/null and b/field_timepicker/static/description/assets/icons/consultation.png differ diff --git a/field_timepicker/static/description/assets/icons/ecom-black.png b/field_timepicker/static/description/assets/icons/ecom-black.png new file mode 100644 index 000000000..a9385ff13 Binary files /dev/null and b/field_timepicker/static/description/assets/icons/ecom-black.png differ diff --git a/field_timepicker/static/description/assets/icons/education-black.png b/field_timepicker/static/description/assets/icons/education-black.png new file mode 100644 index 000000000..3eb09b27b Binary files /dev/null and b/field_timepicker/static/description/assets/icons/education-black.png differ diff --git a/field_timepicker/static/description/assets/icons/hotel-black.png b/field_timepicker/static/description/assets/icons/hotel-black.png new file mode 100644 index 000000000..130f613be Binary files /dev/null and b/field_timepicker/static/description/assets/icons/hotel-black.png differ diff --git a/field_timepicker/static/description/assets/icons/license.png b/field_timepicker/static/description/assets/icons/license.png new file mode 100644 index 000000000..a5869797e Binary files /dev/null and b/field_timepicker/static/description/assets/icons/license.png differ diff --git a/field_timepicker/static/description/assets/icons/lifebuoy.png b/field_timepicker/static/description/assets/icons/lifebuoy.png new file mode 100644 index 000000000..658d56ccc Binary files /dev/null and b/field_timepicker/static/description/assets/icons/lifebuoy.png differ diff --git a/field_timepicker/static/description/assets/icons/logo.png b/field_timepicker/static/description/assets/icons/logo.png new file mode 100644 index 000000000..478462d3e Binary files /dev/null and b/field_timepicker/static/description/assets/icons/logo.png differ diff --git a/field_timepicker/static/description/assets/icons/manufacturing-black.png b/field_timepicker/static/description/assets/icons/manufacturing-black.png new file mode 100644 index 000000000..697eb0e9f Binary files /dev/null and b/field_timepicker/static/description/assets/icons/manufacturing-black.png differ diff --git a/field_timepicker/static/description/assets/icons/pos-black.png b/field_timepicker/static/description/assets/icons/pos-black.png new file mode 100644 index 000000000..97c0f90c1 Binary files /dev/null and b/field_timepicker/static/description/assets/icons/pos-black.png differ diff --git a/field_timepicker/static/description/assets/icons/puzzle.png b/field_timepicker/static/description/assets/icons/puzzle.png new file mode 100644 index 000000000..65cf854e7 Binary files /dev/null and b/field_timepicker/static/description/assets/icons/puzzle.png differ diff --git a/field_timepicker/static/description/assets/icons/restaurant-black.png b/field_timepicker/static/description/assets/icons/restaurant-black.png new file mode 100644 index 000000000..4a35eb939 Binary files /dev/null and b/field_timepicker/static/description/assets/icons/restaurant-black.png differ diff --git a/field_timepicker/static/description/assets/icons/service-black.png b/field_timepicker/static/description/assets/icons/service-black.png new file mode 100644 index 000000000..301ab51cb Binary files /dev/null and b/field_timepicker/static/description/assets/icons/service-black.png differ diff --git a/field_timepicker/static/description/assets/icons/trading-black.png b/field_timepicker/static/description/assets/icons/trading-black.png new file mode 100644 index 000000000..9398ba2f1 Binary files /dev/null and b/field_timepicker/static/description/assets/icons/trading-black.png differ diff --git a/field_timepicker/static/description/assets/icons/training.png b/field_timepicker/static/description/assets/icons/training.png new file mode 100644 index 000000000..884ca024d Binary files /dev/null and b/field_timepicker/static/description/assets/icons/training.png differ diff --git a/field_timepicker/static/description/assets/icons/update.png b/field_timepicker/static/description/assets/icons/update.png new file mode 100644 index 000000000..ecbc5a01a Binary files /dev/null and b/field_timepicker/static/description/assets/icons/update.png differ diff --git a/field_timepicker/static/description/assets/icons/user.png b/field_timepicker/static/description/assets/icons/user.png new file mode 100644 index 000000000..6ffb23d9f Binary files /dev/null and b/field_timepicker/static/description/assets/icons/user.png differ diff --git a/field_timepicker/static/description/assets/icons/wrench.png b/field_timepicker/static/description/assets/icons/wrench.png new file mode 100644 index 000000000..6c04dea0f Binary files /dev/null and b/field_timepicker/static/description/assets/icons/wrench.png differ diff --git a/field_timepicker/static/description/assets/modules/1.png b/field_timepicker/static/description/assets/modules/1.png new file mode 100644 index 000000000..4a467ea22 Binary files /dev/null and b/field_timepicker/static/description/assets/modules/1.png differ diff --git a/field_timepicker/static/description/assets/modules/2.png b/field_timepicker/static/description/assets/modules/2.png new file mode 100644 index 000000000..3c430a7eb Binary files /dev/null and b/field_timepicker/static/description/assets/modules/2.png differ diff --git a/field_timepicker/static/description/assets/modules/3.png b/field_timepicker/static/description/assets/modules/3.png new file mode 100644 index 000000000..d1b689710 Binary files /dev/null and b/field_timepicker/static/description/assets/modules/3.png differ diff --git a/field_timepicker/static/description/assets/modules/4.png b/field_timepicker/static/description/assets/modules/4.png new file mode 100644 index 000000000..f2b224110 Binary files /dev/null and b/field_timepicker/static/description/assets/modules/4.png differ diff --git a/field_timepicker/static/description/assets/modules/5.png b/field_timepicker/static/description/assets/modules/5.png new file mode 100644 index 000000000..998679818 Binary files /dev/null and b/field_timepicker/static/description/assets/modules/5.png differ diff --git a/field_timepicker/static/description/assets/modules/6.png b/field_timepicker/static/description/assets/modules/6.png new file mode 100644 index 000000000..2c57cbb7b Binary files /dev/null and b/field_timepicker/static/description/assets/modules/6.png differ diff --git a/field_timepicker/static/description/assets/screenshots/hero.png b/field_timepicker/static/description/assets/screenshots/hero.png new file mode 100644 index 000000000..3a19ec583 Binary files /dev/null and b/field_timepicker/static/description/assets/screenshots/hero.png differ diff --git a/field_timepicker/static/description/assets/screenshots/screenshot-1.png b/field_timepicker/static/description/assets/screenshots/screenshot-1.png new file mode 100644 index 000000000..e37b6030a Binary files /dev/null and b/field_timepicker/static/description/assets/screenshots/screenshot-1.png differ diff --git a/field_timepicker/static/description/assets/screenshots/ss1.png b/field_timepicker/static/description/assets/screenshots/ss1.png new file mode 100644 index 000000000..1811278bd Binary files /dev/null and b/field_timepicker/static/description/assets/screenshots/ss1.png differ diff --git a/field_timepicker/static/description/banner.png b/field_timepicker/static/description/banner.png new file mode 100644 index 000000000..23134f8e4 Binary files /dev/null and b/field_timepicker/static/description/banner.png differ diff --git a/field_timepicker/static/description/cybro_logo.png b/field_timepicker/static/description/cybro_logo.png new file mode 100644 index 000000000..bb309114c Binary files /dev/null and b/field_timepicker/static/description/cybro_logo.png differ diff --git a/field_timepicker/static/description/icon.png b/field_timepicker/static/description/icon.png new file mode 100644 index 000000000..9996c4468 Binary files /dev/null and b/field_timepicker/static/description/icon.png differ diff --git a/field_timepicker/static/description/index.html b/field_timepicker/static/description/index.html new file mode 100644 index 000000000..8af868769 --- /dev/null +++ b/field_timepicker/static/description/index.html @@ -0,0 +1,618 @@ +
+
+
+
+ +
+
+
+ Community +
+
+ Enterprise +
+ +
+
+
+
+ +
+
+
+

+ Field Time Picker

+

+ Add Time Picker Widget That Can Be Used With Character Type + Fields In Odoo +

+ +
+
+ + + + +
+
+

+ Overview +

+
+ +
+

+ The module allows the user to add time picker widget that can be + used with character type fields in + Odoo + using the jQuery plugin 'Wickedpicker'. +

+ +
+
+ + +
+
+

+ Features +

+
+ +
+
+ +
+
+

+ + Time picker for character fields

+ +
+
+ +
+
+ +
+
+

+ + Time picker in 24 hour format

+ +
+
+ +
+ +
+
+

+ Screenshots +

+
+
+

+ Time Picker Widget

+

+ Just add widget='timepicker' to character field. +

+ +
+
+

+ Time Picker

+

+ You will get time picker like this. +

+ +
+
+ + +
+

+ Suggested Products

+
+ +
+ + + +
+
+
+

Our Services

+
+
+ +
+
+ +
+
+ Odoo + Customization
+
+ +
+
+ +
+
+ Odoo + Implementation
+
+ +
+
+ +
+
+ Odoo + Support
+
+ + +
+
+ +
+
+ Hire + Odoo + Developer
+
+ +
+
+ +
+
+ Odoo + Integration
+
+ +
+
+ +
+
+ Odoo + Migration
+
+ + +
+
+ +
+
+ Odoo + Consultancy
+
+ +
+
+ +
+
+ Odoo + Implementation
+
+ +
+
+ +
+
+ Odoo + Licensing Consultancy
+
+
+
+ + + +
+
+
+

Our Industries

+
+
+ +
+
+ +
+ Trading +
+

+ Easily procure + and + sell your products

+
+
+ +
+
+ +
+ POS +
+

+ Easy + configuration + and convivial experience

+
+
+ +
+
+ +
+ Education +
+

+ A platform for + educational management

+
+
+ +
+
+ +
+ Manufacturing +
+

+ Plan, track and + schedule your operations

+
+
+ +
+
+ +
+ E-commerce & Website +
+

+ Mobile + friendly, + awe-inspiring product pages

+
+
+ +
+
+ +
+ Service Management +
+

+ Keep track of + services and invoice

+
+
+ +
+
+ +
+ Restaurant +
+

+ Run your bar or + restaurant methodically

+
+
+ +
+
+ +
+ Hotel Management +
+

+ An + all-inclusive + hotel management application

+
+
+ +
+
+ + + + + +
+
+
+

Need Help?

+
+
+
+ + +
+ +
+ +
+ +
+ WhatsApp +
+
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+
+
+ + +
\ No newline at end of file diff --git a/field_timepicker/static/description/picker.png b/field_timepicker/static/description/picker.png new file mode 100644 index 000000000..4581d9b72 Binary files /dev/null and b/field_timepicker/static/description/picker.png differ diff --git a/field_timepicker/static/description/time-picker-cybrosys-1.png b/field_timepicker/static/description/time-picker-cybrosys-1.png new file mode 100644 index 000000000..e37b6030a Binary files /dev/null and b/field_timepicker/static/description/time-picker-cybrosys-1.png differ diff --git a/field_timepicker/static/src/js/time_widget.js b/field_timepicker/static/src/js/time_widget.js new file mode 100644 index 000000000..e57c8ff5f --- /dev/null +++ b/field_timepicker/static/src/js/time_widget.js @@ -0,0 +1,75 @@ +odoo.define('field_timepicker.timepicker', function(require) { + "use strict"; + + var field_registry = require('web.field_registry'); + var global_show_time = null; + var FieldChar = require('web.basic_fields').FieldChar; + var Dialog = require('web.Dialog'); + + /** + * Custom field for time selection. + */ + var FieldTimePicker = FieldChar.extend({ + template: 'FieldTimePicker', + widget_class: 'oe_form_field_time', + + /** + * Renders the field in read-only mode. + */ + _renderReadonly: function() { + var show_value = this._formatValue(this.value); + this.$el.text(show_value); + global_show_time = show_value; + }, + + /** + * Gets the current value of the field. + * + * @returns {string} The field value. + */ + _getValue: function() { + var $input = this.$el.find('input'); + return $input.val(); + }, + + /** + * Renders the field in edit mode. + */ + _renderEdit: function() { + var show_value = this._formatValue(this.value); + this.$el.find('input')[0].value=show_value; + var self = this; + this.$el.on('click', '.timepickerg', function() { + self._onClickTimePicker(); + }); + }, + _onClickTimePicker: function() { + /** + * Function to be executed when the "timepickerg" class is clicked. + * It renders the field as an editable timepicker widget if the formatType is "char". + */ + if (this.formatType === "char") { + var $input = this.$el.find('input'); + var options = { + twentyFour: true, + title: 'Timepicker', + showSeconds: true, + }; + if (global_show_time) { + options['now'] = global_show_time; + } + $input.wickedpicker(options); + } else { + Dialog.alert(this, "Timepicker widget only works with 'Char' field type"); + return false; + } + }, + }); + + // Register the FieldTimePicker in the field registry + field_registry.add('timepicker', FieldTimePicker); + + return { + FieldTimePicker: FieldTimePicker + }; +}); \ No newline at end of file diff --git a/field_timepicker/static/src/xml/timepicker.xml b/field_timepicker/static/src/xml/timepicker.xml new file mode 100644 index 000000000..c3da394fe --- /dev/null +++ b/field_timepicker/static/src/xml/timepicker.xml @@ -0,0 +1,20 @@ + + + + + +
+ + +
+
+ +
+
\ No newline at end of file diff --git a/field_timepicker/static/wickedpicker/.gitignore b/field_timepicker/static/wickedpicker/.gitignore new file mode 100644 index 000000000..4a42dee53 --- /dev/null +++ b/field_timepicker/static/wickedpicker/.gitignore @@ -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 diff --git a/field_timepicker/static/wickedpicker/LICENSE.md b/field_timepicker/static/wickedpicker/LICENSE.md new file mode 100644 index 000000000..fc1cc60fa --- /dev/null +++ b/field_timepicker/static/wickedpicker/LICENSE.md @@ -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. \ No newline at end of file diff --git a/field_timepicker/static/wickedpicker/README.md b/field_timepicker/static/wickedpicker/README.md new file mode 100644 index 000000000..8c84570e4 --- /dev/null +++ b/field_timepicker/static/wickedpicker/README.md @@ -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 + + .... + + .... + + + + ``` + +#### 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. + diff --git a/field_timepicker/static/wickedpicker/bower.json b/field_timepicker/static/wickedpicker/bower.json new file mode 100644 index 000000000..2f29eeea7 --- /dev/null +++ b/field_timepicker/static/wickedpicker/bower.json @@ -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 +} diff --git a/field_timepicker/static/wickedpicker/fonts/fontello.eot b/field_timepicker/static/wickedpicker/fonts/fontello.eot new file mode 100644 index 000000000..f9d3a8aea Binary files /dev/null and b/field_timepicker/static/wickedpicker/fonts/fontello.eot differ diff --git a/field_timepicker/static/wickedpicker/fonts/fontello.svg b/field_timepicker/static/wickedpicker/fonts/fontello.svg new file mode 100644 index 000000000..930a6cc3f --- /dev/null +++ b/field_timepicker/static/wickedpicker/fonts/fontello.svg @@ -0,0 +1,14 @@ + + + +Copyright (C) 2015 by original authors @ fontello.com + + + + + + + + + + \ No newline at end of file diff --git a/field_timepicker/static/wickedpicker/fonts/fontello.ttf b/field_timepicker/static/wickedpicker/fonts/fontello.ttf new file mode 100644 index 000000000..2877820b1 Binary files /dev/null and b/field_timepicker/static/wickedpicker/fonts/fontello.ttf differ diff --git a/field_timepicker/static/wickedpicker/fonts/fontello.woff b/field_timepicker/static/wickedpicker/fonts/fontello.woff new file mode 100644 index 000000000..35636f7f9 Binary files /dev/null and b/field_timepicker/static/wickedpicker/fonts/fontello.woff differ diff --git a/field_timepicker/static/wickedpicker/src/wickedpicker.js b/field_timepicker/static/wickedpicker/src/wickedpicker.js new file mode 100644 index 000000000..e0ee537fa --- /dev/null +++ b/field_timepicker/static/wickedpicker/src/wickedpicker.js @@ -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 = '

' + this.options.title + '

  • 00
  • :
  • 00
  • '; + if (this.options.showSeconds) { + picker += '
  • :
  • 00
  • '; + } + picker += '
  • AM
'; + $('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('
').after('×'); + + //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); diff --git a/field_timepicker/static/wickedpicker/stylesheets/wickedpicker.css b/field_timepicker/static/wickedpicker/stylesheets/wickedpicker.css new file mode 100644 index 000000000..d2a6ab27b --- /dev/null +++ b/field_timepicker/static/wickedpicker/stylesheets/wickedpicker.css @@ -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; } diff --git a/field_timepicker/views/templates.xml b/field_timepicker/views/templates.xml new file mode 100644 index 000000000..76374848f --- /dev/null +++ b/field_timepicker/views/templates.xml @@ -0,0 +1,11 @@ + + +