/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
(function ($) {
"use strict";
/*global document, window, jQuery, console */
var KEY, Util, DropDown, ResultList, Selection, Select2, Queries;
function createClass(def) {
var type = function (attrs) {
var self = this;
if (def.attrs !== undefined) {
$.each(def.attrs, function (name, body) {
if (attrs[name] !== undefined) {
self[name] = attrs[name];
} else {
if (body.required === true) {
throw "Value for required attribute: " + name + " not defined";
}
if (body.init !== undefined) {
self[name] = typeof (body.init) === "function" ? body.init.apply(self) : body.init;
}
}
});
}
if (def.methods !== undefined && def.methods.init !== undefined) {
self.init(attrs);
}
};
if (def.methods !== undefined) {
if (def.methods.bind !== undefined) {
throw "Class cannot declare a method called 'bind'";
}
$.each(def.methods, function (name, body) {
type.prototype[name] = body;
});
type.prototype.bind = function (func) {
var self = this;
return function () {
func.apply(self, arguments);
};
};
}
return type;
}
KEY = {
TAB: 9,
ENTER: 13,
ESC: 27,
SPACE: 32,
LEFT: 37,
UP: 38,
RIGHT: 39,
DOWN: 40,
SHIFT: 16,
CTRL: 17,
ALT: 18,
PAGE_UP: 33,
PAGE_DOWN: 34,
HOME: 36,
END: 35,
BACKSPACE: 8,
DELETE: 46
};
Util = {};
Util.debounce = function (threshold, fn) {
var timeout;
return function () {
window.clearTimeout(timeout);
timeout = window.setTimeout(fn, threshold);
};
};
Util.debounceEvent = function (element, threshold, event, debouncedEvent, direct) {
debouncedEvent = debouncedEvent || event + "-debounced";
direct = direct || true;
var notify = Util.debounce(threshold, function (e) {
element.trigger(debouncedEvent, e);
});
element.on(event, function (e) {
if (direct && element.get().indexOf(e.target) < 0) {
return;
}
notify(e);
});
};
(function () {
var lastpos;
/**
* Filters mouse events so an event is fired only if the mouse moved.
* Filters out mouse events that occur when mouse is stationary but
* the elements under the pointer are scrolled
*/
Util.filterMouseEvent = function (element, event, filteredEvent, direct) {
filteredEvent = filteredEvent || event + "-filtered";
direct = direct || false;
element.on(event, "*", function (e) {
if (direct && element.get().indexOf(e.target) < 0) {
return;
}
if (lastpos === undefined || lastpos.x !== e.pageX || lastpos.y !== e.pageY) {
$(e.target).trigger(filteredEvent, e);
lastpos = {x: e.pageX, y: e.pageY};
}
});
};
}());
DropDown = createClass({
attrs: {
container: {required: true},
element: {required: true},
bus: {required: true}
},
methods: {
open: function () {
if (this.isOpen()) {
return;
}
this.container.addClass("select2-dropdown-open");
// register click-outside-closes-dropdown listener
$(document).on("mousedown.dropdown", this.bind(function (e) {
var inside = false,
container = this.container.get(0);
$(e.target).parents().each(function () {
return !(inside = (this === container));
});
if (!inside) {
this.close();
}
}));
this.element.show();
this.bus.trigger("opened");
},
close: function () {
if (!this.isOpen()) {
return;
}
this.container.removeClass("select2-dropdown-open");
$(document).off("mousedown.dropdown");
this.element.hide();
this.bus.trigger("closed");
},
isOpen: function () {
return this.container.hasClass("select2-dropdown-open");
},
toggle: function () {
if (this.isOpen()) {
this.close();
} else {
this.open();
}
}
}
});
ResultList = createClass({
attrs: {
element: {required: true},
bus: {required: true},
formatInputTooShort: {required: true},
formatNoMatches: {required: true},
formatResult: {required: true},
minimumInputLength: {required: true},
query: {required: true},
selection: {required: true}
},
methods: {
init: function () {
var self = this;
this.search = this.element.find("input");
this.results = this.element.find("ul");
this.scrollPosition = 0;
this.vars = {};
this.search.on("keyup", function (e) {
if (e.which >= 48 || e.which === KEY.SPACE || e.which === KEY.BACKSPACE || e.which === KEY.DELETE) {
self.update();
}
});
this.search.on("keydown", function (e) {
switch (e.which) {
case KEY.TAB:
e.preventDefault();
self.select();
return;
case KEY.ENTER:
e.preventDefault();
e.stopPropagation();
self.select();
return;
case KEY.UP:
self.moveSelection(-1);
e.preventDefault();
e.stopPropagation();
return;
case KEY.DOWN:
self.moveSelection(1);
e.preventDefault();
e.stopPropagation();
return;
case KEY.ESC:
e.preventDefault();
e.stopPropagation();
self.cancel();
return;
}
});
// this.results.on("mouseleave", "li.select2-result", this.bind(this.unhighlight));
Util.filterMouseEvent(this.results, "mousemove");
this.results.on("mousemove-filtered", this.bind(function (e) {
var el = $(e.target).closest("li.select2-result");
if (el.length < 1) {
return;
}
this.setSelection(el.index());
}));
this.results.on("click", this.bind(function (e) {
var el = $(e.target).closest("li.select2-result");
if (el.length < 1) {
return;
}
this.bus.trigger("selected", [el.data("select2-result")]);
}));
Util.debounceEvent(this.results, 100, "scroll");
this.results.on("scroll-debounced", this.bind(function (e) {
this.scrollPosition = this.results.scrollTop();
var more = this.results.find("li.select2-more-results"), below;
if (more.length === 0) {
return;
}
// pixels the element is below the scroll fold, below==0 is when the element is starting to be visible
below = more.offset().top - this.results.offset().top - this.results.height();
if (below <= 0) {
more.addClass("select2-active");
this.query({term: this.search.val(), vars: this.vars, callback: this.bind(this.append)});
}
}));
},
open: function (e) {
this.search.focus();
this.results.scrollTop(this.scrollPosition);
if (this.results.children().length === 0) {
// first time the dropdown is opened, update the results
this.update();
}
},
close: function () {
//this.search.val("");
//this.clear();
},
clear: function () {
this.results.empty();
},
showInputTooShort: function () {
this.show("