UNPKG

metro4

Version:

The front-end framework for Build responsive, mobile-first projects on the web with the first front-end component library in Metro Style

561 lines (447 loc) 17.6 kB
/* global Metro */ (function(Metro, $) { 'use strict'; var Utils = Metro.utils; var TagInputDefaultConfig = { autocomplete: null, autocompleteUnique: true, autocompleteUrl: null, autocompleteUrlMethod: "GET", autocompleteUrlKey: null, autocompleteDivider: ",", autocompleteListHeight: 200, label: "", size: "normal", taginputDeferred: 0, static: false, clearButton: true, clearButtonIcon: "<span class='default-icon-cross'></span>", randomColor: false, maxTags: 0, tagSeparator: ",", tagTrigger: "Enter, Space, Comma", backspace: true, clsComponent: "", clsInput: "", clsClearButton: "", clsTag: "", clsTagTitle: "", clsTagRemover: "", clsLabel: "", onBeforeTagAdd: Metro.noop_true, onTagAdd: Metro.noop, onBeforeTagRemove: Metro.noop_true, onTagRemove: Metro.noop, onTag: Metro.noop, onClear: Metro.noop, onTagTrigger: Metro.noop, onTagInputCreate: Metro.noop }; Metro.tagInputSetup = function (options) { TagInputDefaultConfig = $.extend({}, TagInputDefaultConfig, options); }; if (typeof window["metroTagInputSetup"] !== undefined) { Metro.tagInputSetup(window["metroTagInputSetup"]); } Metro.Component('tag-input', { init: function( options, elem ) { this._super(elem, options, TagInputDefaultConfig, { values: [], triggers: [], autocomplete: [] }); return this; }, _create: function(){ this.triggers = (""+this.options.tagTrigger).toArray(","); if (this.triggers.includes("Space") || this.triggers.includes("Spacebar")) { this.triggers.push(" "); this.triggers.push("Spacebar"); } if (this.triggers.includes("Comma")) { this.triggers.push(","); } this._createStructure(); this._createEvents(); this._fireEvent("tag-input-create", { element: this.element }); }, _createStructure: function(){ var that = this, element = this.element, o = this.options; var container, input, clearButton; var values = element.val().trim(); container = $("<div>").addClass("tag-input " + element[0].className).addClass(o.clsComponent).insertBefore(element); element.appendTo(container); container.addClass("input-" + o.size) element[0].className = ""; element.addClass("original-input"); input = $("<input type='text'>").addClass("input-wrapper").addClass(o.clsInput).attr("size", 1); input.appendTo(container); if (o.clearButton !== false && !element[0].readOnly) { container.addClass("padding-for-clear"); clearButton = $("<button>").addClass("button input-clear-button").attr("tabindex", -1).attr("type", "button").html(o.clearButtonIcon); clearButton.appendTo(container); } if (Utils.isValue(values)) { $.each(values.toArray(o.tagSeparator), function(){ that._addTag(this); }) } if (o.label) { var label = $("<label>").addClass("label-for-input").addClass(o.clsLabel).html(o.label).insertBefore(container); if (element.attr("id")) { label.attr("for", element.attr("id")); } if (element.attr("dir") === "rtl") { label.addClass("rtl"); } } if (element.is(":disabled")) { this.disable(); } else { this.enable(); } if (o.static === true || element.attr("readonly") !== undefined) { container.addClass("static-mode"); } if (!Utils.isNull(o.autocomplete) || !Utils.isNull(o.autocompleteUrl)) { $("<div>").addClass("autocomplete-list").css({ maxHeight: o.autocompleteListHeight, display: "none" }).appendTo(container); } if (Utils.isValue(o.autocomplete)) { var autocomplete_obj = Utils.isObject(o.autocomplete); if (autocomplete_obj !== false) { this.autocomplete = autocomplete_obj; } else { this.autocomplete = o.autocomplete.toArray(o.autocompleteDivider); } } if (Utils.isValue(o.autocompleteUrl)) { fetch(o.autocompleteUrl, { method: o.autocompleteUrlMethod }).then(function(response){ return response.text() }).then(function(data){ var newData = []; try { newData = JSON.parse(data); if (o.autocompleteUrlKey) { newData = newData[o.autocompleteUrlKey]; } } catch (e) { newData = data.split("\n"); } that.autocomplete = that.autocomplete.concat(newData); }); } }, _createEvents: function(){ var that = this, element = this.element, o = this.options; var container = element.closest(".tag-input"); var input = container.find(".input-wrapper"); var autocompleteList = container.find(".autocomplete-list"); input.on(Metro.events.focus, function(){ container.addClass("focused"); }); input.on(Metro.events.blur, function(){ container.removeClass("focused"); }); input.on(Metro.events.inputchange, function(){ input.attr("size", Math.ceil(input.val().length / 2) + 2); }); input.on(Metro.events.keydown, function(e){ var val = input.val().trim(); var key = e.key; if (key === "Enter") e.preventDefault(); if (o.backspace === true && key === "Backspace" && val.length === 0) { if (that.values.length > 0) { that.values.splice(-1,1); element.siblings(".tag").last().remove(); element.val(that.values.join(o.tagSeparator)); } return ; } if (val === "") {return ;} if (!that.triggers.includes(key)) { return ; } that._fireEvent("tag-trigger", { key: key }); input.val(""); that._addTag(val); input.attr("size", 1); }); input.on(Metro.events.keyup, function(e){ var val = input.val(); var key = e.key; if (that.triggers.includes(key) && val[val.length - 1] === key) { input.val(val.slice(0, -1)); } }); container.on(Metro.events.click, ".tag .remover", function(){ var tag = $(this).closest(".tag"); that._delTag(tag); }); container.on(Metro.events.click, function(){ input.focus(); }); container.on(Metro.events.click, ".input-clear-button", function(){ var val = element.val(); that.clear(); that._fireEvent("clear", { val: val }); }); input.on(Metro.events.input, function(){ var val = this.value.toLowerCase(); that._drawAutocompleteList(val); }); container.on(Metro.events.click, ".autocomplete-list .item", function(){ var val = $(this).attr("data-autocomplete-value"); input.val(""); that._addTag(val); input.attr("size", 1); autocompleteList.css({ display: "none" }); that._fireEvent("autocomplete-select", { value: val }); }); }, _drawAutocompleteList: function(val){ var that = this, element = this.element, o = this.options; var container = element.closest(".tag-input"); var input = container.find(".input-wrapper"); var autocompleteList = container.find(".autocomplete-list"); var items; if (autocompleteList.length === 0) { return; } autocompleteList.html(""); items = this.autocomplete.filter(function(item){ return item.toLowerCase().indexOf(val) > -1; }); autocompleteList.css({ display: items.length > 0 ? "block" : "none", left: input.position().left }); $.each(items, function(){ if (o.autocompleteUnique && that.values.indexOf(this) !== -1) { return ; } var v = this; var index = v.toLowerCase().indexOf(val), content; var item = $("<div>").addClass("item").attr("data-autocomplete-value", v); if (index === 0) { content = "<strong>"+v.substr(0, val.length)+"</strong>"+v.substr(val.length); } else { content = v.substr(0, index) + "<strong>"+v.substr(index, val.length)+"</strong>"+v.substr(index + val.length); } item.html(content).appendTo(autocompleteList); that._fireEvent("draw-autocomplete-item", { item: item }) }); }, _addTag: function(val){ var element = this.element, o = this.options; var container = element.closest(".tag-input"); var input = container.find(".input-wrapper"); var tag, title, remover; var tagSize, tagStatic; if (container.hasClass("input-large")) { tagSize = "large"; } else if (container.hasClass("input-small")) { tagSize = "small" } if (o.maxTags > 0 && this.values.length === o.maxTags) { return ; } if ((""+val).trim() === "") { return ; } if (!Utils.exec(o.onBeforeTagAdd, [val, this.values], element[0])) { return ; } tag = $("<span>") .addClass("tag") .addClass(tagSize) .addClass(o.clsTag) .insertBefore(input); tag.data("value", val); tagStatic = o.static || container.hasClass("static-mode") || element.readonly || element.disabled || container.hasClass("disabled"); if (tagStatic) { tag.addClass("static"); } title = $("<span>").addClass("title").addClass(o.clsTagTitle).html(val); remover = $("<span>").addClass("remover").addClass(o.clsTagRemover).html("&times;"); title.appendTo(tag); remover.appendTo(tag); if (o.randomColor === true) { var colors = Metro.colors.colors(Metro.colors.PALETTES.ALL), bg, fg, bg_r; bg = colors[$.random(0, colors.length - 1)]; bg_r = Metro.colors.darken(bg, 15); fg = Metro.colors.isDark(bg) ? "#ffffff" : "#000000"; tag.css({ backgroundColor: bg, color: fg }); remover.css({ backgroundColor: bg_r, color: fg }); } this.values.push(val); element.val(this.values.join(o.tagSeparator)); this._fireEvent("tag-add", { tag: tag[0], val: val, values: this.values }); this._fireEvent("tag", { tag: tag[0], val: val, values: this.values }); }, _delTag: function(tag) { var element = this.element, o = this.options; var val = tag.data("value"); if (!Utils.exec(o.onBeforeTagRemove, [tag, val, this.values], element[0])) { return ; } Utils.arrayDelete(this.values, val); element.val(this.values.join(o.tagSeparator)); this._fireEvent("tag-remove", { tag: tag[0], val: val, values: this.values }); this._fireEvent("tag", { tag: tag[0], val: val, values: this.values }); tag.remove(); }, tags: function(){ return this.values; }, val: function(v){ var that = this, element = this.element, o = this.options; var container = element.closest(".tag-input"); var newValues = []; if (!Utils.isValue(v)) { return this.tags(); } this.values = []; container.find(".tag").remove(); if (typeof v === "string") { newValues = (""+v).toArray(o.tagSeparator); } else { if (Array.isArray(v)) { newValues = v; } } $.each(newValues, function(){ that._addTag(this); }); return this; }, append: function(v){ var that = this, o = this.options; var newValues = this.values; if (typeof v === "string") { newValues = (""+v).toArray(o.tagSeparator); } else { if (Array.isArray(v)) { newValues = v; } } $.each(newValues, function(){ that._addTag(this); }); return this; }, clear: function(){ var element = this.element; var container = element.closest(".tag-input"); this.values = []; element.val("").trigger("change"); container.find(".tag").remove(); return this; }, disable: function(){ this.element.data("disabled", true); this.element.parent().addClass("disabled"); }, enable: function(){ this.element.data("disabled", false); this.element.parent().removeClass("disabled"); }, toggleState: function(){ if (this.elem.disabled) { this.disable(); } else { this.enable(); } }, toggleStatic: function(val){ var container = this.element.closest(".tag-input"); var staticMode; if (Utils.isValue(val)) { staticMode = Utils.bool(val); } else { staticMode = !container.hasClass("static-mode"); } if (staticMode) { container.addClass("static-mode"); } else { container.removeClass("static-mode"); } }, setAutocompleteList: function(l){ var autocomplete_list = Utils.isObject(l); if (autocomplete_list !== false) { this.autocomplete = autocomplete_list; } else if (typeof l === "string") { this.autocomplete = l.toArray(this.options.autocompleteDivider); } }, changeAttribute: function(attributeName){ var that = this, element = this.element, o = this.options; var changeValue = function(){ var val = element.attr("value").trim(); that.clear(); if (!Utils.isValue(val)) { return ; } that.val(val.toArray(o.tagSeparator)); }; switch (attributeName) { case "value": changeValue(); break; case "disabled": this.toggleState(); break; case "static": this.toggleStatic(); break; } }, destroy: function(){ var element = this.element; var container = element.closest(".tag-input"); var input = container.find(".input-wrapper"); input.off(Metro.events.focus); input.off(Metro.events.blur); input.off(Metro.events.keydown); container.off(Metro.events.click, ".tag .remover"); container.off(Metro.events.click); return element; } }); $(document).on(Metro.events.click, function(){ $('.tag-input .autocomplete-list').hide(); }); }(Metro, m4q));