From 917fb81e64656ada897585dbd6da6523b19f9b59 Mon Sep 17 00:00:00 2001 From: Ladylain Date: Tue, 4 Oct 2022 12:43:08 +0200 Subject: [PATCH] First Commit --- Plugin.php | 76 +++ classes/ControlDesignTimeProvider.php | 9 + .../_control-yearpicker.htm | 3 + composer.json | 8 + formwidgets/YearPicker.php | 58 ++ .../yearpicker/assets/css/yearpicker.css | 105 ++++ .../yearpicker/assets/js/yearpicker.js | 512 ++++++++++++++++++ .../yearpicker/partials/_yearpicker.php | 31 ++ lang/en/lang.php | 7 + lang/fr/lang.php | 7 + updates/version.yaml | 1 + 11 files changed, 817 insertions(+) create mode 100644 Plugin.php create mode 100644 classes/ControlDesignTimeProvider.php create mode 100644 classes/controldesigntimeprovider/_control-yearpicker.htm create mode 100644 composer.json create mode 100644 formwidgets/YearPicker.php create mode 100644 formwidgets/yearpicker/assets/css/yearpicker.css create mode 100644 formwidgets/yearpicker/assets/js/yearpicker.js create mode 100644 formwidgets/yearpicker/partials/_yearpicker.php create mode 100644 lang/en/lang.php create mode 100644 lang/fr/lang.php create mode 100644 updates/version.yaml diff --git a/Plugin.php b/Plugin.php new file mode 100644 index 0000000..af4bae0 --- /dev/null +++ b/Plugin.php @@ -0,0 +1,76 @@ + 'YearPicker', + 'description' => 'Add a Year Picker form widget', + 'author' => 'LucasPalomba', + 'icon' => 'icon-leaf' + ]; + } + + /** + * Register method, called when the plugin is first registered. + * + * @return void + */ + public function register() + { + + } + + /** + * Boot method, called right before the request route. + * + * @return void + */ + public function boot() + { + + $properties = [ + 'minYear' => [ + 'title' => 'Min. Year', + 'type' => 'string' + ], + 'maxYear' => [ + 'title' => 'Max. Year', + 'type' => 'string' + + ], + ]; + + if(PluginManager::instance()->exists('RainLab.Builder')){ + Event::listen('pages.builder.registerControls', function($controlLibrary) use($properties) { + $controlLibrary->registerControl( + 'yearpicker', + 'Year Picker', + 'Sélecteur d\'année', + \RainLab\Builder\Classes\ControlLibrary::GROUP_WIDGETS, + 'icon-file-image-o', + $controlLibrary->getStandardProperties([], $properties), + 'LucasPalomba\YearPicker\Classes\ControlDesignTimeProvider' + ); + }); + } + } + public function registerFormWidgets() + { + return [ + \LucasPalomba\YearPicker\FormWidgets\YearPicker::class => 'yearpicker' + ]; + } +} diff --git a/classes/ControlDesignTimeProvider.php b/classes/ControlDesignTimeProvider.php new file mode 100644 index 0000000..317e6ce --- /dev/null +++ b/classes/ControlDesignTimeProvider.php @@ -0,0 +1,9 @@ +defaultControlsTypes[] = 'yearpicker'; + } +} \ No newline at end of file diff --git a/classes/controldesigntimeprovider/_control-yearpicker.htm b/classes/controldesigntimeprovider/_control-yearpicker.htm new file mode 100644 index 0000000..4b42708 --- /dev/null +++ b/classes/controldesigntimeprovider/_control-yearpicker.htm @@ -0,0 +1,3 @@ +
+ +
\ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..ec881aa --- /dev/null +++ b/composer.json @@ -0,0 +1,8 @@ +{ + "name": "lucaspalomba/yearpicker-plugin", + "type": "october-plugin", + "description": "No description provided yet...", + "require": { + "composer/installers": "~1.0" + } +} diff --git a/formwidgets/YearPicker.php b/formwidgets/YearPicker.php new file mode 100644 index 0000000..cacfad2 --- /dev/null +++ b/formwidgets/YearPicker.php @@ -0,0 +1,58 @@ +fillFromConfig([ + 'minYear', + 'maxYear', + ]); + } + + public function render(){ + $this->prepareVars(); + $this->addCss('css/yearpicker.css'); + $this->addJs('js/yearpicker.js'); + return $this->makePartial('yearpicker'); + } + + public function prepareVars(){ + $this->vars['name'] = $this->getFieldName(); + $this->vars['value'] = $this->getLoadValue(); + $this->vars['field'] = $this->formField; + $this->vars['minYear'] = $this->minYear; + $this->vars['maxYear'] = $this->maxYear; + } + + + /** + * @inheritDoc + */ + public function getSaveValue($value) + { + if (!strlen($value)) { + return null; + } + + return $value; + } +} \ No newline at end of file diff --git a/formwidgets/yearpicker/assets/css/yearpicker.css b/formwidgets/yearpicker/assets/css/yearpicker.css new file mode 100644 index 0000000..4d1576a --- /dev/null +++ b/formwidgets/yearpicker/assets/css/yearpicker.css @@ -0,0 +1,105 @@ +:root { + --background-color: #fff; + --border-color: #95a6a733; + --text-color: #555; + --selected-text-color: #6bc48d; + --hover-background-color: #eee; +} + +.yearpicker-container { + position: absolute; + color: var(--text-color); + border: 1px solid var(--border-color); + background-color: var(--background-color); + box-shadow: 0 0 32px rgb(67 86 100 / 20%);; + border-radius: 8px; + font-family: sans-serif; + font-size: 12px; + margin-top: 5px; + width: 310px; + z-index: 10100; +} + +.yearpicker-header { + display: flex; + width: 100%; + height: 2.5rem; + border-bottom: 1px solid var(--border-color); + align-items: center; + justify-content: space-between; + padding:0.25rem 1rem; +} + +.yearpicker-prev, +.yearpicker-next { + background-color: transparent; + background-position: 50%; + background-repeat: no-repeat; + background-size: 75% 75%; + border: 0; + cursor: pointer; + display: block; + height: 30px; + opacity: .5; + outline: none; + overflow: hidden; + padding: 0; + position: relative; + *position: absolute; + text-indent: 100%; + *top: 0; + white-space: nowrap; + width: 20px; +} + +.yearpicker-prev{ + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAeCAYAAAAsEj5rAAAAUklEQVR42u3VMQoAIBADQf8Pgj+OD9hG2CtONJB2ymQkKe0HbwAP0xucDiQWARITIDEBEnMgMQ8S8+AqBIl6kKgHiXqQqAeJepBo/z38J/U0uAHlaBkBl9I4GwAAAABJRU5ErkJggg==); +} +.yearpicker-next{ + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAeCAYAAAAsEj5rAAAAU0lEQVR42u3VOwoAMAgE0dwfAnNjU26bYkBCFGwfiL9VVWoO+BJ4Gf3gtsEKKoFBNTCoCAYVwaAiGNQGMUHMkjGbgjk2mIONuXo0nC8XnCf1JXgArVIZAQh5TKYAAAAASUVORK5CYII=); +} + +.yearpicker-prev:hover, +.yearpicker-next:hover { + opacity: 1; +} + +.yearpicker-current{ + line-height: 1; +} + +.yearpicker-year { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: center; + text-align: center; + padding: 0.5rem; +} + +.yearpicker-items { + list-style: none; + padding: 1rem 0.5rem; + flex: 0 0 33.3%; + width: 100%; +} + +.yearpicker-items:hover { + background-color: var(--hover-background-color); + color: var(--selected-text-color); + cursor: pointer; +} + +.yearpicker-items.selected { + background: var(--selected-text-color); + color:#fff; +} + +.hide { + display: none; +} + +.yearpicker-items.disabled { + pointer-events: none; + color: #bbb; +} \ No newline at end of file diff --git a/formwidgets/yearpicker/assets/js/yearpicker.js b/formwidgets/yearpicker/assets/js/yearpicker.js new file mode 100644 index 0000000..01bddb3 --- /dev/null +++ b/formwidgets/yearpicker/assets/js/yearpicker.js @@ -0,0 +1,512 @@ ++function ($) { "use strict"; +const version = '1.0.0'; +const appName = 'YearPicker'; + + +var defaults = { + // Auto Hide + autoHide: true, + // The Initial Date + year: null, + // Start Date + startYear: null, + // End Date + endYear: null, + // A element tag items + itemTag: 'li', + //css class selected date item + selectedClass: 'selected', + // css class disabled + disabledClass: 'disabled', + hideClass: 'hide', + highlightedClass: 'highlighted', + template: `
+
+
+
SelectedYear
+
+
+
+
    +
+
+
+`, + + // Event shortcuts + show: null, + hide: null, + pick: null +}; + +var window = typeof window !== 'undefained' ? window : {}; + +var event_click = 'click.'; +var event_focus = 'focus.'; +var event_keyup = 'keyup.'; +var event_selected = 'selected.'; +var event_show = 'show.'; +var event_hide = 'hide.'; + +var methods = { + // Show datepicker + showView: function showView() { + this.unbuild(); + if (!this.build) { + this.init(); + } + + if (this.show) { + return; + } + + if (this.trigger(event_show).isDefaultPrevented()) { + return; + } + this.show = true; + var $template = this.$template, + options = this.options; + + $template.removeClass(options.hideClass).on(event_click, $.proxy(this.click, this)); + $(document).on(event_click, this.onGlobalClick = proxy(this.globalClick, this)); + this.place(); + }, + + // Hide the datepicker + hideView: function hideView() { + if (!this.show) { + return; + } + + if (this.trigger(event_hide).isDefaultPrevented()) { + return; + } + + var $template = this.$template, + options = this.options; + + $template.addClass(options.hideClass).off(event_click,this.click); + $(document).off(event_click,this.onGlobalClick); + this.show = false; + }, + // toggle show and hide + toggle: function toggle() { + if (this.show) { + this.hideView(); + } else { + this.show(); + } + }, + setStartYear: function setStartYear(year) { + this.startYear = year; + + if (this.build) { + this.render(); + } + }, + setEndYear: function setEndYear(year) { + this.endYear = year; + if (this.build) { + this.render(); + } + } +}; + +var handlers = { + click: function click(e) { + var $target = $(e.target); + var options = this.options; + var viewYear = this.viewYear; + if ($target.hasClass('disabled')) { + return; + } + var view = $target.data('view') + switch (view) { + case 'yearpicker-prev': + var year = viewYear - 12; + this.viewYear = year; + this.renderYear(); + break; + case 'yearpicker-next': + var year = viewYear + 12; + this.viewYear = year; + this.renderYear(); + break; + case 'yearpicker-items': + this.year = parseInt($target.html()); + this.renderYear(); + this.hideView(); + break; + default: + break; + } + }, + globalClick: function globalClick(_ref) { + var target = _ref.target; + var element = this.element; + var hidden = true; + + if (target !== document) { + while (target === element || $(target).closest('.yearpicker-header').length === 1) { + hidden = false; + break; + } + + target = target.parentNode; + } + + if (hidden) { + this.hideView(); + } + } +} + +var render = { + renderYear: function renderYear() { + var options = this.options, + startYear = this.startYear, + endYear = this.endYear; + var disabledClass = options.disabledClass; + + // viewed year in the calenter + var viewYear = this.viewYear; + // selected year + var selectedYear = this.year; + var now = new Date(); + // current year + var thisYear = now.getFullYear(); + + var start = -5; + var end = 6; + var items = []; + var prevDisabled = false; + var nextDisabled = false; + var i = void 0; + + for (i = start; i <= end; i++) { + var year = viewYear + i; + var disabled = false; + + if (startYear) { + disabled = year < startYear; + if (i === start) { + prevDisabled = disabled; + } + } + + if (!disabled && endYear) { + disabled = year > endYear; + if (i === end) { + nextDisabled = disabled; + } + } + + // check for this is a selected year + var isSelectedYear = year === selectedYear; + var view = isSelectedYear ? 'yearpicker-items' : 'yearpicker-items'; + items.push(this.createItem({ + selected: isSelectedYear, + disabled: disabled, + text: viewYear + i, + view: disabled ? 'yearpicker-items disabled' : view, + highlighted: year === thisYear + })); + } + + this.yearsPrev.toggleClass(disabledClass, prevDisabled); + this.yearsNext.toggleClass(disabledClass, nextDisabled); + this.yearsCurrent.html(selectedYear); + this.yearsBody.html(items.join(' ')); + this.setValue(); + } +} + +function isString(value) { + return typeof value === 'string'; +} + +function isNumber(value) { + return typeof value === 'number' && value !== 'NaN'; +} + +function isUndefained(value) { + return typeof value === 'undefined'; +} + +function proxy(fn, context) { + + for (var len = arguments.length, args = Array(len > 2 ? len - 2 : 0), key = 2; key < len; key++) { + args[key - 2] = arguments[key]; + } + + return function () { + for (var len2 = arguments.length, args2 = Array(len2), key2 = 0; key2 < len2; key2++) { + args2[key2] = arguments[key2]; + } + + return fn.apply(context, args.concat(args2)); + } +} + +'use strict'; + +var _setupError = 'YearPicker Error'; +if (isUndefained(jQuery)) { + alert(`${appName} ${version} requires jQuery`); +} + +var classCheck = function (instance, constractor) { + if (!(instance instanceof constractor)) { + alert('cannot call a class as instance of function!!!'); + } +} + +var class_top_left = appName + '-top-left'; +var class_top_right = appName + '-top-right'; +var class_bottom_left = appName + '-bottom-left'; +var class_bottom_right = appName + '-bottom-right'; +var class_placements = [class_top_left, class_top_right, class_bottom_left, class_bottom_right].join(' '); + +var Yearpicker = function () { + function Yearpicker(element) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + classCheck(this, Yearpicker); + + this.$element = $(element); + this.element = element; + this.options = $.extend({}, defaults, options); + this.build = false; + this.show = false; + this.startYear = this.$element.data('min-year') || null; + this.endYear = this.$element.data('max-year') || null; + + this.create(); + } + + // yearpicker + Yearpicker.prototype = { + create: function () { + var $this = this.$element, + options = this.options; + var startYear = this.startYear, + endYear = this.endYear, + year = this.year; + + //this.trigger = $(options.trigger); + this.isInput = $this.is('input') || $this.is('textarea'); + this.initialValue = this.getValue(); + this.oldValue = this.initialValue; + year = year || this.initialValue || new Date().getFullYear(); + + if (startYear) { + if (year < startYear) { + year = startYear; + } + this.startYear = startYear; + } + + if (endYear) { + if (year > endYear) { + year = endYear; + } + this.endYear = endYear; + } + + this.year = year; + this.viewYear = year; + this.initialYear = year; + this.bind(); + this.init(); + }, + init: function () { + if (this.build) { + return; + } + this.build = true; + + var $this = this.$element, + options = this.options; + var $template = $(options.template); + this.$template = $template; + + this.yearsPrev = $template.find('.yearpicker-prev'); + this.yearsCurrent = $template.find('.yearpicker-current'); + this.yearsNext = $template.find('.yearpicker-next'); + this.yearsBody = $template.find('.yearpicker-year'); + + $template.addClass(options.hideClass); + $(document.body).append($template.addClass(appName + '-dropdown')); + this.renderYear(); + + }, + unbuild: function () { + if (!this.build) { + return; + } + this.build = false; + this.$template.remove(); + }, + // assign a events + bind: function () { + var $this = this.$element, + options = this.options; + + if ($.isFunction(options.show)) { + $this.on(event_show, options.show); + } + if ($.isFunction(options.hide)) { + $this.on(event_hide, options.hide); + } + if ($.isFunction(options.click)) { + $this.on(event_click, options.click); + } + if (this.isInput) { + $this.on(event_focus, $.proxy(this.showView, this)); + } else { + $this.on(event_click, $.proxy(this.showView, this)); + } + + }, + getValue: function () { + var $this = this.$element; + var value = this.isInput ? $this.val() : $this.text(); + value = parseInt(value); + return this.isInput ? parseInt($this.val()) : $this.text(); + }, + setValue: function () { + var $this = this.$element; + var value = this.year; + if (this.isInput) { + $this.val(value); + } else { + $this.html(value); + } + }, + trigger: function (type, data) { + var e = $.Event(type, data); + this.$element.trigger(e); + return e; + }, + place: function () { + + var $this = this.$element, + options = this.options, + $template = this.$template; + + var containerWidth = $(document).outerWidth(), + containerHeight = $(document).outerHeight(), + elementWidth = $this.outerWidth(), + elementHeight = $this.outerHeight(), + width = $template.width(), + height = $template.height(); + + var elementOffset = $this.offset(), + top = elementOffset.top, + left = elementOffset.left; + + var offset = parseFloat(options.offset); + var placements = class_top_left; + + offset = isNaN(offset) ? 10 : offset; + + // positioning the y axis + if (top > height && top + elementHeight + height > containerHeight) { + top -= height + offset; + placements = class_bottom_left; + } else { + top += elementHeight + offset; + } + + // positioning the x axis + if (left + width > containerWidth) { + left += elementWidth - width; + placements = placements.replace('left', 'right'); + } + + $template.removeClass(class_placements).addClass(placements).css({ + top: top, + left: left, + zIndex: parseInt(this.zIndex, 10) + }) + + }, + createItem: function (data) { + var options = this.options; + var itemTag = options.itemTag; + + var items = { + text: '', + view: '', + selected: false, + disabled: false, + highlighted: false + }; + + var classes = []; + $.extend(items, data); + if (items.selected) { + classes.push(options.selectedClass); + } + + if (items.disabled) { + classes.push(options.disabledClass); + } + + if (items.highlighted) { + classes.push(options.highlightedClass) + } + + return `<${itemTag} class="${items.view} ${classes.join(' ')}" data-view="${items.view}">${items.text}` + } + } + + return Yearpicker; +}(); + +if ($.extend) { + $.extend(Yearpicker.prototype, methods, render, handlers); +} + +if ($.fn) { + $.fn.yearpicker = function jQueryYearpicker(option) { + for (var len = arguments.length, args = Array(len > 1 ? len - 1 : 0), key = 1; key < len; key++) { + args[key - 1] = arguments[key]; + } + var result = void 0; + + this.each(function (i, element) { + var $element = $(element); + var isDestory = option === 'destroy'; + var yearpicker = $element.data(appName); + + if (!yearpicker) { + if (isDestory) { + return; + } + var options = $.extend({}, $element.data(), $.isPlainObject(option) && option); + yearpicker = new Yearpicker(element, options); + $element.data(appName, yearpicker); + } + if (isString(option)) { + var fn = yearpicker[option]; + + if ($.isFunction(fn)) { + result = fn.apply(yearpicker, args); + + if (isDestory) { + $element.removeData(appName); + } + } + } + }); + + return !isUndefained(result) ? result : this; + }; + $.fn.yearpicker.constractor = Yearpicker; +}; +$(document).render(function(){ + $('[data-yearpicker]').yearpicker(); +}) + +}(window.jQuery); diff --git a/formwidgets/yearpicker/partials/_yearpicker.php b/formwidgets/yearpicker/partials/_yearpicker.php new file mode 100644 index 0000000..ed0a539 --- /dev/null +++ b/formwidgets/yearpicker/partials/_yearpicker.php @@ -0,0 +1,31 @@ +previewMode): ?> +
+ + +
+ + +
+ + getAttributes() ?> + data-min-year="" + data-max-year="" + data-yearpicker /> +
+ + + +
+ + \ No newline at end of file diff --git a/lang/en/lang.php b/lang/en/lang.php new file mode 100644 index 0000000..4fcf2ca --- /dev/null +++ b/lang/en/lang.php @@ -0,0 +1,7 @@ + [ + 'placeholder' => 'Year picker' + ] +]; diff --git a/lang/fr/lang.php b/lang/fr/lang.php new file mode 100644 index 0000000..4fcf2ca --- /dev/null +++ b/lang/fr/lang.php @@ -0,0 +1,7 @@ + [ + 'placeholder' => 'Year picker' + ] +]; diff --git a/updates/version.yaml b/updates/version.yaml new file mode 100644 index 0000000..f9f4306 --- /dev/null +++ b/updates/version.yaml @@ -0,0 +1 @@ +1.0.1: First version of YearPicker