UNPKG

stf-angular-select

Version:

Custom reusable select for angular with wide posibilities

402 lines (401 loc) 19.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var Observable_1 = require("rxjs/Observable"); require("rxjs/add/operator/map"); require("rxjs/add/operator/throttleTime"); require("rxjs/add/operator/debounceTime"); require("rxjs/add/observable/fromEvent"); var _ = require("lodash"); var StfSelectDirective = (function () { function StfSelectDirective($translate, $window, $compile, _NP_STF_SELECT_THROTTLE_TIME) { this.$translate = $translate; this.$window = $window; this.$compile = $compile; this._NP_STF_SELECT_THROTTLE_TIME = _NP_STF_SELECT_THROTTLE_TIME; this._getScope = function () { return null; }; this.template = "\n<section class=\"stf-select\" ng-class=\"{'stf-select_has-value': ngModel? true : false, 'stf-select_focused': focused, 'stf-select_disabled': disabled || ngDisabled}\">\n <div class=\"stf-select__label\" ng-transclude=\"label\"></div>\n <section class=\"stf-select__container\" > \n <section class=\"stf-select__inner-wrapper\">\n <div class=\"stf-select__value\" ng-transclude=\"value\"></div>\n <div class=\"stf-select__placeholder\" ng-transclude=\"label\"></div>\n <div class=\"stf-select__icon\"></div>\n </section>\n\n <section class=\"stf-select__search-input\" tabindex=\"{{ngDisabled ? '-1' : '0'}}\" ng-transclude=\"searchInput\"></section>\n <section class=\"stf-select__options\">\n <div class=\"stf-select__fixed-option sss\"></div> \n </section>\n </section>\n</section>\n "; this.restrict = 'E'; this.require = "ngModel"; this.scope = { fixNgModal: "<", ngDisabled: "<", disabled: "<", optionsClass: "<" }; this.transclude = { label: 'stfSelectLabel', value: 'stfSelectValue', searchInput: '?stfSearchInput', }; } StfSelectDirective.prototype.link = function (scope, element, attributes, ngModelController, transcludeFn) { var _this = this; if (scope.fixNgModal) mdFixes(); element.addClass("stf-select-root"); var $mainContainer = $(window); var openScrollTimerId; var jqSelectOptions = element.find('.stf-select__options'); var placeHolder = element.find('.stf-select__placeholder'); var self = this; var elementChildren = element.children('.stf-select'); var valueClicked = false; render(); ngModelController.$render = render; scope.selectId = Math.round(Math.random() * 100000000000); element.attr('data-stf-select-id', scope.selectId); var $body = $('body'); var $searchInputContainer = element.find('.stf-select__search-input'); var elemetClickSubscription = Observable_1.Observable.fromEvent($searchInputContainer, 'click') .subscribe(function (event) { event.stopPropagation(); }); $searchInputContainer.delegate("input", "keydown", function (event) { var inputs = $searchInputContainer.find('input'); var keyCode = event.keyCode || event.which; if (inputs.length > 1) { if (event.target !== inputs[inputs.length - 1] && keyCode === 9) { event.stopPropagation(); } } }); var $searchInputContainerKeyDownSubscription = Observable_1.Observable.fromEvent($searchInputContainer, 'keydown') .subscribe(function (event) { var keyCode = event.keyCode || event.which; if (scope.focused) { switch (keyCode) { case 9: hideDropDown(); break; case 40: selectKeyDownPressed(); break; case 38: selectKeyUpPressed(); break; case 27: $searchInputContainer.focus(); hideDropDown(); event.preventDefault(); event.stopPropagation(); break; case 13: if (keyCode === 13) { event.stopPropagation(); var optionForClick = $("#stf-select-optins-" + scope.selectId + " .stf-select-option__selected"); if (!optionForClick.length) { optionForClick = $("#stf-select-optins-" + scope.selectId + " .stf-select-option").first(); } optionForClick.click(); return; } break; } } else { switch (keyCode) { case 13: showDropDown(); break; } } }); var $searchInputFocusSubscription = Observable_1.Observable.fromEvent($searchInputContainer, 'focus') .subscribe(function (event) { elementChildren.addClass('stf-select__tab-focus'); }); var $searchInputBlurSubscription = Observable_1.Observable.fromEvent($searchInputContainer, 'blur') .subscribe(function (event) { elementChildren.removeClass('stf-select__tab-focus'); }); var $searchInputKePressSubscription = Observable_1.Observable.fromEvent($searchInputContainer, 'click') .subscribe(function (event) { showDropDown(); }); var valueContainer = element.find('.stf-select__inner-wrapper'); var valueContainerObservable = Observable_1.Observable.fromEvent(valueContainer, 'click').throttleTime(this._NP_STF_SELECT_THROTTLE_TIME); var valueContainerSubscription = valueContainerObservable.subscribe(function (event) { if (!scope.disabled && !scope.ngDisabled) { scope.focused = true; scope.$apply(); } }); var iconEl = element.find('.stf-select__icon'); var iconElObservable = Observable_1.Observable.fromEvent(iconEl, 'click').throttleTime(this._NP_STF_SELECT_THROTTLE_TIME); var iconElSubscription = iconElObservable.subscribe(function (event) { if (scope.focused) { event.stopPropagation(); scope.focused = false; scope.$apply(); } }); var windowClickObservable = Observable_1.Observable.fromEvent(this.$window, 'click').throttleTime(100); var windowClickSubscription = windowClickObservable.subscribe(function (event) { if (!$(event.target).closest("[data-stf-select-id=" + scope.selectId + "]").length) { scope.focused = false; scope.$applyAsync(); } }); var windowResizeObservable = Observable_1.Observable.fromEvent(this.$window, 'resize').throttleTime(100); var windowResizeSubscription = windowResizeObservable.subscribe(function (event) { return calculatePositionAnsSize(); }); var scrollListener = _.debounce(function () { calculatePositionAnsSize(); }, 100); document.addEventListener('scroll', scrollListener, true); var elementMouseWheelObservable = Observable_1.Observable.fromEvent(element, "mousewheel"); var elementMouseWheelSubscription = elementMouseWheelObservable.subscribe(function (event) { if (scope.focused) { event.stopPropagation(); event.returnValue = false; } }); var stfSelectOption = element.find('.stf-select-option'); scope.$on('stf-select-option.selected', function (event, value) { var old = ngModelController.$viewValue; scope.focused = false; if (old !== value) { ngModelController.$setViewValue(value); scope.ngModel = value; scope.$broadcast('stf-select.value_changed', value); } setTimeout(function () { return $searchInputContainer.focus(); }, 100); }); scope.$watch('focused', function (newValue, oldValue) { if (scope.focused) { if (element.find('.stf-select__search-input input').length) { setTimeout(function () { return scope.focused && element.find('.stf-select__search-input input').first().focus(); }, 200); } else if ($searchInputContainer.length) { setTimeout(function () { return scope.focused && $searchInputContainer.first().focus(); }, 200); } scrollUnscrollContainers(); calculatePositionAnsSize(); } else { scrollUnscrollContainers(); } }); var options; var fixedOpt; var jOptins; var jOptinsParent; var transcludedScope; transcludeFn(function (transcludeEls, scopeTr) { _.each(transcludeEls, function (el) { if (el.tagName === "STF-SELECT-OPTIONS") { options = el; } if (el.tagName === "STF-FIXED-OPTION") { fixedOpt = el; } }); transcludedScope = scopeTr; $('body').append(_this.$compile("\n <div ng-attr-class=\"{{optionsClass}}\">\n <div ng-class=\"{'stf-select_has-value': ngModel? true : false, \n 'stf-select_focused': focused, 'stf-select_disabled': disabled || ngDisabled}\">\n <div class=\"stf-select__options\" id=\"stf-select-optins-" + scope.selectId + "\"></div>\n </div>\n </div>\n ")(scope)); jOptins = $("#stf-select-optins-" + scope.selectId); jOptins.append(options); jOptins.append('<div tabindex="0" class="stf-select__fixed-option"></div>'); jOptins.children('.stf-select__fixed-option').append(fixedOpt); jOptinsParent = jOptins.parent(); jOptins.delegate('.stf-select-option', "keydown", (function (event) { var _this = this; var keyCode = event.keyCode || event.which; switch (keyCode) { case 13: setTimeout(function () { return _this.click(); }, 100); break; case 9: event.preventDefault(); event.stopPropagation(); element.find('.stf-select__search-input').focus(); hideDropDown(); break; case 40: { optionKeyDown($(event.target)); event.preventDefault(); } break; case 38: { optionKeyUp($(event.target)); event.preventDefault(); } break; case 27: element.find('.stf-select__search-input').focus(); hideDropDown(); event.preventDefault(); event.stopPropagation(); break; } })); jOptins.find('.stf-select__fixed-option').keydown(function (event) { var keyCode = event.keyCode || event.which; switch (keyCode) { case 13: { jOptins.find('stf-fixed-option').click(); hideDropDown(); } break; case 38: fixedKeyUpPressed(); break; case 40: fixedKeyDownPressed(); break; case 9: hideDropDown(); break; case 27: hideDropDown(); event.preventDefault(); event.stopPropagation(); break; } }); }); scope.$on('$destroy', function () { valueContainerSubscription.unsubscribe(); windowClickSubscription.unsubscribe(); windowResizeSubscription.unsubscribe(); jOptinsParent.parent().remove(); elementMouseWheelSubscription.unsubscribe(); elemetClickSubscription.unsubscribe(); iconElSubscription.unsubscribe(); document.removeEventListener('scroll', scrollListener, true); $('body, .modal-content').css('overflow-y', ''); clearTimeout(openScrollTimerId); $searchInputFocusSubscription.unsubscribe(); $searchInputKePressSubscription.unsubscribe(); transcludedScope.$destroy(); }); function calculatePositionAnsSize() { if (!scope.focused) { return; } var elOffset = element.children().offset(); jOptinsParent.width(elementChildren.width()); jOptins.width(elementChildren.width()); console.log($mainContainer.scrollTop()); if ((jqSelectOptions.offset().top - $mainContainer.scrollTop() + jOptins.height() + 10) > (window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight)) { jOptinsParent.addClass('top'); jOptins.css('top', elOffset.top - jOptins.height() - 28); } else { jOptinsParent.removeClass('top'); jOptins.css('top', jqSelectOptions.offset().top); } jOptins.css('left', elOffset.left); } function mdFixes() { } function scrollUnscrollContainers() { if (scope.focused) { var jqContainer_1 = $('body, .modal-content'); jqContainer_1.css('overflow-y', 'hidden'); openScrollTimerId = setTimeout(function () { return jqContainer_1.css('overflow-y', 'hidden'); }, 200); } else { $('body, .modal-content').css('overflow-y', ''); } } element; function showDropDown() { if (!scope.disabled && !scope.ngDisabled) { valueClicked = true; scope.focused = true; scope.$apply(); } } function hideDropDown() { scope.focused = false; jOptinsParent.width(0); setTimeout(function () { scope.focused || scope.$applyAsync(); }, 0); } function selectKeyDownPressed() { var elementForFocus = jOptins.find('.stf-select-option').first(); if (!elementForFocus.length) { elementForFocus = jOptins.find('.stf-select__fixed-option'); } setTimeout(function () { return elementForFocus.focus(); }, 100); } function selectKeyUpPressed() { var elementForFocus = jOptins.find('.stf-select__fixed-option').last(); if (!elementForFocus.children().length) elementForFocus.length = 0; if (!elementForFocus.length) { elementForFocus = jOptins.find('.stf-select-option').last(); } setTimeout(function () { return elementForFocus.focus(); }, 100); } function fixedKeyUpPressed() { var elementForFocus = jOptins.find('.stf-select-option').last(); if (!elementForFocus.length) { elementForFocus = $searchInputContainer.find('input').length ? $searchInputContainer.find('input').first() : $searchInputContainer; } setTimeout(function () { return elementForFocus.focus(); }, 100); } function fixedKeyDownPressed() { var elementForFocus = $searchInputContainer.find('input').length ? $searchInputContainer.find('input').first() : jOptins.find('.stf-select-option').first(); setTimeout(function () { return elementForFocus.focus(); }, 100); } function optionKeyDown(element) { var elementParentFocus = element.parent().next(); var elementForFocus = elementParentFocus.children(); if (!elementForFocus.length) { elementParentFocus = elementParentFocus.next(); elementForFocus = elementParentFocus.children(); } if (!elementForFocus.length) { var fixed = jOptins.find('.stf-select__fixed-option'); if (fixed.children().length) elementForFocus = jOptins.find('.stf-select__fixed-option'); } if (!elementForFocus.length) { elementForFocus = $searchInputContainer.find('input').first(); } if (!elementForFocus.length) { elementForFocus = jOptins.find('.stf-select-option').first(); } elementForFocus.focus(); } function optionKeyUp(element) { var elementParentFocus = element.parent().prev(); var elementForFocus = elementParentFocus.children(); if (!elementForFocus.length) { elementParentFocus = elementParentFocus.prev(); elementForFocus = elementParentFocus.children(); } if (!elementForFocus.length) { elementForFocus = $searchInputContainer.find('input').first(); } if (!elementForFocus.length) { var fixed = jOptins.find('.stf-select__fixed-option'); if (fixed.children().length) elementForFocus = jOptins.find('.stf-select__fixed-option'); } if (!elementForFocus.length) { elementForFocus = jOptins.find('.stf-select-option').last(); } elementForFocus.focus(); } function render() { scope.ngModel = ngModelController.$viewValue; scope.$broadcast('stf-select.value_changed', scope.ngModel); return scope.ngModel; } }; StfSelectDirective.Factory = function ($translate, $window, $compile, NP_STF_SELECT_THROTTLE_TIME) { return new StfSelectDirective($translate, $window, $compile, NP_STF_SELECT_THROTTLE_TIME); }; return StfSelectDirective; }()); exports.StfSelectDirective = StfSelectDirective; StfSelectDirective.Factory.$inject = ['$translate', "$window", "$compile", "NP_STF_SELECT_THROTTLE_TIME"];