From 3aec1a420b1607627ac302a039ab5b8968d9499c Mon Sep 17 00:00:00 2001 From: AsTex Date: Fri, 24 Feb 2017 03:56:26 +0300 Subject: [PATCH] Separate calendar from popup --- common.blocks/calendar/calendar.bemhtml.js | 15 +-- common.blocks/calendar/calendar.bh.js | 11 +- common.blocks/calendar/calendar.deps.js | 10 +- common.blocks/calendar/calendar.js | 115 ++++++------------ .../calendar.tmpl-specs/10-calendar.html | 2 +- .../input_has-calendar.bemhtml.js | 14 ++- .../_has-calendar/input_has-calendar.bh.js | 14 ++- .../_has-calendar/input_has-calendar.deps.js | 7 ++ .../input/_has-calendar/input_has-calendar.js | 111 ++++++++++++++--- desktop.bundles/index/index.bemjson.js | 10 ++ 10 files changed, 187 insertions(+), 122 deletions(-) diff --git a/common.blocks/calendar/calendar.bemhtml.js b/common.blocks/calendar/calendar.bemhtml.js index f53865b..5f6dcbd 100644 --- a/common.blocks/calendar/calendar.bemhtml.js +++ b/common.blocks/calendar/calendar.bemhtml.js @@ -1,10 +1,5 @@ -block('calendar').mix()(function() { - return { - block: 'popup', - mods: { - 'has-calendar': true, - target: 'anchor', - theme: this.mods.theme - } - }; -}); +block('calendar')( + js()(function() { + return { val: this.ctx.val }; + }) +); diff --git a/common.blocks/calendar/calendar.bh.js b/common.blocks/calendar/calendar.bh.js index 493757e..d49f828 100644 --- a/common.blocks/calendar/calendar.bh.js +++ b/common.blocks/calendar/calendar.bh.js @@ -1,14 +1,5 @@ module.exports = function(bh) { bh.match('calendar', function(ctx) { - var mods = ctx.mods(); - - ctx.mix({ - block: 'popup', - mods: { - 'has-calendar': true, - target: 'anchor', - theme: mods.theme - } - }); + ctx.js({ val: ctx.json().val }); }); }; diff --git a/common.blocks/calendar/calendar.deps.js b/common.blocks/calendar/calendar.deps.js index e4ef639..dd0d0d1 100644 --- a/common.blocks/calendar/calendar.deps.js +++ b/common.blocks/calendar/calendar.deps.js @@ -4,15 +4,9 @@ block: 'i-bem-dom' }, shouldDeps: [ + { block: 'jquery', elem: 'event', mods: { type: 'pointer' } }, { - elems: ['arrow', 'day', 'dayname'] - }, - { - block: 'popup', - mods: { - theme: 'islands', - target: 'anchor' - } + elem: ['arrow', 'day', 'dayname'] } ] }, diff --git a/common.blocks/calendar/calendar.js b/common.blocks/calendar/calendar.js index 58ebdc1..df16305 100644 --- a/common.blocks/calendar/calendar.js +++ b/common.blocks/calendar/calendar.js @@ -1,7 +1,7 @@ /** * @module calendar */ -modules.define('calendar', ['i-bem-dom', 'BEMHTML', 'jquery', 'popup'], function(provide, bemDom, BEMHTML, $, Popup) { +modules.define('calendar', ['i-bem-dom', 'BEMHTML', 'jquery'], function(provide, bemDom, BEMHTML, $) { function compareMonths(a, b) { return (a.getFullYear() - b.getFullYear()) * 100 + a.getMonth() - b.getMonth(); @@ -21,20 +21,22 @@ provide(bemDom.declBlock(this.name, /** @lends calendar.prototype */{ js: { inited: function() { this._val = null; + this._selectedDayElem = null; + this._firstDayIndex = -1; + var today = this._getToday(), + params = this.params; - this._popup = this.findMixedBlock(Popup); - - this._month = this._getToday(); + this._month = today; this._month.setDate(1); - this.setLimits( - this.params.earlierLimit, - this.params.laterLimit - ); - }, + this.setLimits(params.earlierLimit, params.laterLimit); + + this.setVal(this._isValidDate(params.val) ? params.val : today); + + if(!this._elem('container')) { + this._build(); + } - '': function() { - this._popup && bemDom.destruct(this._popup.domElem); } } }, @@ -58,47 +60,25 @@ provide(bemDom.declBlock(this.name, /** @lends calendar.prototype */{ var date = this.parseDate(val); this._val = this._isValidDate(date) ? date : null; - if(this._val) { + if(this._val) { + var shouldRebuild = this._month.getMonth() !== date.getMonth() || + this._month.getFullYear() !== date.getFullYear(); + this._month = new Date(this._val.getTime()); this._month.setDate(1); - } - - return this; - }, - - /** - * Show calendar - * - * @returns {calendar} this - */ - show: function() { - this._build(); - - this._popup.setMod('visible', true); - - return this; - }, - - /** - * Hide calendar - * - * @returns {calendar} this - */ - hide: function() { - this._popup.delMod('visible'); + if(!this._elem('container') || shouldRebuild) { + this._build(); + } else { + this._selectDayElem( + this._elems('day') + .get(this._firstDayIndex + this._val.getDate() - 1) + ); + } + } return this; }, - /** - * Is shown calendar? - * - * @returns {boolean} - */ - isShown: function() { - return this._popup.hasMod('visible'); - }, - /** * Switch month * @@ -140,30 +120,6 @@ provide(bemDom.declBlock(this.name, /** @lends calendar.prototype */{ return null; }, - /** - * Set target - * - * @param {jQuery|Function} anchor - DOM elem or anchor Bem block. - * @returns {calendar} this - */ - setAnchor: function(anchor) { - this._popup.setAnchor(anchor); - - return this; - }, - - /** - * Sets directions for calendar. - * - * @param {Array} directions - @see Popup.directions - * @returns {calendar} this - */ - setDirections: function(directions) { - this._popup.params.directions = directions; - - return this; - }, - /** * Sets limits * @@ -248,7 +204,6 @@ provide(bemDom.declBlock(this.name, /** @lends calendar.prototype */{ }, _build: function() { var rows = []; - rows.push(this._buildShortWeekdays()); rows = rows.concat(this._buildMonth(this._month)); @@ -270,8 +225,8 @@ provide(bemDom.declBlock(this.name, /** @lends calendar.prototype */{ } ] })); - - this._popup.setContent(calendar); + bemDom.update(this.domElem, calendar); + this._selectedDayElem = this.findChildElem({ elem: 'day', modName: 'state', modVal: 'current' }); }, _calcWeeks: function(month) { @@ -311,7 +266,6 @@ provide(bemDom.declBlock(this.name, /** @lends calendar.prototype */{ }, _buildMonth: function(month) { var rows = []; - this._calcWeeks(month).forEach(function(week) { var row = [], _this = this; @@ -332,6 +286,9 @@ provide(bemDom.declBlock(this.name, /** @lends calendar.prototype */{ if(day && !off) { dayElem.attrs['data-day'] = _this._formatDate(day); + if(_this._firstDayIndex === -1) { + _this._firstDayIndex = i; + } } if(weekend) { @@ -352,7 +309,6 @@ provide(bemDom.declBlock(this.name, /** @lends calendar.prototype */{ return rows; }, - _buildShortWeekdays: function() { var row = []; @@ -408,6 +364,7 @@ provide(bemDom.declBlock(this.name, /** @lends calendar.prototype */{ if(!arrow.hasMod('disabled')) { this.switchMonth(arrow.hasMod('direction', 'left') ? -1 : 1); } + }, _onDayClick: function(e) { @@ -415,13 +372,19 @@ provide(bemDom.declBlock(this.name, /** @lends calendar.prototype */{ if(!date) return; this.setVal(date); - this.hide(); var val = this.getVal(); this._emit('change', { value: val, formated: this._formatDate(val) }); + }, + _selectDayElem: function(element) { + if(this._selectedDayElem) { + this._selectedDayElem.delMod('state'); + } + element.setMod('state', 'current'); + this._selectedDayElem = element; } }, /** @lends calendar */ { lazyInit: false, diff --git a/common.blocks/calendar/calendar.tmpl-specs/10-calendar.html b/common.blocks/calendar/calendar.tmpl-specs/10-calendar.html index 500bb66..2f10f7a 100644 --- a/common.blocks/calendar/calendar.tmpl-specs/10-calendar.html +++ b/common.blocks/calendar/calendar.tmpl-specs/10-calendar.html @@ -1 +1 @@ - +
diff --git a/common.blocks/input/_has-calendar/input_has-calendar.bemhtml.js b/common.blocks/input/_has-calendar/input_has-calendar.bemhtml.js index 7fb21e6..a4b0d00 100644 --- a/common.blocks/input/_has-calendar/input_has-calendar.bemhtml.js +++ b/common.blocks/input/_has-calendar/input_has-calendar.bemhtml.js @@ -6,7 +6,8 @@ block('input').mod('has-calendar', true)( earlierLimit: ctx.earlierLimit, laterLimit: ctx.laterLimit, weekdays: ctx.weekdays, - months: ctx.months + months: ctx.months, + val: ctx.val } }); }), elem('box').content()(function() { @@ -16,6 +17,17 @@ block('input').mod('has-calendar', true)( { block: 'calendar', mods: { theme: this.mods.theme, format: this.mods['calendar-format'] }, + mix: [ + { + block: 'popup', + mods: + { + 'has-calendar': true, + theme: 'islands', + target: 'anchor' + } + } + ], js: this._calendar } ]; diff --git a/common.blocks/input/_has-calendar/input_has-calendar.bh.js b/common.blocks/input/_has-calendar/input_has-calendar.bh.js index ef98517..7841079 100644 --- a/common.blocks/input/_has-calendar/input_has-calendar.bh.js +++ b/common.blocks/input/_has-calendar/input_has-calendar.bh.js @@ -4,7 +4,8 @@ module.exports = function(bh) { earlierLimit: json.earlierLimit, laterLimit: json.laterLimit, weekdays: json.weekdays, - months: json.months + months: json.months, + val: json.val }); }); @@ -16,6 +17,17 @@ module.exports = function(bh) { { elem: 'calendar' }, { block: 'calendar', + mix: [ + { + block: 'popup', + mods: + { + 'has-calendar': true, + theme: 'islands', + target: 'anchor' + } + } + ], mods: { theme: ctx.node.mods.theme, format: ctx.node.mods && ctx.node.mods['calendar-format'] diff --git a/common.blocks/input/_has-calendar/input_has-calendar.deps.js b/common.blocks/input/_has-calendar/input_has-calendar.deps.js index 43ad06d..5592a48 100644 --- a/common.blocks/input/_has-calendar/input_has-calendar.deps.js +++ b/common.blocks/input/_has-calendar/input_has-calendar.deps.js @@ -3,6 +3,13 @@ { elems: 'calendar' }, + { + block: 'popup', + mods: { + theme: 'islands', + target: 'anchor' + } + }, 'ua', 'calendar' ] diff --git a/common.blocks/input/_has-calendar/input_has-calendar.js b/common.blocks/input/_has-calendar/input_has-calendar.js index 1e8493c..a80b03b 100644 --- a/common.blocks/input/_has-calendar/input_has-calendar.js +++ b/common.blocks/input/_has-calendar/input_has-calendar.js @@ -1,7 +1,7 @@ /** * @module input */ -modules.define('input', ['i-bem-dom', 'jquery', 'dom', 'calendar'], function(provide, bemDom, $, dom, Calendar, Input) { +modules.define('input', ['i-bem-dom', 'jquery', 'dom', 'calendar', 'popup'], function(provide, bemDom, $, dom, Calendar, Popup, Input) { /** * @exports @@ -15,18 +15,30 @@ provide(Input.declMod({ modName: 'has-calendar', modVal: true }, /** @lends inpu inited: function() { this.__base.apply(this, arguments); + this._popup = this.findChildBlock(Popup); + this.setAnchor(this.domElem); + this._calendar = this.findChildBlock(Calendar) - .setVal(this.getVal()) - .setAnchor(this.domElem); + .setVal(this.getVal()); + this._shouldShowCalendar = false; this._events(this._calendar).on('change', function(e, data) { - this.setVal(data.formated); + this._needShowCalendar = false; + + this + .setVal(data.formated) + .setMod('focused'); + this.hide(); }); this._domEvents(bemDom.doc).on('pointerdown', function(e) { var target = $(e.target), insideCalendar = dom.contains(this._calendar.domElem, target); + if(!insideCalendar && e.target !== this._elem('calendar').domElem[0]) { + this._needShowCalendar = true; + } + this._ignoreBlur = insideCalendar; }); }, @@ -39,11 +51,14 @@ provide(Input.declMod({ modName: 'has-calendar', modVal: true }, /** @lends inpu 'true': function() { this.__base.apply(this, arguments); - if(this._calendar.isShown()) return; + if(!this._needShowCalendar) { + this._needShowCalendar = true; + return; + } + + if(this.isShown()) return; - this._calendar - .setVal(this.getVal()) - .show(); + this.show(); }, '': function() { this.__base.apply(this, arguments); @@ -51,23 +66,89 @@ provide(Input.declMod({ modName: 'has-calendar', modVal: true }, /** @lends inpu if(this._ignoreBlur) { this._ignoreBlur = false; } else { - this._calendar.hide(); + this.hide(); } } } }, - onCalendarClick: function() { - if(this._calendar.isShown()) { - this._calendar.hide(); + _onPointerclick: function(e) { + this.__base.apply(this, arguments); + + if(this.hasMod('disabled') || this.isShown()) return; + + if(e.target === this._elem('calendar').domElem[0]) { + this._needShowCalendar = true; + return; + } + + this.show(); + }, + _onCalendarClick: function() { + if(this.isShown()) { + this.hide(); } else { this._calendar - .setVal(this.getVal()) - .show(); + .setVal(this.getVal()); + this.show(); } + }, + /** + * Is calendar shown? + * + * @returns {boolean} + */ + isShown: function() { + return this._popup.hasMod('visible'); + }, + + /** + * Set target + * + * @param {jQuery|Function} anchor - DOM elem or anchor Bem block. + * @returns {input} this + */ + setAnchor: function(anchor) { + this._popup.setAnchor(anchor); + return this; + }, + + /** + * Show calendar + * + * @returns {input} this + */ + show: function() { + this._calendar._build(); + this._popup.setMod('visible', true); + + return this; + }, + + /** + * Hide calendar + * + * @returns {input} this + */ + hide: function() { + this._popup.delMod('visible'); + + return this; + }, + + /** + * Sets directions for calendar. + * + * @param {Array} directions - @see Popup.directions + * @returns {input} this + */ + setDirections: function(directions) { + this._popup.params.directions = directions; + return this; } }, { onInit: function() { - this._domEvents('calendar').on('pointerclick', this.prototype.onCalendarClick); + this._domEvents().on('pointerclick', this.prototype._onPointerclick); + this._domEvents('calendar').on('pointerclick', this.prototype._onCalendarClick); this.__base.apply(this, arguments); } diff --git a/desktop.bundles/index/index.bemjson.js b/desktop.bundles/index/index.bemjson.js index a04748a..e0eb1dc 100644 --- a/desktop.bundles/index/index.bemjson.js +++ b/desktop.bundles/index/index.bemjson.js @@ -34,6 +34,16 @@ weekdays: ['пн', 'вт', 'ср', 'чт', 'пт', 'сб', 'вс'], months: ['Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'] }] + }, + { + block:'calendar', + mods:{ + theme:'islands' + }, + js:{ + weekdays: ['пн', 'вт', 'ср', 'чт', 'пт', 'сб', 'вс'], + months: ['Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'] + } } ] });