summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorLuke "Jared" Bennett <lbennett@gitlab.com>2017-04-07 13:57:03 +0000
committerJacob Schatz <jschatz@gitlab.com>2017-04-07 13:57:03 +0000
commitdab60475c79ff272c2a941326d609fed5fa4032e (patch)
tree8b9a5b9f269c6d39f6dcafc8b432ae2d9af7fbd4 /app
parent780a8968a50ff1b23eea6a72600f5f19a01cb81a (diff)
downloadgitlab-ce-dab60475c79ff272c2a941326d609fed5fa4032e.tar.gz
Update droplab
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/droplab/constants.js11
-rw-r--r--app/assets/javascripts/droplab/drop_down.js137
-rw-r--r--app/assets/javascripts/droplab/drop_lab.js152
-rw-r--r--app/assets/javascripts/droplab/droplab.js741
-rw-r--r--app/assets/javascripts/droplab/droplab_ajax.js103
-rw-r--r--app/assets/javascripts/droplab/droplab_ajax_filter.js164
-rw-r--r--app/assets/javascripts/droplab/droplab_filter.js76
-rw-r--r--app/assets/javascripts/droplab/hook.js22
-rw-r--r--app/assets/javascripts/droplab/hook_button.js65
-rw-r--r--app/assets/javascripts/droplab/hook_input.js119
-rw-r--r--app/assets/javascripts/droplab/keyboard.js113
-rw-r--r--app/assets/javascripts/droplab/plugins/ajax.js65
-rw-r--r--app/assets/javascripts/droplab/plugins/ajax_filter.js133
-rw-r--r--app/assets/javascripts/droplab/plugins/filter.js95
-rw-r--r--app/assets/javascripts/droplab/plugins/input_setter.js52
-rw-r--r--app/assets/javascripts/droplab/utils.js38
-rw-r--r--app/assets/javascripts/filtered_search/dropdown_hint.js10
-rw-r--r--app/assets/javascripts/filtered_search/dropdown_non_user.js22
-rw-r--r--app/assets/javascripts/filtered_search/dropdown_user.js17
-rw-r--r--app/assets/javascripts/filtered_search/filtered_search_dropdown.js2
-rw-r--r--app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js2
-rw-r--r--app/assets/javascripts/filtered_search/filtered_search_manager.js2
-rw-r--r--app/assets/javascripts/main.js6
-rw-r--r--app/assets/stylesheets/framework/filters.scss6
-rw-r--r--app/views/shared/issuable/_search_bar.html.haml2
25 files changed, 1040 insertions, 1115 deletions
diff --git a/app/assets/javascripts/droplab/constants.js b/app/assets/javascripts/droplab/constants.js
new file mode 100644
index 00000000000..a23d914772a
--- /dev/null
+++ b/app/assets/javascripts/droplab/constants.js
@@ -0,0 +1,11 @@
+const DATA_TRIGGER = 'data-dropdown-trigger';
+const DATA_DROPDOWN = 'data-dropdown';
+const SELECTED_CLASS = 'droplab-item-selected';
+const ACTIVE_CLASS = 'droplab-item-active';
+
+export {
+ DATA_TRIGGER,
+ DATA_DROPDOWN,
+ SELECTED_CLASS,
+ ACTIVE_CLASS,
+};
diff --git a/app/assets/javascripts/droplab/drop_down.js b/app/assets/javascripts/droplab/drop_down.js
new file mode 100644
index 00000000000..f686ad33f6f
--- /dev/null
+++ b/app/assets/javascripts/droplab/drop_down.js
@@ -0,0 +1,137 @@
+/* eslint-disable */
+
+import utils from './utils';
+import { SELECTED_CLASS } from './constants';
+
+var DropDown = function(list) {
+ this.currentIndex = 0;
+ this.hidden = true;
+ this.list = typeof list === 'string' ? document.querySelector(list) : list;
+ this.items = [];
+
+ this.eventWrapper = {};
+
+ this.getItems();
+ this.initTemplateString();
+ this.addEvents();
+
+ this.initialState = list.innerHTML;
+};
+
+Object.assign(DropDown.prototype, {
+ getItems: function() {
+ this.items = [].slice.call(this.list.querySelectorAll('li'));
+ return this.items;
+ },
+
+ initTemplateString: function() {
+ var items = this.items || this.getItems();
+
+ var templateString = '';
+ if (items.length > 0) templateString = items[items.length - 1].outerHTML;
+ this.templateString = templateString;
+
+ return this.templateString;
+ },
+
+ clickEvent: function(e) {
+ var selected = utils.closest(e.target, 'LI');
+ if (!selected) return;
+
+ this.addSelectedClass(selected);
+
+ e.preventDefault();
+ this.hide();
+
+ var listEvent = new CustomEvent('click.dl', {
+ detail: {
+ list: this,
+ selected: selected,
+ data: e.target.dataset,
+ },
+ });
+ this.list.dispatchEvent(listEvent);
+ },
+
+ addSelectedClass: function (selected) {
+ this.removeSelectedClasses();
+ selected.classList.add(SELECTED_CLASS);
+ },
+
+ removeSelectedClasses: function () {
+ const items = this.items || this.getItems();
+
+ items.forEach(item => item.classList.remove(SELECTED_CLASS));
+ },
+
+ addEvents: function() {
+ this.eventWrapper.clickEvent = this.clickEvent.bind(this)
+ this.list.addEventListener('click', this.eventWrapper.clickEvent);
+ },
+
+ toggle: function() {
+ this.hidden ? this.show() : this.hide();
+ },
+
+ setData: function(data) {
+ this.data = data;
+ this.render(data);
+ },
+
+ addData: function(data) {
+ this.data = (this.data || []).concat(data);
+ this.render(this.data);
+ },
+
+ render: function(data) {
+ const children = data ? data.map(this.renderChildren.bind(this)) : [];
+ const renderableList = this.list.querySelector('ul[data-dynamic]') || this.list;
+
+ renderableList.innerHTML = children.join('');
+ },
+
+ renderChildren: function(data) {
+ var html = utils.t(this.templateString, data);
+ var template = document.createElement('div');
+
+ template.innerHTML = html;
+ this.setImagesSrc(template);
+ template.firstChild.style.display = data.droplab_hidden ? 'none' : 'block';
+
+ return template.firstChild.outerHTML;
+ },
+
+ setImagesSrc: function(template) {
+ const images = [].slice.call(template.querySelectorAll('img[data-src]'));
+
+ images.forEach((image) => {
+ image.src = image.getAttribute('data-src');
+ image.removeAttribute('data-src');
+ });
+ },
+
+ show: function() {
+ if (!this.hidden) return;
+ this.list.style.display = 'block';
+ this.currentIndex = 0;
+ this.hidden = false;
+ },
+
+ hide: function() {
+ if (this.hidden) return;
+ this.list.style.display = 'none';
+ this.currentIndex = 0;
+ this.hidden = true;
+ },
+
+ toggle: function () {
+ this.hidden ? this.show() : this.hide();
+ },
+
+ destroy: function() {
+ this.hide();
+ this.list.removeEventListener('click', this.eventWrapper.clickEvent);
+ }
+});
+
+export default DropDown;
diff --git a/app/assets/javascripts/droplab/drop_lab.js b/app/assets/javascripts/droplab/drop_lab.js
new file mode 100644
index 00000000000..6eb9f314af7
--- /dev/null
+++ b/app/assets/javascripts/droplab/drop_lab.js
@@ -0,0 +1,152 @@
+/* eslint-disable */
+
+import HookButton from './hook_button';
+import HookInput from './hook_input';
+import utils from './utils';
+import Keyboard from './keyboard';
+import { DATA_TRIGGER } from './constants';
+
+var DropLab = function() {
+ this.ready = false;
+ this.hooks = [];
+ this.queuedData = [];
+ this.config = {};
+
+ this.eventWrapper = {};
+};
+
+Object.assign(DropLab.prototype, {
+ loadStatic: function(){
+ var dropdownTriggers = [].slice.apply(document.querySelectorAll(`[${DATA_TRIGGER}]`));
+ this.addHooks(dropdownTriggers);
+ },
+
+ addData: function () {
+ var args = [].slice.apply(arguments);
+ this.applyArgs(args, '_addData');
+ },
+
+ setData: function() {
+ var args = [].slice.apply(arguments);
+ this.applyArgs(args, '_setData');
+ },
+
+ destroy: function() {
+ this.hooks.forEach(hook => hook.destroy());
+ this.hooks = [];
+ this.removeEvents();
+ },
+
+ applyArgs: function(args, methodName) {
+ if (this.ready) return this[methodName].apply(this, args);
+
+ this.queuedData = this.queuedData || [];
+ this.queuedData.push(args);
+ },
+
+ _addData: function(trigger, data) {
+ this._processData(trigger, data, 'addData');
+ },
+
+ _setData: function(trigger, data) {
+ this._processData(trigger, data, 'setData');
+ },
+
+ _processData: function(trigger, data, methodName) {
+ this.hooks.forEach((hook) => {
+ if (Array.isArray(trigger)) hook.list[methodName](trigger);
+
+ if (hook.trigger.id === trigger) hook.list[methodName](data);
+ });
+ },
+
+ addEvents: function() {
+ this.eventWrapper.documentClicked = this.documentClicked.bind(this)
+ document.addEventListener('click', this.eventWrapper.documentClicked);
+ },
+
+ documentClicked: function(e) {
+ let thisTag = e.target;
+
+ if (thisTag.tagName !== 'UL') thisTag = utils.closest(thisTag, 'UL');
+ if (utils.isDropDownParts(thisTag, this.hooks) || utils.isDropDownParts(e.target, this.hooks)) return;
+
+ this.hooks.forEach(hook => hook.list.hide());
+ },
+
+ removeEvents: function(){
+ document.removeEventListener('click', this.eventWrapper.documentClicked);
+ },
+
+ changeHookList: function(trigger, list, plugins, config) {
+ const availableTrigger = typeof trigger === 'string' ? document.getElementById(trigger) : trigger;
+
+
+ this.hooks.forEach((hook, i) => {
+ hook.list.list.dataset.dropdownActive = false;
+
+ if (hook.trigger !== availableTrigger) return;
+
+ hook.destroy();
+ this.hooks.splice(i, 1);
+ this.addHook(availableTrigger, list, plugins, config);
+ });
+ },
+
+ addHook: function(hook, list, plugins, config) {
+ const availableHook = typeof hook === 'string' ? document.querySelector(hook) : hook;
+ let availableList;
+
+ if (typeof list === 'string') {
+ availableList = document.querySelector(list);
+ } else if (list instanceof Element) {
+ availableList = list;
+ } else {
+ availableList = document.querySelector(hook.dataset[utils.toCamelCase(DATA_TRIGGER)]);
+ }
+
+ availableList.dataset.dropdownActive = true;
+
+ const HookObject = availableHook.tagName === 'INPUT' ? HookInput : HookButton;
+ this.hooks.push(new HookObject(availableHook, availableList, plugins, config));
+
+ return this;
+ },
+
+ addHooks: function(hooks, plugins, config) {
+ hooks.forEach(hook => this.addHook(hook, null, plugins, config));
+ return this;
+ },
+
+ setConfig: function(obj){
+ this.config = obj;
+ },
+
+ fireReady: function() {
+ const readyEvent = new CustomEvent('ready.dl', {
+ detail: {
+ dropdown: this,
+ },
+ });
+ document.dispatchEvent(readyEvent);
+
+ this.ready = true;
+ },
+
+ init: function (hook, list, plugins, config) {
+ hook ? this.addHook(hook, list, plugins, config) : this.loadStatic();
+
+ this.addEvents();
+
+ Keyboard();
+
+ this.fireReady();
+
+ this.queuedData.forEach(data => this.addData(data));
+ this.queuedData = [];
+
+ return this;
+ },
+});
+
+export default DropLab;
diff --git a/app/assets/javascripts/droplab/droplab.js b/app/assets/javascripts/droplab/droplab.js
deleted file mode 100644
index 8b14191395b..00000000000
--- a/app/assets/javascripts/droplab/droplab.js
+++ /dev/null
@@ -1,741 +0,0 @@
-/* eslint-disable */
-// Determine where to place this
-if (typeof Object.assign != 'function') {
- Object.assign = function (target, varArgs) { // .length of function is 2
- 'use strict';
- if (target == null) { // TypeError if undefined or null
- throw new TypeError('Cannot convert undefined or null to object');
- }
-
- var to = Object(target);
-
- for (var index = 1; index < arguments.length; index++) {
- var nextSource = arguments[index];
-
- if (nextSource != null) { // Skip over if undefined or null
- for (var nextKey in nextSource) {
- // Avoid bugs when hasOwnProperty is shadowed
- if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
- to[nextKey] = nextSource[nextKey];
- }
- }
- }
- }
- return to;
- };
-}
-
-(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.droplab = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
-var DATA_TRIGGER = 'data-dropdown-trigger';
-var DATA_DROPDOWN = 'data-dropdown';
-
-module.exports = {
- DATA_TRIGGER: DATA_TRIGGER,
- DATA_DROPDOWN: DATA_DROPDOWN,
-}
-
-},{}],2:[function(require,module,exports){
-// Custom event support for IE
-if ( typeof CustomEvent === "function" ) {
- module.exports = CustomEvent;
-} else {
- require('./window')(function(w){
- var CustomEvent = function ( event, params ) {
- params = params || { bubbles: false, cancelable: false, detail: undefined };
- var evt = document.createEvent( 'CustomEvent' );
- evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail );
- return evt;
- }
- CustomEvent.prototype = w.Event.prototype;
-
- w.CustomEvent = CustomEvent;
- });
- module.exports = CustomEvent;
-}
-
-},{"./window":11}],3:[function(require,module,exports){
-var CustomEvent = require('./custom_event_polyfill');
-var utils = require('./utils');
-
-var DropDown = function(list) {
- this.currentIndex = 0;
- this.hidden = true;
- this.list = list;
- this.items = [];
- this.getItems();
- this.initTemplateString();
- this.addEvents();
- this.initialState = list.innerHTML;
-};
-
-Object.assign(DropDown.prototype, {
- getItems: function() {
- this.items = [].slice.call(this.list.querySelectorAll('li'));
- return this.items;
- },
-
- initTemplateString: function() {
- var items = this.items || this.getItems();
-
- var templateString = '';
- if(items.length > 0) {
- templateString = items[items.length - 1].outerHTML;
- }
- this.templateString = templateString;
- return this.templateString;
- },
-
- clickEvent: function(e) {
- // climb up the tree to find the LI
- var selected = utils.closest(e.target, 'LI');
-
- if(selected) {
- e.preventDefault();
- this.hide();
- var listEvent = new CustomEvent('click.dl', {
- detail: {
- list: this,
- selected: selected,
- data: e.target.dataset,
- },
- });
- this.list.dispatchEvent(listEvent);
- }
- },
-
- addEvents: function() {
- this.clickWrapper = this.clickEvent.bind(this);
- // event delegation.
- this.list.addEventListener('click', this.clickWrapper);
- },
-
- toggle: function() {
- if(this.hidden) {
- this.show();
- } else {
- this.hide();
- }
- },
-
- setData: function(data) {
- this.data = data;
- this.render(data);
- },
-
- addData: function(data) {
- this.data = (this.data || []).concat(data);
- this.render(this.data);
- },
-
- // call render manually on data;
- render: function(data){
- // debugger
- // empty the list first
- var templateString = this.templateString;
- var newChildren = [];
- var toAppend;
-
- newChildren = (data ||[]).map(function(dat){
- var html = utils.t(templateString, dat);
- var template = document.createElement('div');
- template.innerHTML = html;
-
- // Help set the image src template
- var imageTags = template.querySelectorAll('img[data-src]');
- // debugger
- for(var i = 0; i < imageTags.length; i++) {
- var imageTag = imageTags[i];
- imageTag.src = imageTag.getAttribute('data-src');
- imageTag.removeAttribute('data-src');
- }
-
- if(dat.hasOwnProperty('droplab_hidden') && dat.droplab_hidden){
- template.firstChild.style.display = 'none'
- }else{
- template.firstChild.style.display = 'block';
- }
- return template.firstChild.outerHTML;
- });
- toAppend = this.list.querySelector('ul[data-dynamic]');
- if(toAppend) {
- toAppend.innerHTML = newChildren.join('');
- } else {
- this.list.innerHTML = newChildren.join('');
- }
- },
-
- show: function() {
- if (this.hidden) {
- // debugger
- this.list.style.display = 'block';
- this.currentIndex = 0;
- this.hidden = false;
- }
- },
-
- hide: function() {
- if (!this.hidden) {
- // debugger
- this.list.style.display = 'none';
- this.currentIndex = 0;
- this.hidden = true;
- }
- },
-
- destroy: function() {
- this.hide();
- this.list.removeEventListener('click', this.clickWrapper);
- }
-});
-
-module.exports = DropDown;
-
-},{"./custom_event_polyfill":2,"./utils":10}],4:[function(require,module,exports){
-require('./window')(function(w){
- module.exports = function(deps) {
- deps = deps || {};
- var window = deps.window || w;
- var document = deps.document || window.document;
- var CustomEvent = deps.CustomEvent || require('./custom_event_polyfill');
- var HookButton = deps.HookButton || require('./hook_button');
- var HookInput = deps.HookInput || require('./hook_input');
- var utils = deps.utils || require('./utils');
- var DATA_TRIGGER = require('./constants').DATA_TRIGGER;
-
- var DropLab = function(hook){
- if (!(this instanceof DropLab)) return new DropLab(hook);
- this.ready = false;
- this.hooks = [];
- this.queuedData = [];
- this.config = {};
- this.loadWrapper;
- if(typeof hook !== 'undefined'){
- this.addHook(hook);
- }
- };
-
-
- Object.assign(DropLab.prototype, {
- load: function() {
- this.loadWrapper();
- },
-
- loadWrapper: function(){
- var dropdownTriggers = [].slice.apply(document.querySelectorAll('['+DATA_TRIGGER+']'));
- this.addHooks(dropdownTriggers).init();
- },
-
- addData: function () {
- var args = [].slice.apply(arguments);
- this.applyArgs(args, '_addData');
- },
-
- setData: function() {
- var args = [].slice.apply(arguments);
- this.applyArgs(args, '_setData');
- },
-
- destroy: function() {
- for(var i = 0; i < this.hooks.length; i++) {
- this.hooks[i].destroy();
- }
- this.hooks = [];
- this.removeEvents();
- },
-
- applyArgs: function(args, methodName) {
- if(this.ready) {
- this[methodName].apply(this, args);
- } else {
- this.queuedData = this.queuedData || [];
- this.queuedData.push(args);
- }
- },
-
- _addData: function(trigger, data) {
- this._processData(trigger, data, 'addData');
- },
-
- _setData: function(trigger, data) {
- this._processData(trigger, data, 'setData');
- },
-
- _processData: function(trigger, data, methodName) {
- for(var i = 0; i < this.hooks.length; i++) {
- var hook = this.hooks[i];
- if(hook.trigger.dataset.hasOwnProperty('id')) {
- if(hook.trigger.dataset.id === trigger) {
- hook.list[methodName](data);
- }
- }
- }
- },
-
- addEvents: function() {
- var self = this;
- this.windowClickedWrapper = function(e){
- var thisTag = e.target;
- if(thisTag.tagName !== 'UL'){
- // climb up the tree to find the UL
- thisTag = utils.closest(thisTag, 'UL');
- }
- if(utils.isDropDownParts(thisTag)){ return }
- if(utils.isDropDownParts(e.target)){ return }
- for(var i = 0; i < self.hooks.length; i++) {
- self.hooks[i].list.hide();
- }
- }.bind(this);
- document.addEventListener('click', this.windowClickedWrapper);
- },
-
- removeEvents: function(){
- w.removeEventListener('click', this.windowClickedWrapper);
- w.removeEventListener('load', this.loadWrapper);
- },
-
- changeHookList: function(trigger, list, plugins, config) {
- trigger = document.querySelector('[data-id="'+trigger+'"]');
- // list = document.querySelector(list);
- this.hooks.every(function(hook, i) {
- if(hook.trigger === trigger) {
- hook.destroy();
- this.hooks.splice(i, 1);
- this.addHook(trigger, list, plugins, config);
- return false;
- }
- return true
- }.bind(this));
- },
-
- addHook: function(hook, list, plugins, config) {
- if(!(hook instanceof HTMLElement) && typeof hook === 'string'){
- hook = document.querySelector(hook);
- }
- if(!list){
- list = document.querySelector(hook.dataset[utils.toDataCamelCase(DATA_TRIGGER)]);
- }
-
- if(hook) {
- if(hook.tagName === 'A' || hook.tagName === 'BUTTON') {
- this.hooks.push(new HookButton(hook, list, plugins, config));
- } else if(hook.tagName === 'INPUT') {
- this.hooks.push(new HookInput(hook, list, plugins, config));
- }
- }
- return this;
- },
-
- addHooks: function(hooks, plugins, config) {
- for(var i = 0; i < hooks.length; i++) {
- var hook = hooks[i];
- this.addHook(hook, null, plugins, config);
- }
- return this;
- },
-
- setConfig: function(obj){
- this.config = obj;
- },
-
- init: function () {
- this.addEvents();
- var readyEvent = new CustomEvent('ready.dl', {
- detail: {
- dropdown: this,
- },
- });
- window.dispatchEvent(readyEvent);
- this.ready = true;
- for(var i = 0; i < this.queuedData.length; i++) {
- this.addData.apply(this, this.queuedData[i]);
- }
- this.queuedData = [];
- return this;
- },
- });
-
- return DropLab;
- };
-});
-
-},{"./constants":1,"./custom_event_polyfill":2,"./hook_button":6,"./hook_input":7,"./utils":10,"./window":11}],5:[function(require,module,exports){
-var DropDown = require('./dropdown');
-
-var Hook = function(trigger, list, plugins, config){
- this.trigger = trigger;
- this.list = new DropDown(list);
- this.type = 'Hook';
- this.event = 'click';
- this.plugins = plugins || [];
- this.config = config || {};
- this.id = trigger.dataset.id;
-};
-
-Object.assign(Hook.prototype, {
-
- addEvents: function(){},
-
- constructor: Hook,
-});
-
-module.exports = Hook;
-
-},{"./dropdown":3}],6:[function(require,module,exports){
-var CustomEvent = require('./custom_event_polyfill');
-var Hook = require('./hook');
-
-var HookButton = function(trigger, list, plugins, config) {
- Hook.call(this, trigger, list, plugins, config);
- this.type = 'button';
- this.event = 'click';
- this.addEvents();
- this.addPlugins();
-};
-
-HookButton.prototype = Object.create(Hook.prototype);
-
-Object.assign(HookButton.prototype, {
- addPlugins: function() {
- for(var i = 0; i < this.plugins.length; i++) {
- this.plugins[i].init(this);
- }
- },
-
- clicked: function(e){
- var buttonEvent = new CustomEvent('click.dl', {
- detail: {
- hook: this,
- },
- bubbles: true,
- cancelable: true
- });
- this.list.show();
- e.target.dispatchEvent(buttonEvent);
- },
-
- addEvents: function(){
- this.clickedWrapper = this.clicked.bind(this);
- this.trigger.addEventListener('click', this.clickedWrapper);
- },
-
- removeEvents: function(){
- this.trigger.removeEventListener('click', this.clickedWrapper);
- },
-
- restoreInitialState: function() {
- this.list.list.innerHTML = this.list.initialState;
- },
-
- removePlugins: function() {
- for(var i = 0; i < this.plugins.length; i++) {
- this.plugins[i].destroy();
- }
- },
-
- destroy: function() {
- this.restoreInitialState();
- this.removeEvents();
- this.removePlugins();
- },
-
-
- constructor: HookButton,
-});
-
-
-module.exports = HookButton;
-
-},{"./custom_event_polyfill":2,"./hook":5}],7:[function(require,module,exports){
-var CustomEvent = require('./custom_event_polyfill');
-var Hook = require('./hook');
-
-var HookInput = function(trigger, list, plugins, config) {
- Hook.call(this, trigger, list, plugins, config);
- this.type = 'input';
- this.event = 'input';
- this.addPlugins();
- this.addEvents();
-};
-
-Object.assign(HookInput.prototype, {
- addPlugins: function() {
- var self = this;
- for(var i = 0; i < this.plugins.length; i++) {
- this.plugins[i].init(self);
- }
- },
-
- addEvents: function(){
- var self = this;
-
- this.mousedown = function mousedown(e) {
- if(self.hasRemovedEvents) return;
-
- var mouseEvent = new CustomEvent('mousedown.dl', {
- detail: {
- hook: self,
- text: e.target.value,
- },
- bubbles: true,
- cancelable: true
- });
- e.target.dispatchEvent(mouseEvent);
- }
-
- this.input = function input(e) {
- if(self.hasRemovedEvents) return;
-
- self.list.show();
-
- var inputEvent = new CustomEvent('input.dl', {
- detail: {
- hook: self,
- text: e.target.value,
- },
- bubbles: true,
- cancelable: true
- });
- e.target.dispatchEvent(inputEvent);
- }
-
- this.keyup = function keyup(e) {
- if(self.hasRemovedEvents) return;
-
- keyEvent(e, 'keyup.dl');
- }
-
- this.keydown = function keydown(e) {
- if(self.hasRemovedEvents) return;
-
- keyEvent(e, 'keydown.dl');
- }
-
- function keyEvent(e, keyEventName){
- self.list.show();
-
- var keyEvent = new CustomEvent(keyEventName, {
- detail: {
- hook: self,
- text: e.target.value,
- which: e.which,
- key: e.key,
- },
- bubbles: true,
- cancelable: true
- });
- e.target.dispatchEvent(keyEvent);
- }
-
- this.events = this.events || {};
- this.events.mousedown = this.mousedown;
- this.events.input = this.input;
- this.events.keyup = this.keyup;
- this.events.keydown = this.keydown;
- this.trigger.addEventListener('mousedown', this.mousedown);
- this.trigger.addEventListener('input', this.input);
- this.trigger.addEventListener('keyup', this.keyup);
- this.trigger.addEventListener('keydown', this.keydown);
- },
-
- removeEvents: function() {
- this.hasRemovedEvents = true;
- this.trigger.removeEventListener('mousedown', this.mousedown);
- this.trigger.removeEventListener('input', this.input);
- this.trigger.removeEventListener('keyup', this.keyup);
- this.trigger.removeEventListener('keydown', this.keydown);
- },
-
- restoreInitialState: function() {
- this.list.list.innerHTML = this.list.initialState;
- },
-
- removePlugins: function() {
- for(var i = 0; i < this.plugins.length; i++) {
- this.plugins[i].destroy();
- }
- },
-
- destroy: function() {
- this.restoreInitialState();
- this.removeEvents();
- this.removePlugins();
- this.list.destroy();
- }
-});
-
-module.exports = HookInput;
-
-},{"./custom_event_polyfill":2,"./hook":5}],8:[function(require,module,exports){
-var DropLab = require('./droplab')();
-var DATA_TRIGGER = require('./constants').DATA_TRIGGER;
-var keyboard = require('./keyboard')();
-var setup = function() {
- window.DropLab = DropLab;
-};
-
-
-module.exports = setup();
-
-},{"./constants":1,"./droplab":4,"./keyboard":9}],9:[function(require,module,exports){
-require('./window')(function(w){
- module.exports = function(){
- var currentKey;
- var currentFocus;
- var isUpArrow = false;
- var isDownArrow = false;
- var removeHighlight = function removeHighlight(list) {
- var listItems = Array.prototype.slice.call(list.list.querySelectorAll('li:not(.divider)'), 0);
- var listItemsTmp = [];
- for(var i = 0; i < listItems.length; i++) {
- var listItem = listItems[i];
- listItem.classList.remove('dropdown-active');
-
- if (listItem.style.display !== 'none') {
- listItemsTmp.push(listItem);
- }
- }
- return listItemsTmp;
- };
-
- var setMenuForArrows = function setMenuForArrows(list) {
- var listItems = removeHighlight(list);
- if(list.currentIndex>0){
- if(!listItems[list.currentIndex-1]){
- list.currentIndex = list.currentIndex-1;
- }
-
- if (listItems[list.currentIndex-1]) {
- var el = listItems[list.currentIndex-1];
- var filterDropdownEl = el.closest('.filter-dropdown');
- el.classList.add('dropdown-active');
-
- if (filterDropdownEl) {
- var filterDropdownBottom = filterDropdownEl.offsetHeight;
- var elOffsetTop = el.offsetTop - 30;
-
- if (elOffsetTop > filterDropdownBottom) {
- filterDropdownEl.scrollTop = elOffsetTop - filterDropdownBottom;
- }
- }
- }
- }
- };
-
- var mousedown = function mousedown(e) {
- var list = e.detail.hook.list;
- removeHighlight(list);
- list.show();
- list.currentIndex = 0;
- isUpArrow = false;
- isDownArrow = false;
- };
- var selectItem = function selectItem(list) {
- var listItems = removeHighlight(list);
- var currentItem = listItems[list.currentIndex-1];
- var listEvent = new CustomEvent('click.dl', {
- detail: {
- list: list,
- selected: currentItem,
- data: currentItem.dataset,
- },
- });
- list.list.dispatchEvent(listEvent);
- list.hide();
- }
-
- var keydown = function keydown(e){
- var typedOn = e.target;
- var list = e.detail.hook.list;
- var currentIndex = list.currentIndex;
- isUpArrow = false;
- isDownArrow = false;
-
- if(e.detail.which){
- currentKey = e.detail.which;
- if(currentKey === 13){
- selectItem(e.detail.hook.list);
- return;
- }
- if(currentKey === 38) {
- isUpArrow = true;
- }
- if(currentKey === 40) {
- isDownArrow = true;
- }
- } else if(e.detail.key) {
- currentKey = e.detail.key;
- if(currentKey === 'Enter'){
- selectItem(e.detail.hook.list);
- return;
- }
- if(currentKey === 'ArrowUp') {
- isUpArrow = true;
- }
- if(currentKey === 'ArrowDown') {
- isDownArrow = true;
- }
- }
- if(isUpArrow){ currentIndex--; }
- if(isDownArrow){ currentIndex++; }
- if(currentIndex < 0){ currentIndex = 0; }
- list.currentIndex = currentIndex;
- setMenuForArrows(e.detail.hook.list);
- };
-
- w.addEventListener('mousedown.dl', mousedown);
- w.addEventListener('keydown.dl', keydown);
- };
-});
-},{"./window":11}],10:[function(require,module,exports){
-var DATA_TRIGGER = require('./constants').DATA_TRIGGER;
-var DATA_DROPDOWN = require('./constants').DATA_DROPDOWN;
-
-var toDataCamelCase = function(attr){
- return this.camelize(attr.split('-').slice(1).join(' '));
-};
-
-// the tiniest damn templating I can do
-var t = function(s,d){
- for(var p in d)
- s=s.replace(new RegExp('{{'+p+'}}','g'), d[p]);
- return s;
-};
-
-var camelize = function(str) {
- return str.replace(/(?:^\w|[A-Z]|\b\w)/g, function(letter, index) {
- return index == 0 ? letter.toLowerCase() : letter.toUpperCase();
- }).replace(/\s+/g, '');
-};
-
-var closest = function(thisTag, stopTag) {
- while(thisTag && thisTag.tagName !== stopTag && thisTag.tagName !== 'HTML'){
- thisTag = thisTag.parentNode;
- }
- return thisTag;
-};
-
-var isDropDownParts = function(target) {
- if(!target || target.tagName === 'HTML') { return false; }
- return (
- target.hasAttribute(DATA_TRIGGER) ||
- target.hasAttribute(DATA_DROPDOWN)
- );
-};
-
-module.exports = {
- toDataCamelCase: toDataCamelCase,
- t: t,
- camelize: camelize,
- closest: closest,
- isDropDownParts: isDropDownParts,
-};
-
-},{"./constants":1}],11:[function(require,module,exports){
-module.exports = function(callback) {
- return (function() {
- callback(this);
- }).call(null);
-};
-
-},{}]},{},[8])(8)
-});
diff --git a/app/assets/javascripts/droplab/droplab_ajax.js b/app/assets/javascripts/droplab/droplab_ajax.js
deleted file mode 100644
index 020f8b4ac65..00000000000
--- a/app/assets/javascripts/droplab/droplab_ajax.js
+++ /dev/null
@@ -1,103 +0,0 @@
-/* eslint-disable */
-(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g=(g.droplab||(g.droplab = {}));g=(g.ajax||(g.ajax = {}));g=(g.datasource||(g.datasource = {}));g.js = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
-/* global droplab */
-
-require('../window')(function(w){
- function droplabAjaxException(message) {
- this.message = message;
- }
-
- w.droplabAjax = {
- _loadUrlData: function _loadUrlData(url) {
- var self = this;
- return new Promise(function(resolve, reject) {
- var xhr = new XMLHttpRequest;
- xhr.open('GET', url, true);
- xhr.onreadystatechange = function () {
- if(xhr.readyState === XMLHttpRequest.DONE) {
- if (xhr.status === 200) {
- var data = JSON.parse(xhr.responseText);
- self.cache[url] = data;
- return resolve(data);
- } else {
- return reject([xhr.responseText, xhr.status]);
- }
- }
- };
- xhr.send();
- });
- },
-
- _loadData: function _loadData(data, config, self) {
- if (config.loadingTemplate) {
- var dataLoadingTemplate = self.hook.list.list.querySelector('[data-loading-template]');
-
- if (dataLoadingTemplate) {
- dataLoadingTemplate.outerHTML = self.listTemplate;
- }
- }
-
- if (!self.destroyed) {
- self.hook.list[config.method].call(self.hook.list, data);
- }
- },
-
- init: function init(hook) {
- var self = this;
- self.destroyed = false;
- self.cache = self.cache || {};
- var config = hook.config.droplabAjax;
- this.hook = hook;
-
- if (!config || !config.endpoint || !config.method) {
- return;
- }
-
- if (config.method !== 'setData' && config.method !== 'addData') {
- return;
- }
-
- if (config.loadingTemplate) {
- var dynamicList = hook.list.list.querySelector('[data-dynamic]');
-
- var loadingTemplate = document.createElement('div');
- loadingTemplate.innerHTML = config.loadingTemplate;
- loadingTemplate.setAttribute('data-loading-template', '');
-
- this.listTemplate = dynamicList.outerHTML;
- dynamicList.outerHTML = loadingTemplate.outerHTML;
- }
-
- if (self.cache[config.endpoint]) {
- self._loadData(self.cache[config.endpoint], config, self);
- } else {
- this._loadUrlData(config.endpoint)
- .then(function(d) {
- self._loadData(d, config, self);
- }, function(xhrError) {
- // TODO: properly handle errors due to XHR cancellation
- return;
- }).catch(function(e) {
- throw new droplabAjaxException(e.message || e);
- });
- }
- },
-
- destroy: function() {
- var dynamicList = this.hook.list.list.querySelector('[data-dynamic]');
- this.destroyed = true;
- if (this.listTemplate && dynamicList) {
- dynamicList.outerHTML = this.listTemplate;
- }
- }
- };
-});
-},{"../window":2}],2:[function(require,module,exports){
-module.exports = function(callback) {
- return (function() {
- callback(this);
- }).call(null);
-};
-
-},{}]},{},[1])(1)
-});
diff --git a/app/assets/javascripts/droplab/droplab_ajax_filter.js b/app/assets/javascripts/droplab/droplab_ajax_filter.js
deleted file mode 100644
index 05eba7aef56..00000000000
--- a/app/assets/javascripts/droplab/droplab_ajax_filter.js
+++ /dev/null
@@ -1,164 +0,0 @@
-/* eslint-disable */
-(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g=(g.droplab||(g.droplab = {}));g=(g.ajax||(g.ajax = {}));g=(g.datasource||(g.datasource = {}));g.js = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
-/* global droplab */
-
-require('../window')(function(w){
- w.droplabAjaxFilter = {
- init: function(hook) {
- this.destroyed = false;
- this.hook = hook;
- this.notLoading();
-
- this.debounceTriggerWrapper = this.debounceTrigger.bind(this);
- this.hook.trigger.addEventListener('keydown.dl', this.debounceTriggerWrapper);
- this.hook.trigger.addEventListener('focus', this.debounceTriggerWrapper);
- this.trigger(true);
- },
-
- notLoading: function notLoading() {
- this.loading = false;
- },
-
- debounceTrigger: function debounceTrigger(e) {
- var NON_CHARACTER_KEYS = [16, 17, 18, 20, 37, 38, 39, 40, 91, 93];
- var invalidKeyPressed = NON_CHARACTER_KEYS.indexOf(e.detail.which || e.detail.keyCode) > -1;
- var focusEvent = e.type === 'focus';
-
- if (invalidKeyPressed || this.loading) {
- return;
- }
-
- if (this.timeout) {
- clearTimeout(this.timeout);
- }
-
- this.timeout = setTimeout(this.trigger.bind(this, focusEvent), 200);
- },
-
- trigger: function trigger(getEntireList) {
- var config = this.hook.config.droplabAjaxFilter;
- var searchValue = this.trigger.value;
-
- if (!config || !config.endpoint || !config.searchKey) {
- return;
- }
-
- if (config.searchValueFunction) {
- searchValue = config.searchValueFunction();
- }
-
- if (config.loadingTemplate && this.hook.list.data === undefined ||
- this.hook.list.data.length === 0) {
- var dynamicList = this.hook.list.list.querySelector('[data-dynamic]');
-
- var loadingTemplate = document.createElement('div');
- loadingTemplate.innerHTML = config.loadingTemplate;
- loadingTemplate.setAttribute('data-loading-template', true);
-
- this.listTemplate = dynamicList.outerHTML;
- dynamicList.outerHTML = loadingTemplate.outerHTML;
- }
-
- if (getEntireList) {
- searchValue = '';
- }
-
- if (config.searchKey === searchValue) {
- return this.list.show();
- }
-
- this.loading = true;
-
- var params = config.params || {};
- params[config.searchKey] = searchValue;
- var self = this;
- self.cache = self.cache || {};
- var url = config.endpoint + this.buildParams(params);
- var urlCachedData = self.cache[url];
-
- if (urlCachedData) {
- self._loadData(urlCachedData, config, self);
- } else {
- this._loadUrlData(url)
- .then(function(data) {
- self._loadData(data, config, self);
- }, function(xhrError) {
- // TODO: properly handle errors due to XHR cancellation
- return;
- });
- }
- },
-
- _loadUrlData: function _loadUrlData(url) {
- var self = this;
- return new Promise(function(resolve, reject) {
- var xhr = new XMLHttpRequest;
- xhr.open('GET', url, true);
- xhr.onreadystatechange = function () {
- if(xhr.readyState === XMLHttpRequest.DONE) {
- if (xhr.status === 200) {
- var data = JSON.parse(xhr.responseText);
- self.cache[url] = data;
- return resolve(data);
- } else {
- return reject([xhr.responseText, xhr.status]);
- }
- }
- };
- xhr.send();
- });
- },
-
- _loadData: function _loadData(data, config, self) {
- if (config.loadingTemplate && self.hook.list.data === undefined ||
- self.hook.list.data.length === 0) {
- const dataLoadingTemplate = self.hook.list.list.querySelector('[data-loading-template]');
-
- if (dataLoadingTemplate) {
- dataLoadingTemplate.outerHTML = self.listTemplate;
- }
- }
-
- if (!self.destroyed) {
- var hookListChildren = self.hook.list.list.children;
- var onlyDynamicList = hookListChildren.length === 1 && hookListChildren[0].hasAttribute('data-dynamic');
-
- if (onlyDynamicList && data.length === 0) {
- self.hook.list.hide();
- }
-
- self.hook.list.setData.call(self.hook.list, data);
- }
- self.notLoading();
- self.hook.list.currentIndex = 0;
- },
-
- buildParams: function(params) {
- if (!params) return '';
- var paramsArray = Object.keys(params).map(function(param) {
- return param + '=' + (params[param] || '');
- });
- return '?' + paramsArray.join('&');
- },
-
- destroy: function destroy() {
- if (this.timeout) {
- clearTimeout(this.timeout);
- }
-
- this.destroyed = true;
-
- this.hook.trigger.removeEventListener('keydown.dl', this.debounceTriggerWrapper);
- this.hook.trigger.removeEventListener('focus', this.debounceTriggerWrapper);
- }
- };
-});
-},{"../window":2}],2:[function(require,module,exports){
-module.exports = function(callback) {
- return (function() {
- callback(this);
- }).call(null);
-};
-
-},{}]},{},[1])(1)
-});
diff --git a/app/assets/javascripts/droplab/droplab_filter.js b/app/assets/javascripts/droplab/droplab_filter.js
deleted file mode 100644
index 7f7d93f3e27..00000000000
--- a/app/assets/javascripts/droplab/droplab_filter.js
+++ /dev/null
@@ -1,76 +0,0 @@
-/* eslint-disable */
-(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g=(g.droplab||(g.droplab = {}));g=(g.filter||(g.filter = {}));g.js = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
-/* global droplab */
-
-require('../window')(function(w){
- w.droplabFilter = {
-
- keydownWrapper: function(e){
- var hiddenCount = 0;
- var dataHiddenCount = 0;
- var list = e.detail.hook.list;
- var data = list.data;
- var value = e.detail.hook.trigger.value.toLowerCase();
- var config = e.detail.hook.config.droplabFilter;
- var matches = [];
- var filterFunction;
- // will only work on dynamically set data
- if(!data){
- return;
- }
-
- if (config && config.filterFunction && typeof config.filterFunction === 'function') {
- filterFunction = config.filterFunction;
- } else {
- filterFunction = function(o){
- // cheap string search
- o.droplab_hidden = o[config.template].toLowerCase().indexOf(value) === -1;
- return o;
- };
- }
-
- dataHiddenCount = data.filter(function(o) {
- return !o.droplab_hidden;
- }).length;
-
- matches = data.map(function(o) {
- return filterFunction(o, value);
- });
-
- hiddenCount = matches.filter(function(o) {
- return !o.droplab_hidden;
- }).length;
-
- if (dataHiddenCount !== hiddenCount) {
- list.render(matches);
- list.currentIndex = 0;
- }
- },
-
- init: function init(hookInput) {
- var config = hookInput.config.droplabFilter;
-
- if (!config || (!config.template && !config.filterFunction)) {
- return;
- }
-
- this.hookInput = hookInput;
- this.hookInput.trigger.addEventListener('keyup.dl', this.keydownWrapper);
- this.hookInput.trigger.addEventListener('mousedown.dl', this.keydownWrapper);
- },
-
- destroy: function destroy(){
- this.hookInput.trigger.removeEventListener('keyup.dl', this.keydownWrapper);
- this.hookInput.trigger.removeEventListener('mousedown.dl', this.keydownWrapper);
- }
- };
-});
-},{"../window":2}],2:[function(require,module,exports){
-module.exports = function(callback) {
- return (function() {
- callback(this);
- }).call(null);
-};
-
-},{}]},{},[1])(1)
-});
diff --git a/app/assets/javascripts/droplab/hook.js b/app/assets/javascripts/droplab/hook.js
new file mode 100644
index 00000000000..2f840083571
--- /dev/null
+++ b/app/assets/javascripts/droplab/hook.js
@@ -0,0 +1,22 @@
+/* eslint-disable */
+
+import DropDown from './drop_down';
+
+var Hook = function(trigger, list, plugins, config){
+ this.trigger = trigger;
+ this.list = new DropDown(list);
+ this.type = 'Hook';
+ this.event = 'click';
+ this.plugins = plugins || [];
+ this.config = config || {};
+ this.id = trigger.id;
+};
+
+Object.assign(Hook.prototype, {
+
+ addEvents: function(){},
+
+ constructor: Hook,
+});
+
+export default Hook;
diff --git a/app/assets/javascripts/droplab/hook_button.js b/app/assets/javascripts/droplab/hook_button.js
new file mode 100644
index 00000000000..be8aead1303
--- /dev/null
+++ b/app/assets/javascripts/droplab/hook_button.js
@@ -0,0 +1,65 @@
+/* eslint-disable */
+
+import Hook from './hook';
+
+var HookButton = function(trigger, list, plugins, config) {
+ Hook.call(this, trigger, list, plugins, config);
+
+ this.type = 'button';
+ this.event = 'click';
+
+ this.eventWrapper = {};
+
+ this.addEvents();
+ this.addPlugins();
+};
+
+HookButton.prototype = Object.create(Hook.prototype);
+
+Object.assign(HookButton.prototype, {
+ addPlugins: function() {
+ this.plugins.forEach(plugin => plugin.init(this));
+ },
+
+ clicked: function(e){
+ var buttonEvent = new CustomEvent('click.dl', {
+ detail: {
+ hook: this,
+ },
+ bubbles: true,
+ cancelable: true
+ });
+ e.target.dispatchEvent(buttonEvent);
+
+ this.list.toggle();
+ },
+
+ addEvents: function(){
+ this.eventWrapper.clicked = this.clicked.bind(this);
+ this.trigger.addEventListener('click', this.eventWrapper.clicked);
+ },
+
+ removeEvents: function(){
+ this.trigger.removeEventListener('click', this.eventWrapper.clicked);
+ },
+
+ restoreInitialState: function() {
+ this.list.list.innerHTML = this.list.initialState;
+ },
+
+ removePlugins: function() {
+ this.plugins.forEach(plugin => plugin.destroy());
+ },
+
+ destroy: function() {
+ this.restoreInitialState();
+
+ this.removeEvents();
+ this.removePlugins();
+ },
+
+ constructor: HookButton,
+});
+
+
+export default HookButton;
diff --git a/app/assets/javascripts/droplab/hook_input.js b/app/assets/javascripts/droplab/hook_input.js
new file mode 100644
index 00000000000..05082334045
--- /dev/null
+++ b/app/assets/javascripts/droplab/hook_input.js
@@ -0,0 +1,119 @@
+/* eslint-disable */
+
+import Hook from './hook';
+
+var HookInput = function(trigger, list, plugins, config) {
+ Hook.call(this, trigger, list, plugins, config);
+
+ this.type = 'input';
+ this.event = 'input';
+
+ this.eventWrapper = {};
+
+ this.addEvents();
+ this.addPlugins();
+};
+
+Object.assign(HookInput.prototype, {
+ addPlugins: function() {
+ this.plugins.forEach(plugin => plugin.init(this));
+ },
+
+ addEvents: function(){
+ this.eventWrapper.mousedown = this.mousedown.bind(this);
+ this.eventWrapper.input = this.input.bind(this);
+ this.eventWrapper.keyup = this.keyup.bind(this);
+ this.eventWrapper.keydown = this.keydown.bind(this);
+
+ this.trigger.addEventListener('mousedown', this.eventWrapper.mousedown);
+ this.trigger.addEventListener('input', this.eventWrapper.input);
+ this.trigger.addEventListener('keyup', this.eventWrapper.keyup);
+ this.trigger.addEventListener('keydown', this.eventWrapper.keydown);
+ },
+
+ removeEvents: function() {
+ this.hasRemovedEvents = true;
+
+ this.trigger.removeEventListener('mousedown', this.eventWrapper.mousedown);
+ this.trigger.removeEventListener('input', this.eventWrapper.input);
+ this.trigger.removeEventListener('keyup', this.eventWrapper.keyup);
+ this.trigger.removeEventListener('keydown', this.eventWrapper.keydown);
+ },
+
+ input: function(e) {
+ if(this.hasRemovedEvents) return;
+
+ this.list.show();
+
+ const inputEvent = new CustomEvent('input.dl', {
+ detail: {
+ hook: this,
+ text: e.target.value,
+ },
+ bubbles: true,
+ cancelable: true
+ });
+ e.target.dispatchEvent(inputEvent);
+ },
+
+ mousedown: function(e) {
+ if (this.hasRemovedEvents) return;
+
+ const mouseEvent = new CustomEvent('mousedown.dl', {
+ detail: {
+ hook: this,
+ text: e.target.value,
+ },
+ bubbles: true,
+ cancelable: true,
+ });
+ e.target.dispatchEvent(mouseEvent);
+ },
+
+ keyup: function(e) {
+ if (this.hasRemovedEvents) return;
+
+ this.keyEvent(e, 'keyup.dl');
+ },
+
+ keydown: function(e) {
+ if (this.hasRemovedEvents) return;
+
+ this.keyEvent(e, 'keydown.dl');
+ },
+
+ keyEvent: function(e, eventName) {
+ this.list.show();
+
+ const keyEvent = new CustomEvent(eventName, {
+ detail: {
+ hook: this,
+ text: e.target.value,
+ which: e.which,
+ key: e.key,
+ },
+ bubbles: true,
+ cancelable: true,
+ });
+ e.target.dispatchEvent(keyEvent);
+ },
+
+ restoreInitialState: function() {
+ this.list.list.innerHTML = this.list.initialState;
+ },
+
+ removePlugins: function() {
+ this.plugins.forEach(plugin => plugin.destroy());
+ },
+
+ destroy: function() {
+ this.restoreInitialState();
+
+ this.removeEvents();
+ this.removePlugins();
+
+ this.list.destroy();
+ }
+});
+
+export default HookInput;
diff --git a/app/assets/javascripts/droplab/keyboard.js b/app/assets/javascripts/droplab/keyboard.js
new file mode 100644
index 00000000000..36740a430e1
--- /dev/null
+++ b/app/assets/javascripts/droplab/keyboard.js
@@ -0,0 +1,113 @@
+/* eslint-disable */
+
+import { ACTIVE_CLASS } from './constants';
+
+const Keyboard = function () {
+ var currentKey;
+ var currentFocus;
+ var isUpArrow = false;
+ var isDownArrow = false;
+ var removeHighlight = function removeHighlight(list) {
+ var itemElements = Array.prototype.slice.call(list.list.querySelectorAll('li:not(.divider)'), 0);
+ var listItems = [];
+ for(var i = 0; i < itemElements.length; i++) {
+ var listItem = itemElements[i];
+ listItem.classList.remove(ACTIVE_CLASS);
+
+ if (listItem.style.display !== 'none') {
+ listItems.push(listItem);
+ }
+ }
+ return listItems;
+ };
+
+ var setMenuForArrows = function setMenuForArrows(list) {
+ var listItems = removeHighlight(list);
+ if(list.currentIndex>0){
+ if(!listItems[list.currentIndex-1]){
+ list.currentIndex = list.currentIndex-1;
+ }
+
+ if (listItems[list.currentIndex-1]) {
+ var el = listItems[list.currentIndex-1];
+ var filterDropdownEl = el.closest('.filter-dropdown');
+ el.classList.add(ACTIVE_CLASS);
+
+ if (filterDropdownEl) {
+ var filterDropdownBottom = filterDropdownEl.offsetHeight;
+ var elOffsetTop = el.offsetTop - 30;
+
+ if (elOffsetTop > filterDropdownBottom) {
+ filterDropdownEl.scrollTop = elOffsetTop - filterDropdownBottom;
+ }
+ }
+ }
+ }
+ };
+
+ var mousedown = function mousedown(e) {
+ var list = e.detail.hook.list;
+ removeHighlight(list);
+ list.show();
+ list.currentIndex = 0;
+ isUpArrow = false;
+ isDownArrow = false;
+ };
+ var selectItem = function selectItem(list) {
+ var listItems = removeHighlight(list);
+ var currentItem = listItems[list.currentIndex-1];
+ var listEvent = new CustomEvent('click.dl', {
+ detail: {
+ list: list,
+ selected: currentItem,
+ data: currentItem.dataset,
+ },
+ });
+ list.list.dispatchEvent(listEvent);
+ list.hide();
+ }
+
+ var keydown = function keydown(e){
+ var typedOn = e.target;
+ var list = e.detail.hook.list;
+ var currentIndex = list.currentIndex;
+ isUpArrow = false;
+ isDownArrow = false;
+
+ if(e.detail.which){
+ currentKey = e.detail.which;
+ if(currentKey === 13){
+ selectItem(e.detail.hook.list);
+ return;
+ }
+ if(currentKey === 38) {
+ isUpArrow = true;
+ }
+ if(currentKey === 40) {
+ isDownArrow = true;
+ }
+ } else if(e.detail.key) {
+ currentKey = e.detail.key;
+ if(currentKey === 'Enter'){
+ selectItem(e.detail.hook.list);
+ return;
+ }
+ if(currentKey === 'ArrowUp') {
+ isUpArrow = true;
+ }
+ if(currentKey === 'ArrowDown') {
+ isDownArrow = true;
+ }
+ }
+ if(isUpArrow){ currentIndex--; }
+ if(isDownArrow){ currentIndex++; }
+ if(currentIndex < 0){ currentIndex = 0; }
+ list.currentIndex = currentIndex;
+ setMenuForArrows(e.detail.hook.list);
+ };
+
+ document.addEventListener('mousedown.dl', mousedown);
+ document.addEventListener('keydown.dl', keydown);
+};
+
+export default Keyboard;
diff --git a/app/assets/javascripts/droplab/plugins/ajax.js b/app/assets/javascripts/droplab/plugins/ajax.js
new file mode 100644
index 00000000000..12afe53ed76
--- /dev/null
+++ b/app/assets/javascripts/droplab/plugins/ajax.js
@@ -0,0 +1,65 @@
+/* eslint-disable */
+
+const Ajax = {
+ _loadUrlData: function _loadUrlData(url) {
+ var self = this;
+ return new Promise(function(resolve, reject) {
+ var xhr = new XMLHttpRequest;
+ xhr.open('GET', url, true);
+ xhr.onreadystatechange = function () {
+ if(xhr.readyState === XMLHttpRequest.DONE) {
+ if (xhr.status === 200) {
+ var data = JSON.parse(xhr.responseText);
+ self.cache[url] = data;
+ return resolve(data);
+ } else {
+ return reject([xhr.responseText, xhr.status]);
+ }
+ }
+ };
+ xhr.send();
+ });
+ },
+ _loadData: function _loadData(data, config, self) {
+ if (config.loadingTemplate) {
+ var dataLoadingTemplate = self.hook.list.list.querySelector('[data-loading-template]');
+ if (dataLoadingTemplate) dataLoadingTemplate.outerHTML = self.listTemplate;
+ }
+
+ if (!self.destroyed) self.hook.list[config.method].call(self.hook.list, data);
+ },
+ init: function init(hook) {
+ var self = this;
+ self.destroyed = false;
+ self.cache = self.cache || {};
+ var config = hook.config.Ajax;
+ this.hook = hook;
+ if (!config || !config.endpoint || !config.method) {
+ return;
+ }
+ if (config.method !== 'setData' && config.method !== 'addData') {
+ return;
+ }
+ if (config.loadingTemplate) {
+ var dynamicList = hook.list.list.querySelector('[data-dynamic]');
+ var loadingTemplate = document.createElement('div');
+ loadingTemplate.innerHTML = config.loadingTemplate;
+ loadingTemplate.setAttribute('data-loading-template', '');
+ this.listTemplate = dynamicList.outerHTML;
+ dynamicList.outerHTML = loadingTemplate.outerHTML;
+ }
+ if (self.cache[config.endpoint]) {
+ self._loadData(self.cache[config.endpoint], config, self);
+ } else {
+ this._loadUrlData(config.endpoint)
+ .then(function(d) {
+ self._loadData(d, config, self);
+ }, config.onError).catch(config.onError);
+ }
+ },
+ destroy: function() {
+ this.destroyed = true;
+ }
+};
+
+export default Ajax;
diff --git a/app/assets/javascripts/droplab/plugins/ajax_filter.js b/app/assets/javascripts/droplab/plugins/ajax_filter.js
new file mode 100644
index 00000000000..cfd7e2ca189
--- /dev/null
+++ b/app/assets/javascripts/droplab/plugins/ajax_filter.js
@@ -0,0 +1,133 @@
+/* eslint-disable */
+
+const AjaxFilter = {
+ init: function(hook) {
+ this.destroyed = false;
+ this.hook = hook;
+ this.notLoading();
+
+ this.eventWrapper = {};
+ this.eventWrapper.debounceTrigger = this.debounceTrigger.bind(this);
+ this.hook.trigger.addEventListener('keydown.dl', this.eventWrapper.debounceTrigger);
+ this.hook.trigger.addEventListener('focus', this.eventWrapper.debounceTrigger);
+
+ this.trigger(true);
+ },
+
+ notLoading: function notLoading() {
+ this.loading = false;
+ },
+
+ debounceTrigger: function debounceTrigger(e) {
+ var NON_CHARACTER_KEYS = [16, 17, 18, 20, 37, 38, 39, 40, 91, 93];
+ var invalidKeyPressed = NON_CHARACTER_KEYS.indexOf(e.detail.which || e.detail.keyCode) > -1;
+ var focusEvent = e.type === 'focus';
+ if (invalidKeyPressed || this.loading) {
+ return;
+ }
+ if (this.timeout) {
+ clearTimeout(this.timeout);
+ }
+ this.timeout = setTimeout(this.trigger.bind(this, focusEvent), 200);
+ },
+
+ trigger: function trigger(getEntireList) {
+ var config = this.hook.config.AjaxFilter;
+ var searchValue = this.trigger.value;
+ if (!config || !config.endpoint || !config.searchKey) {
+ return;
+ }
+ if (config.searchValueFunction) {
+ searchValue = config.searchValueFunction();
+ }
+ if (config.loadingTemplate && this.hook.list.data === undefined ||
+ this.hook.list.data.length === 0) {
+ var dynamicList = this.hook.list.list.querySelector('[data-dynamic]');
+ var loadingTemplate = document.createElement('div');
+ loadingTemplate.innerHTML = config.loadingTemplate;
+ loadingTemplate.setAttribute('data-loading-template', true);
+ this.listTemplate = dynamicList.outerHTML;
+ dynamicList.outerHTML = loadingTemplate.outerHTML;
+ }
+ if (getEntireList) {
+ searchValue = '';
+ }
+ if (config.searchKey === searchValue) {
+ return this.list.show();
+ }
+ this.loading = true;
+ var params = config.params || {};
+ params[config.searchKey] = searchValue;
+ var self = this;
+ self.cache = self.cache || {};
+ var url = config.endpoint + this.buildParams(params);
+ var urlCachedData = self.cache[url];
+ if (urlCachedData) {
+ self._loadData(urlCachedData, config, self);
+ } else {
+ this._loadUrlData(url)
+ .then(function(data) {
+ self._loadData(data, config, self);
+ }, config.onError).catch(config.onError);
+ }
+ },
+
+ _loadUrlData: function _loadUrlData(url) {
+ var self = this;
+ return new Promise(function(resolve, reject) {
+ var xhr = new XMLHttpRequest;
+ xhr.open('GET', url, true);
+ xhr.onreadystatechange = function () {
+ if(xhr.readyState === XMLHttpRequest.DONE) {
+ if (xhr.status === 200) {
+ var data = JSON.parse(xhr.responseText);
+ self.cache[url] = data;
+ return resolve(data);
+ } else {
+ return reject([xhr.responseText, xhr.status]);
+ }
+ }
+ };
+ xhr.send();
+ });
+ },
+
+ _loadData: function _loadData(data, config, self) {
+ const list = self.hook.list;
+ if (config.loadingTemplate && list.data === undefined ||
+ list.data.length === 0) {
+ const dataLoadingTemplate = list.list.querySelector('[data-loading-template]');
+ if (dataLoadingTemplate) {
+ dataLoadingTemplate.outerHTML = self.listTemplate;
+ }
+ }
+ if (!self.destroyed) {
+ var hookListChildren = list.list.children;
+ var onlyDynamicList = hookListChildren.length === 1 && hookListChildren[0].hasAttribute('data-dynamic');
+ if (onlyDynamicList && data.length === 0) {
+ list.hide();
+ }
+ list.setData.call(list, data);
+ }
+ self.notLoading();
+ list.currentIndex = 0;
+ },
+
+ buildParams: function(params) {
+ if (!params) return '';
+ var paramsArray = Object.keys(params).map(function(param) {
+ return param + '=' + (params[param] || '');
+ });
+ return '?' + paramsArray.join('&');
+ },
+
+ destroy: function destroy() {
+ if (this.timeout)clearTimeout(this.timeout);
+ this.destroyed = true;
+
+ this.hook.trigger.removeEventListener('keydown.dl', this.eventWrapper.debounceTrigger);
+ this.hook.trigger.removeEventListener('focus', this.eventWrapper.debounceTrigger);
+ }
+};
+
+export default AjaxFilter;
diff --git a/app/assets/javascripts/droplab/plugins/filter.js b/app/assets/javascripts/droplab/plugins/filter.js
new file mode 100644
index 00000000000..d6a1aadd49c
--- /dev/null
+++ b/app/assets/javascripts/droplab/plugins/filter.js
@@ -0,0 +1,95 @@
+/* eslint-disable */
+
+const Filter = {
+ keydown: function(e){
+ if (this.destroyed) return;
+
+ var hiddenCount = 0;
+ var dataHiddenCount = 0;
+
+ var list = e.detail.hook.list;
+ var data = list.data;
+ var value = e.detail.hook.trigger.value.toLowerCase();
+ var config = e.detail.hook.config.Filter;
+ var matches = [];
+ var filterFunction;
+ // will only work on dynamically set data
+ if(!data){
+ return;
+ }
+
+ if (config && config.filterFunction && typeof config.filterFunction === 'function') {
+ filterFunction = config.filterFunction;
+ } else {
+ filterFunction = function(o){
+ // cheap string search
+ o.droplab_hidden = o[config.template].toLowerCase().indexOf(value) === -1;
+ return o;
+ };
+ }
+
+ dataHiddenCount = data.filter(function(o) {
+ return !o.droplab_hidden;
+ }).length;
+
+ matches = data.map(function(o) {
+ return filterFunction(o, value);
+ });
+
+ hiddenCount = matches.filter(function(o) {
+ return !o.droplab_hidden;
+ }).length;
+
+ if (dataHiddenCount !== hiddenCount) {
+ list.setData(matches);
+ list.currentIndex = 0;
+ }
+ },
+
+ debounceKeydown: function debounceKeydown(e) {
+ if ([
+ 13, // enter
+ 16, // shift
+ 17, // ctrl
+ 18, // alt
+ 20, // caps lock
+ 37, // left arrow
+ 38, // up arrow
+ 39, // right arrow
+ 40, // down arrow
+ 91, // left window
+ 92, // right window
+ 93, // select
+ ].indexOf(e.detail.which || e.detail.keyCode) > -1) return;
+
+ if (this.timeout) clearTimeout(this.timeout);
+ this.timeout = setTimeout(this.keydown.bind(this, e), 200);
+ },
+
+ init: function init(hook) {
+ var config = hook.config.Filter;
+
+ if (!config || !config.template) return;
+
+ this.hook = hook;
+ this.destroyed = false;
+
+ this.eventWrapper = {};
+ this.eventWrapper.debounceKeydown = this.debounceKeydown.bind(this);
+
+ this.hook.trigger.addEventListener('keydown.dl', this.eventWrapper.debounceKeydown);
+ this.hook.trigger.addEventListener('mousedown.dl', this.eventWrapper.debounceKeydown);
+
+ this.debounceKeydown({ detail: { hook: this.hook } });
+ },
+
+ destroy: function destroy() {
+ if (this.timeout) clearTimeout(this.timeout);
+ this.destroyed = true;
+
+ this.hook.trigger.removeEventListener('keydown.dl', this.eventWrapper.debounceKeydown);
+ this.hook.trigger.removeEventListener('mousedown.dl', this.eventWrapper.debounceKeydown);
+ }
+};
+
+export default Filter;
diff --git a/app/assets/javascripts/droplab/plugins/input_setter.js b/app/assets/javascripts/droplab/plugins/input_setter.js
new file mode 100644
index 00000000000..c292cfa7b8f
--- /dev/null
+++ b/app/assets/javascripts/droplab/plugins/input_setter.js
@@ -0,0 +1,52 @@
+/* eslint-disable */
+
+const InputSetter = {
+ init(hook) {
+ this.hook = hook;
+ this.destroyed = false;
+ this.config = hook.config.InputSetter || (this.hook.config.InputSetter = {});
+
+ this.eventWrapper = {};
+
+ this.addEvents();
+ },
+
+ addEvents() {
+ this.eventWrapper.setInputs = this.setInputs.bind(this);
+ this.hook.list.list.addEventListener('click.dl', this.eventWrapper.setInputs);
+ },
+
+ removeEvents() {
+ this.hook.list.list.removeEventListener('click.dl', this.eventWrapper.setInputs);
+ },
+
+ setInputs(e) {
+ if (this.destroyed) return;
+
+ const selectedItem = e.detail.selected;
+
+ if (!Array.isArray(this.config)) this.config = [this.config];
+
+ this.config.forEach(config => this.setInput(config, selectedItem));
+ },
+
+ setInput(config, selectedItem) {
+ const input = config.input || this.hook.trigger;
+ const newValue = selectedItem.getAttribute(config.valueAttribute);
+ const inputAttribute = config.inputAttribute;
+
+ if (!newValue) return;
+
+ if (input.hasAttribute(inputAttribute)) return input.setAttribute(inputAttribute, newValue);
+ if (input.tagName === 'INPUT') return input.value = newValue;
+ return input.textContent = newValue;
+ },
+
+ destroy() {
+ this.destroyed = true;
+
+ this.removeEvents();
+ },
+};
+
+export default InputSetter;
diff --git a/app/assets/javascripts/droplab/utils.js b/app/assets/javascripts/droplab/utils.js
new file mode 100644
index 00000000000..c149a33a1e9
--- /dev/null
+++ b/app/assets/javascripts/droplab/utils.js
@@ -0,0 +1,38 @@
+/* eslint-disable */
+
+import { DATA_TRIGGER, DATA_DROPDOWN } from './constants';
+
+const utils = {
+ toCamelCase(attr) {
+ return this.camelize(attr.split('-').slice(1).join(' '));
+ },
+
+ t(s, d) {
+ for (const p in d) {
+ if (Object.prototype.hasOwnProperty.call(d, p)) {
+ s = s.replace(new RegExp(`{{${p}}}`, 'g'), d[p]);
+ }
+ }
+ return s;
+ },
+
+ camelize(str) {
+ return str.replace(/(?:^\w|[A-Z]|\b\w)/g, (letter, index) => {
+ return index === 0 ? letter.toLowerCase() : letter.toUpperCase();
+ }).replace(/\s+/g, '');
+ },
+
+ closest(thisTag, stopTag) {
+ while (thisTag && thisTag.tagName !== stopTag && thisTag.tagName !== 'HTML') {
+ thisTag = thisTag.parentNode;
+ }
+ return thisTag;
+ },
+
+ isDropDownParts(target) {
+ if (!target || target.tagName === 'HTML') return false;
+ return target.hasAttribute(DATA_TRIGGER) || target.hasAttribute(DATA_DROPDOWN);
+ },
+};
+
+export default utils;
diff --git a/app/assets/javascripts/filtered_search/dropdown_hint.js b/app/assets/javascripts/filtered_search/dropdown_hint.js
index 64d7153e547..381c40c03d8 100644
--- a/app/assets/javascripts/filtered_search/dropdown_hint.js
+++ b/app/assets/javascripts/filtered_search/dropdown_hint.js
@@ -1,13 +1,13 @@
-require('./filtered_search_dropdown');
+import Filter from '~/droplab/plugins/filter';
-/* global droplabFilter */
+require('./filtered_search_dropdown');
(() => {
class DropdownHint extends gl.FilteredSearchDropdown {
constructor(droplab, dropdown, input, filter) {
super(droplab, dropdown, input, filter);
this.config = {
- droplabFilter: {
+ Filter: {
template: 'hint',
filterFunction: gl.DropdownUtils.filterHint.bind(null, input),
},
@@ -69,12 +69,12 @@ require('./filtered_search_dropdown');
}
});
- this.droplab.changeHookList(this.hookId, this.dropdown, [droplabFilter], this.config);
+ this.droplab.changeHookList(this.hookId, this.dropdown, [Filter], this.config);
this.droplab.setData(this.hookId, dropdownData);
}
init() {
- this.droplab.addHook(this.input, this.dropdown, [droplabFilter], this.config).init();
+ this.droplab.addHook(this.input, this.dropdown, [Filter], this.config).init();
}
}
diff --git a/app/assets/javascripts/filtered_search/dropdown_non_user.js b/app/assets/javascripts/filtered_search/dropdown_non_user.js
index b3dc3e502c5..6296965b911 100644
--- a/app/assets/javascripts/filtered_search/dropdown_non_user.js
+++ b/app/assets/javascripts/filtered_search/dropdown_non_user.js
@@ -1,7 +1,9 @@
-require('./filtered_search_dropdown');
+/* global Flash */
+
+import Ajax from '~/droplab/plugins/ajax';
+import Filter from '~/droplab/plugins/filter';
-/* global droplabAjax */
-/* global droplabFilter */
+require('./filtered_search_dropdown');
(() => {
class DropdownNonUser extends gl.FilteredSearchDropdown {
@@ -9,13 +11,19 @@ require('./filtered_search_dropdown');
super(droplab, dropdown, input, filter);
this.symbol = symbol;
this.config = {
- droplabAjax: {
+ Ajax: {
endpoint,
method: 'setData',
loadingTemplate: this.loadingTemplate,
+ onError() {
+ /* eslint-disable no-new */
+ new Flash('An error occured fetching the dropdown data.');
+ /* eslint-enable no-new */
+ },
},
- droplabFilter: {
+ Filter: {
filterFunction: gl.DropdownUtils.filterWithSymbol.bind(null, this.symbol, input),
+ template: 'title',
},
};
}
@@ -29,13 +37,13 @@ require('./filtered_search_dropdown');
renderContent(forceShowList = false) {
this.droplab
- .changeHookList(this.hookId, this.dropdown, [droplabAjax, droplabFilter], this.config);
+ .changeHookList(this.hookId, this.dropdown, [Ajax, Filter], this.config);
super.renderContent(forceShowList);
}
init() {
this.droplab
- .addHook(this.input, this.dropdown, [droplabAjax, droplabFilter], this.config).init();
+ .addHook(this.input, this.dropdown, [Ajax, Filter], this.config).init();
}
}
diff --git a/app/assets/javascripts/filtered_search/dropdown_user.js b/app/assets/javascripts/filtered_search/dropdown_user.js
index 04e2afad02f..38b5d315bcf 100644
--- a/app/assets/javascripts/filtered_search/dropdown_user.js
+++ b/app/assets/javascripts/filtered_search/dropdown_user.js
@@ -1,13 +1,15 @@
-require('./filtered_search_dropdown');
+/* global Flash */
+
+import AjaxFilter from '~/droplab/plugins/ajax_filter';
-/* global droplabAjaxFilter */
+require('./filtered_search_dropdown');
(() => {
class DropdownUser extends gl.FilteredSearchDropdown {
constructor(droplab, dropdown, input, filter) {
super(droplab, dropdown, input, filter);
this.config = {
- droplabAjaxFilter: {
+ AjaxFilter: {
endpoint: `${gon.relative_url_root || ''}/autocomplete/users.json`,
searchKey: 'search',
params: {
@@ -18,6 +20,11 @@ require('./filtered_search_dropdown');
},
searchValueFunction: this.getSearchInput.bind(this),
loadingTemplate: this.loadingTemplate,
+ onError() {
+ /* eslint-disable no-new */
+ new Flash('An error occured fetching the dropdown data.');
+ /* eslint-enable no-new */
+ },
},
};
}
@@ -28,7 +35,7 @@ require('./filtered_search_dropdown');
}
renderContent(forceShowList = false) {
- this.droplab.changeHookList(this.hookId, this.dropdown, [droplabAjaxFilter], this.config);
+ this.droplab.changeHookList(this.hookId, this.dropdown, [AjaxFilter], this.config);
super.renderContent(forceShowList);
}
@@ -56,7 +63,7 @@ require('./filtered_search_dropdown');
}
init() {
- this.droplab.addHook(this.input, this.dropdown, [droplabAjaxFilter], this.config).init();
+ this.droplab.addHook(this.input, this.dropdown, [AjaxFilter], this.config).init();
}
}
diff --git a/app/assets/javascripts/filtered_search/filtered_search_dropdown.js b/app/assets/javascripts/filtered_search/filtered_search_dropdown.js
index e7bf530d343..d58eeeebf81 100644
--- a/app/assets/javascripts/filtered_search/filtered_search_dropdown.js
+++ b/app/assets/javascripts/filtered_search/filtered_search_dropdown.js
@@ -4,7 +4,7 @@
class FilteredSearchDropdown {
constructor(droplab, dropdown, input, filter) {
this.droplab = droplab;
- this.hookId = input && input.getAttribute('data-id');
+ this.hookId = input && input.id;
this.input = input;
this.filter = filter;
this.dropdown = dropdown;
diff --git a/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js b/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js
index 5fbe0450bb8..ec481b9ef97 100644
--- a/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js
+++ b/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js
@@ -1,4 +1,4 @@
-/* global DropLab */
+import DropLab from '~/droplab/drop_lab';
import FilteredSearchContainer from './container';
(() => {
diff --git a/app/assets/javascripts/filtered_search/filtered_search_manager.js b/app/assets/javascripts/filtered_search/filtered_search_manager.js
index 2a8a6b81b3f..b93a8f1d322 100644
--- a/app/assets/javascripts/filtered_search/filtered_search_manager.js
+++ b/app/assets/javascripts/filtered_search/filtered_search_manager.js
@@ -154,7 +154,7 @@ import eventHub from './event_hub';
if (e.keyCode === 13) {
const dropdown = this.dropdownManager.mapping[this.dropdownManager.currentDropdown];
const dropdownEl = dropdown.element;
- const activeElements = dropdownEl.querySelectorAll('.dropdown-active');
+ const activeElements = dropdownEl.querySelectorAll('.droplab-item-active');
e.preventDefault();
diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js
index 5b50bc62876..177cf66b37d 100644
--- a/app/assets/javascripts/main.js
+++ b/app/assets/javascripts/main.js
@@ -75,12 +75,6 @@ import './u2f/error';
import './u2f/register';
import './u2f/util';
-// droplab
-import './droplab/droplab';
-import './droplab/droplab_ajax';
-import './droplab/droplab_ajax_filter';
-import './droplab/droplab_filter';
-
// everything else
import './abuse_reports';
import './activities';
diff --git a/app/assets/stylesheets/framework/filters.scss b/app/assets/stylesheets/framework/filters.scss
index 484df6214d3..12465d4a70b 100644
--- a/app/assets/stylesheets/framework/filters.scss
+++ b/app/assets/stylesheets/framework/filters.scss
@@ -446,10 +446,8 @@
}
}
-.filter-dropdown-item.dropdown-active {
- .btn {
- @extend %filter-dropdown-item-btn-hover;
- }
+.filter-dropdown-item.droplab-item-active .btn {
+ @extend %filter-dropdown-item-btn-hover;
}
.filter-dropdown-loading {
diff --git a/app/views/shared/issuable/_search_bar.html.haml b/app/views/shared/issuable/_search_bar.html.haml
index 9e241c3ea12..b447996a8ab 100644
--- a/app/views/shared/issuable/_search_bar.html.haml
+++ b/app/views/shared/issuable/_search_bar.html.haml
@@ -23,7 +23,7 @@
.scroll-container
%ul.tokens-container.list-unstyled
%li.input-token
- %input.form-control.filtered-search{ placeholder: 'Search or filter results...', data: { id: "filtered-search-#{type.to_s}", 'project-id' => @project.id, 'username-params' => @users.to_json(only: [:id, :username]), 'base-endpoint' => namespace_project_path(@project.namespace, @project) } }
+ %input.form-control.filtered-search{ id: "filtered-search-#{type.to_s}", placeholder: 'Search or filter results...', data: { 'project-id' => @project.id, 'username-params' => @users.to_json(only: [:id, :username]), 'base-endpoint' => namespace_project_path(@project.namespace, @project) } }
= icon('filter')
%button.clear-search.hidden{ type: 'button' }
= icon('times')