Guest User

Untitled

a guest
Aug 6th, 2017
670
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. (function () {
  2.     angular.module('app').factory('SelectFx', ["$http",
  3.     function ($http) {
  4.         function hasParent(e, p) {
  5.             if (!e)
  6.                 return false;
  7.             var el = e.target || e.srcElement || e || false;
  8.             while (el && el != p) {
  9.                 el = el.parentNode || false;
  10.             }
  11.             return (el !== false);
  12.         };
  13.  
  14.         /**
  15.          * extend obj function
  16.          */
  17.         function extend(a, b) {
  18.             for (var key in b) {
  19.                 if (b.hasOwnProperty(key)) {
  20.                     a[key] = b[key];
  21.                 }
  22.             }
  23.             return a;
  24.         }
  25.  
  26.         /**
  27.          * SelectFx function
  28.          */
  29.         function SelectFx(el, options) {
  30.             this.el = el[0];
  31.             this.options = extend({}, this.options);
  32.             extend(this.options, options);
  33.             this._init();
  34.         }
  35.  
  36.         function classReg(className) {
  37.             return new RegExp("(^|\\s+)" + className + "(\\s+|$)");
  38.         }
  39.  
  40.         // classList support for class management
  41.         // altho to be fair, the api sucks because it won't accept multiple classes at once
  42.         var hasClass, addClass, removeClass;
  43.  
  44.         if ('classList' in document.documentElement) {
  45.             hasClass = function (elem, c) {
  46.                 return elem.classList.contains(c);
  47.             };
  48.             addClass = function (elem, c) {
  49.                 elem.classList.add(c);
  50.             };
  51.             removeClass = function (elem, c) {
  52.                 elem.classList.remove(c);
  53.             };
  54.         } else {
  55.             hasClass = function (elem, c) {
  56.                 return classReg(c).test(elem.className);
  57.             };
  58.             addClass = function (elem, c) {
  59.                 if (!hasClass(elem, c)) {
  60.                     elem.className = elem.className + ' ' + c;
  61.                 }
  62.             };
  63.             removeClass = function (elem, c) {
  64.                 elem.className = elem.className.replace(classReg(c), ' ');
  65.             };
  66.         }
  67.  
  68.         function toggleClass(elem, c) {
  69.             var fn = hasClass(elem, c) ? removeClass : addClass;
  70.             fn(elem, c);
  71.         }
  72.  
  73.         var classie = {
  74.             // full names
  75.             hasClass: hasClass,
  76.             addClass: addClass,
  77.             removeClass: removeClass,
  78.             toggleClass: toggleClass,
  79.             // short names
  80.             has: hasClass,
  81.             add: addClass,
  82.             remove: removeClass,
  83.             toggle: toggleClass
  84.         };
  85.  
  86.         // transport
  87.         if (typeof define === 'function' && define.amd) {
  88.             // AMD
  89.             define(classie);
  90.         } else {
  91.             // browser global
  92.             window.classie = classie;
  93.         }
  94.  
  95.         /**
  96.          * SelectFx options
  97.          */
  98.         SelectFx.prototype.options = {
  99.             // if true all the links will open in a new tab.
  100.             // if we want to be redirected when we click an option, we need to define a data-link attr on the option of the native select element
  101.             newTab: true,
  102.             // when opening the select element, the default placeholder (if any) is shown
  103.             stickyPlaceholder: true,
  104.             // callback when changing the value
  105.             onChange: function (val) {
  106.                 return false;
  107.             }
  108.         };
  109.  
  110.         /**
  111.          * init function
  112.          * initialize and cache some vars
  113.          */
  114.         SelectFx.prototype._init = function () {
  115.  
  116.             var selectDisabled = false;
  117.             var createSelect = true;
  118.             if (this.el.hasAttribute("disabled")) {
  119.                 this.el.className = this.el.className + " disabled";
  120.                 selectDisabled = true;
  121.             };
  122.  
  123.             if (this._styleExist(this.el.previousSibling)) {
  124.                 createSelect = false;
  125.             }
  126.             // check if we are using a placeholder for the native select box
  127.             // we assume the placeholder is disabled and selected by default
  128.             var selectedOpt = this.el.querySelectorAll('option[selected]')[this.el.querySelectorAll('option[selected]').length - 1];
  129.  
  130.  
  131.             this.hasDefaultPlaceholder = selectedOpt && selectedOpt.disabled;
  132.  
  133.             // get selected option (either the first option with attr selected or just the first option)
  134.             this.selectedOpt = selectedOpt || this.el.querySelector('option');
  135.  
  136.             // create structure
  137.             this._createSelectEl();
  138.  
  139.             // all options
  140.             this.selOpts = [].slice.call(this.selEl.querySelectorAll('li[data-option]'));
  141.  
  142.             // total options
  143.             this.selOptsCount = this.selOpts.length;
  144.  
  145.             // current index
  146.             this.current = this.selOpts.indexOf(this.selEl.querySelector('li.cs-selected')) || -1;
  147.  
  148.             // placeholder elem
  149.             this.selPlaceholder = this.selEl.querySelector('span.cs-placeholder');
  150.  
  151.             if (!selectDisabled) {
  152.                 // init events
  153.                 this._initEvents(createSelect);
  154.             }
  155.  
  156.         };
  157.         /**
  158.          * creates the structure for the select element
  159.          */
  160.         SelectFx.prototype._createSelectEl = function () {
  161.  
  162.             var self = this, options = '', createOptionHTML = function (el) {
  163.                 var optclass = '', classes = '', link = '';
  164.  
  165.                 if (el.getAttribute('selected')) {
  166.  
  167.                     classes += 'cs-selected ';
  168.  
  169.                 }
  170.                 // extra classes
  171.                 if (el.getAttribute('data-class')) {
  172.                     classes += el.getAttribute('data-class');
  173.                 }
  174.                 // link options
  175.                 if (el.getAttribute('data-link')) {
  176.                     link = 'data-link=' + el.getAttribute('data-link');
  177.                 }
  178.  
  179.                 if (classes !== '') {
  180.                     optclass = 'class="' + classes + '" ';
  181.                 }
  182.  
  183.                 return '<li ' + optclass + link + ' data-option data-value="' + el.value + '"><span>' + el.textContent + '</span></li>';
  184.             };
  185.  
  186.             [].slice.call(this.el.children).forEach(function (el) {
  187.                 if (el.disabled) {
  188.                     return;
  189.                 }
  190.  
  191.                 var tag = el.tagName.toLowerCase();
  192.  
  193.                 if (tag === 'option') {
  194.                     options += createOptionHTML(el);
  195.                 } else if (tag === 'optgroup') {
  196.                     options += '<li class="cs-optgroup"><span>' + el.label + '</span><ul>';
  197.                     [].slice.call(el.children).forEach(function (opt) {
  198.                         options += createOptionHTML(opt);
  199.                     });
  200.                     options += '</ul></li>';
  201.                 }
  202.             });
  203.  
  204.             if (this._styleExist(this.el.previousSibling)) {
  205.                 this.selEl = this.el.parentNode;
  206.                 this.selEl.tabIndex = this.el.tabIndex;
  207.  
  208.                 this.el.previousSibling.innerHTML = '<ul>' + options + '</ul>';
  209.  
  210.                 return;
  211.             } else {
  212.  
  213.                 var opts_el = '<div class="cs-options"><ul>' + options + '</ul></div>';
  214.                 this.selEl = document.createElement('div');
  215.                 this.selEl.className = this.el.className;
  216.                 this.selEl.tabIndex = this.el.tabIndex;
  217.                 this.selEl.innerHTML = '<span class="cs-placeholder">' + this.selectedOpt.textContent + '</span>' + opts_el;
  218.                 this.el.parentNode.appendChild(this.selEl);
  219.                 this.selEl.appendChild(this.el);
  220.             }
  221.  
  222.         };
  223.         /**
  224.          * initialize the events
  225.          */
  226.         SelectFx.prototype._initEvents = function (a) {
  227.  
  228.             var self = this;
  229.             if (a) {
  230.                 // open/close select
  231.                 this.selPlaceholder.addEventListener('click', function () {
  232.                     self._toggleSelect();
  233.                 });
  234.             }
  235.             // clicking the options
  236.             this.selOpts.forEach(function (opt, idx) {
  237.                 opt.addEventListener('click', function () {
  238.                     self.current = idx;
  239.                     self._changeOption();
  240.                     // close select elem
  241.                     self._toggleSelect();
  242.                 });
  243.             });
  244.  
  245.             // close the select element if the target it´s not the select element or one of its descendants..
  246.             document.addEventListener('click', function (ev) {
  247.                 var target = ev.target;
  248.                 if (self._isOpen() && target !== self.selEl && !hasParent(target, self.selEl)) {
  249.                     self._toggleSelect();
  250.                 }
  251.             });
  252.  
  253.             // keyboard navigation events
  254.             this.selEl.addEventListener('keydown', function (ev) {
  255.                 var keyCode = ev.keyCode || ev.which;
  256.  
  257.                 switch (keyCode) {
  258.                     // up key
  259.                     case 38:
  260.                         ev.preventDefault();
  261.                         self._navigateOpts('prev');
  262.                         break;
  263.                         // down key
  264.                     case 40:
  265.                         ev.preventDefault();
  266.                         self._navigateOpts('next');
  267.                         break;
  268.                         // space key
  269.                     case 32:
  270.                         ev.preventDefault();
  271.                         if (self._isOpen() && typeof self.preSelCurrent != 'undefined' && self.preSelCurrent !== -1) {
  272.                             self._changeOption();
  273.                         }
  274.                         self._toggleSelect();
  275.                         break;
  276.                         // enter key
  277.                     case 13:
  278.                         ev.preventDefault();
  279.                         if (self._isOpen() && typeof self.preSelCurrent != 'undefined' && self.preSelCurrent !== -1) {
  280.                             self._changeOption();
  281.                             self._toggleSelect();
  282.                         }
  283.                         break;
  284.                         // esc key
  285.                     case 27:
  286.                         ev.preventDefault();
  287.                         if (self._isOpen()) {
  288.                             self._toggleSelect();
  289.                         }
  290.                         break;
  291.                 }
  292.             });
  293.         };
  294.         /**
  295.          * navigate with up/dpwn keys
  296.          */
  297.         SelectFx.prototype._navigateOpts = function (dir) {
  298.             if (!this._isOpen()) {
  299.                 this._toggleSelect();
  300.             }
  301.  
  302.             var tmpcurrent = typeof this.preSelCurrent != 'undefined' && this.preSelCurrent !== -1 ? this.preSelCurrent : this.current;
  303.  
  304.             if (dir === 'prev' && tmpcurrent > 0 || dir === 'next' && tmpcurrent < this.selOptsCount - 1) {
  305.                 // save pre selected current - if we click on option, or press enter, or press space this is going to be the index of the current option
  306.                 this.preSelCurrent = dir === 'next' ? tmpcurrent + 1 : tmpcurrent - 1;
  307.                 // remove focus class if any..
  308.                 this._removeFocus();
  309.                 // add class focus - track which option we are navigating
  310.                 classie.add(this.selOpts[this.preSelCurrent], 'cs-focus');
  311.             }
  312.         };
  313.         /**
  314.          * open/close select
  315.          * when opened show the default placeholder if any
  316.          */
  317.         SelectFx.prototype._toggleSelect = function () {
  318.             // remove focus class if any..
  319.             this._removeFocus();
  320.  
  321.             if (this._isOpen()) {
  322.                 if (this.current !== -1) {
  323.                     // update placeholder text
  324.                     this.selPlaceholder.textContent = this.selOpts[this.current].textContent;
  325.                 }
  326.                 classie.remove(this.selEl, 'cs-active');
  327.             } else {
  328.                 if (this.hasDefaultPlaceholder && this.options.stickyPlaceholder) {
  329.                     // everytime we open we wanna see the default placeholder text
  330.                     this.selPlaceholder.textContent = this.selectedOpt.textContent;
  331.                 }
  332.                 classie.add(this.selEl, 'cs-active');
  333.             }
  334.         };
  335.         /**
  336.          * detect if .cs-options wrapper is active for each select
  337.          */
  338.         SelectFx.prototype._styleExist = function (e) {
  339.             return (' ' + e.className + ' ').indexOf(' cs-options ') > -1;
  340.         };
  341.         /**
  342.          * change option - the new value is set
  343.          */
  344.         SelectFx.prototype._changeOption = function () {
  345.  
  346.             // if pre selected current (if we navigate with the keyboard)...
  347.             if (typeof this.preSelCurrent != 'undefined' && this.preSelCurrent !== -1) {
  348.                 this.current = this.preSelCurrent;
  349.                 this.preSelCurrent = -1;
  350.             }
  351.  
  352.             // current option
  353.             var opt = this.selOpts[this.current];
  354.  
  355.             // update current selected value
  356.             this.selPlaceholder.textContent = opt.textContent;
  357.  
  358.             // change native select element´s value
  359.             this.el.value = opt.getAttribute('data-value');
  360.             var event = new Event('change');
  361.             this.el.dispatchEvent(event);
  362.  
  363.             // remove class cs-selected from old selected option and add it to current selected option
  364.             var oldOpt = this.selEl.querySelector('li.cs-selected');
  365.             if (oldOpt) {
  366.                 classie.remove(oldOpt, 'cs-selected');
  367.             }
  368.             classie.add(opt, 'cs-selected');
  369.  
  370.             // if there´s a link defined
  371.             if (opt.getAttribute('data-link')) {
  372.                 // open in new tab?
  373.                 if (this.options.newTab) {
  374.                     window.open(opt.getAttribute('data-link'), '_blank');
  375.                 } else {
  376.                     window.location = opt.getAttribute('data-link');
  377.                 }
  378.             }
  379.  
  380.             // callback
  381.             this.options.onChange(this.el.value);
  382.         };
  383.         /**
  384.          * returns true if select element is opened
  385.          */
  386.         SelectFx.prototype._isOpen = function (opt) {
  387.             return classie.has(this.selEl, 'cs-active');
  388.         };
  389.         /**
  390.          * removes the focus class from the option
  391.          */
  392.         SelectFx.prototype._removeFocus = function (opt) {
  393.             var focusEl = this.selEl.querySelector('li.cs-focus')
  394.             if (focusEl) {
  395.                 classie.remove(focusEl, 'cs-focus');
  396.             }
  397.         };
  398.  
  399.         return SelectFx;
  400.     }]);
  401.  
  402.     angular.module('app').directive('csSelect', ["SelectFx","$timeout", function (SelectFx,$timeout) {
  403.         return {
  404.             restrict: 'AC',
  405.             link: function ($scope, $element, $attributes) {
  406.  
  407.  
  408.                 $timeout(function () {
  409.                     new SelectFx($element);
  410.                 },3000);
  411.  
  412.  
  413.  
  414.  
  415.             }
  416.         };
  417.     }]);
  418. })();
Advertisement
Add Comment
Please, Sign In to add comment