From f791ba634e733811b3e10bb662e30cd5ba0b29e3 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Tue, 7 Jun 2016 16:12:12 +0200 Subject: [PATCH] Edit link WIP + upgrade awesomplete --- inc/awesomplete-multiple-tags.js | 21 +- inc/awesomplete.js | 759 +++++++++++++++++-------------- inc/awesomplete.min.js | 20 +- plugins/markdown/markdown.css | 4 - tpl/default/editlink.html | 82 ++++ 5 files changed, 510 insertions(+), 376 deletions(-) create mode 100644 tpl/default/editlink.html diff --git a/inc/awesomplete-multiple-tags.js b/inc/awesomplete-multiple-tags.js index 4cc8429f..faecb417 100644 --- a/inc/awesomplete-multiple-tags.js +++ b/inc/awesomplete-multiple-tags.js @@ -1,13 +1,16 @@ var awp = Awesomplete.$; -awesomplete = new Awesomplete(awp('input[data-multiple]'), { - filter: function(text, input) { - return Awesomplete.FILTER_CONTAINS(text, input.match(/[^ ]*$/)[0]); - }, - replace: function(text) { - var before = this.input.value.match(/^.+ \s*|/)[0]; - this.input.value = before + text + " "; - }, - minChars: 1 +var autocompleteFields = document.querySelectorAll('input[data-multiple]'); +[].forEach.call(autocompleteFields, function(autocompleteField) { + awesomplete = new Awesomplete(awp(autocompleteField), { + filter: function (text, input) { + return Awesomplete.FILTER_CONTAINS(text, input.match(/[^ ]*$/)[0]); + }, + replace: function (text) { + var before = this.input.value.match(/^.+ \s*|/)[0]; + this.input.value = before + text + " "; + }, + minChars: 1 + }) }); /** diff --git a/inc/awesomplete.js b/inc/awesomplete.js index fae550e2..7303652a 100644 --- a/inc/awesomplete.js +++ b/inc/awesomplete.js @@ -7,382 +7,433 @@ (function () { - var _ = function (input, o) { - var me = this; - - // Setup - - this.input = $(input); - this.input.setAttribute("aria-autocomplete", "list"); - - o = o || {}; - - configure.call(this, { - minChars: 2, - maxItems: 10, - autoFirst: false, - filter: _.FILTER_CONTAINS, - sort: _.SORT_BYLENGTH, - item: function (text, input) { - return $.create("li", { - innerHTML: text.replace(RegExp($.regExpEscape(input.trim()), "gi"), "$&"), - "aria-selected": "false" - }); - }, - replace: function (text) { - this.input.value = text; - } - }, o); - - this.index = -1; - - // Create necessary elements - - this.container = $.create("div", { - className: "awesomplete", - around: input - }); - - this.ul = $.create("ul", { - hidden: "", - inside: this.container - }); - - this.status = $.create("span", { - className: "visually-hidden", - role: "status", - "aria-live": "assertive", - "aria-relevant": "additions", - inside: this.container - }); - - // Bind events - - $.bind(this.input, { - "input": this.evaluate.bind(this), - "blur": this.close.bind(this), - "keydown": function(evt) { - var c = evt.keyCode; - - // If the dropdown `ul` is in view, then act on keydown for the following keys: - // Enter / Esc / Up / Down - if(me.opened) { - if (c === 13 && me.selected) { // Enter - evt.preventDefault(); - me.select(); - } - else if (c === 27) { // Esc - me.close(); - } - else if (c === 38 || c === 40) { // Down/Up arrow - evt.preventDefault(); - me[c === 38? "previous" : "next"](); - } - } - } - }); - - $.bind(this.input.form, {"submit": this.close.bind(this)}); - - $.bind(this.ul, {"mousedown": function(evt) { - var li = evt.target; - - if (li !== this) { - - while (li && !/li/i.test(li.nodeName)) { - li = li.parentNode; - } - - if (li) { - me.select(li); - } - } - }}); - - if (this.input.hasAttribute("list")) { - this.list = "#" + input.getAttribute("list"); - input.removeAttribute("list"); - } - else { - this.list = this.input.getAttribute("data-list") || o.list || []; - } - - _.all.push(this); - }; - - _.prototype = { - set list(list) { - if (Array.isArray(list)) { - this._list = list; - } - else if (typeof list === "string" && list.indexOf(",") > -1) { - this._list = list.split(/\s*,\s*/); - } - else { // Element or CSS selector - list = $(list); - - if (list && list.children) { - this._list = slice.apply(list.children).map(function (el) { - return el.innerHTML.trim(); - }); - } - } - - if (document.activeElement === this.input) { - this.evaluate(); - } - }, - - get selected() { - return this.index > -1; - }, - - get opened() { - return this.ul && this.ul.getAttribute("hidden") == null; - }, - - close: function () { - this.ul.setAttribute("hidden", ""); - this.index = -1; - - $.fire(this.input, "awesomplete-close"); - }, - - open: function () { - this.ul.removeAttribute("hidden"); - - if (this.autoFirst && this.index === -1) { - this.goto(0); - } - - $.fire(this.input, "awesomplete-open"); - }, - - next: function () { - var count = this.ul.children.length; - - this.goto(this.index < count - 1? this.index + 1 : -1); - }, - - previous: function () { - var count = this.ul.children.length; - - this.goto(this.selected? this.index - 1 : count - 1); - }, - - // Should not be used, highlights specific item without any checks! - goto: function (i) { - var lis = this.ul.children; - - if (this.selected) { - lis[this.index].setAttribute("aria-selected", "false"); - } - - this.index = i; - - if (i > -1 && lis.length > 0) { - lis[i].setAttribute("aria-selected", "true"); - this.status.textContent = lis[i].textContent; - } - - $.fire(this.input, "awesomplete-highlight"); - }, - - select: function (selected) { - selected = selected || this.ul.children[this.index]; - - if (selected) { - var prevented; - - $.fire(this.input, "awesomplete-select", { - text: selected.textContent, - preventDefault: function () { - prevented = true; - } - }); - - if (!prevented) { - this.replace(selected.textContent); - this.close(); - $.fire(this.input, "awesomplete-selectcomplete"); - } - } - }, - - evaluate: function() { - var me = this; - var value = this.input.value; - - if (value.length >= this.minChars && this._list.length > 0) { - this.index = -1; - // Populate list with options that match - this.ul.innerHTML = ""; - - this._list - .filter(function(item) { - return me.filter(item, value); - }) - .sort(this.sort) - .every(function(text, i) { - me.ul.appendChild(me.item(text, value)); - - return i < me.maxItems - 1; - }); - - if (this.ul.children.length === 0) { - this.close(); - } else { - this.open(); - } - } - else { - this.close(); - } - } - }; +var _ = function (input, o) { + var me = this; + + // Setup + + this.input = $(input); + this.input.setAttribute("autocomplete", "off"); + this.input.setAttribute("aria-autocomplete", "list"); + + o = o || {}; + + configure(this, { + minChars: 2, + maxItems: 10, + autoFirst: false, + data: _.DATA, + filter: _.FILTER_CONTAINS, + sort: _.SORT_BYLENGTH, + item: _.ITEM, + replace: _.REPLACE + }, o); + + this.index = -1; + + // Create necessary elements + + this.container = $.create("div", { + className: "awesomplete", + around: input + }); + + this.ul = $.create("ul", { + hidden: "hidden", + inside: this.container + }); + + this.status = $.create("span", { + className: "visually-hidden", + role: "status", + "aria-live": "assertive", + "aria-relevant": "additions", + inside: this.container + }); + + // Bind events + + $.bind(this.input, { + "input": this.evaluate.bind(this), + "blur": this.close.bind(this), + "keydown": function(evt) { + var c = evt.keyCode; + + // If the dropdown `ul` is in view, then act on keydown for the following keys: + // Enter / Esc / Up / Down + if(me.opened) { + if (c === 13 && me.selected) { // Enter + evt.preventDefault(); + me.select(); + } + else if (c === 27) { // Esc + me.close(); + } + else if (c === 38 || c === 40) { // Down/Up arrow + evt.preventDefault(); + me[c === 38? "previous" : "next"](); + } + } + } + }); + + $.bind(this.input.form, {"submit": this.close.bind(this)}); + + $.bind(this.ul, {"mousedown": function(evt) { + var li = evt.target; + + if (li !== this) { + + while (li && !/li/i.test(li.nodeName)) { + li = li.parentNode; + } + + if (li && evt.button === 0) { // Only select on left click + evt.preventDefault(); + me.select(li, evt.target); + } + } + }}); + + if (this.input.hasAttribute("list")) { + this.list = "#" + this.input.getAttribute("list"); + this.input.removeAttribute("list"); + } + else { + this.list = this.input.getAttribute("data-list") || o.list || []; + } + + _.all.push(this); +}; + +_.prototype = { + set list(list) { + if (Array.isArray(list)) { + this._list = list; + } + else if (typeof list === "string" && list.indexOf(",") > -1) { + this._list = list.split(/\s*,\s*/); + } + else { // Element or CSS selector + list = $(list); + + if (list && list.children) { + var items = []; + slice.apply(list.children).forEach(function (el) { + if (!el.disabled) { + var text = el.textContent.trim(); + var value = el.value || text; + var label = el.label || text; + if (value !== "") { + items.push({ label: label, value: value }); + } + } + }); + this._list = items; + } + } + + if (document.activeElement === this.input) { + this.evaluate(); + } + }, + + get selected() { + return this.index > -1; + }, + + get opened() { + return !this.ul.hasAttribute("hidden"); + }, + + close: function () { + this.ul.setAttribute("hidden", ""); + this.index = -1; + + $.fire(this.input, "awesomplete-close"); + }, + + open: function () { + this.ul.removeAttribute("hidden"); + + if (this.autoFirst && this.index === -1) { + this.goto(0); + } + + $.fire(this.input, "awesomplete-open"); + }, + + next: function () { + var count = this.ul.children.length; + + this.goto(this.index < count - 1? this.index + 1 : -1); + }, + + previous: function () { + var count = this.ul.children.length; + + this.goto(this.selected? this.index - 1 : count - 1); + }, + + // Should not be used, highlights specific item without any checks! + goto: function (i) { + var lis = this.ul.children; + + if (this.selected) { + lis[this.index].setAttribute("aria-selected", "false"); + } + + this.index = i; + + if (i > -1 && lis.length > 0) { + lis[i].setAttribute("aria-selected", "true"); + this.status.textContent = lis[i].textContent; + + $.fire(this.input, "awesomplete-highlight", { + text: this.suggestions[this.index] + }); + } + }, + + select: function (selected, origin) { + if (selected) { + this.index = $.siblingIndex(selected); + } else { + selected = this.ul.children[this.index]; + } + + if (selected) { + var suggestion = this.suggestions[this.index]; + + var allowed = $.fire(this.input, "awesomplete-select", { + text: suggestion, + origin: origin || selected + }); + + if (allowed) { + this.replace(suggestion); + this.close(); + $.fire(this.input, "awesomplete-selectcomplete", { + text: suggestion + }); + } + } + }, + + evaluate: function() { + var me = this; + var value = this.input.value; + + if (value.length >= this.minChars && this._list.length > 0) { + this.index = -1; + // Populate list with options that match + this.ul.innerHTML = ""; + + this.suggestions = this._list + .map(function(item) { + return new Suggestion(me.data(item, value)); + }) + .filter(function(item) { + return me.filter(item, value); + }) + .sort(this.sort) + .slice(0, this.maxItems); + + this.suggestions.forEach(function(text) { + me.ul.appendChild(me.item(text, value)); + }); + + if (this.ul.children.length === 0) { + this.close(); + } else { + this.open(); + } + } + else { + this.close(); + } + } +}; // Static methods/properties - _.all = []; +_.all = []; - _.FILTER_CONTAINS = function (text, input) { - return RegExp($.regExpEscape(input.trim()), "i").test(text); - }; +_.FILTER_CONTAINS = function (text, input) { + return RegExp($.regExpEscape(input.trim()), "i").test(text); +}; - _.FILTER_STARTSWITH = function (text, input) { - return RegExp("^" + $.regExpEscape(input.trim()), "i").test(text); - }; +_.FILTER_STARTSWITH = function (text, input) { + return RegExp("^" + $.regExpEscape(input.trim()), "i").test(text); +}; - _.SORT_BYLENGTH = function (a, b) { - if (a.length !== b.length) { - return a.length - b.length; - } +_.SORT_BYLENGTH = function (a, b) { + if (a.length !== b.length) { + return a.length - b.length; + } - return a < b? -1 : 1; - }; + return a < b? -1 : 1; +}; + +_.ITEM = function (text, input) { + var html = input === '' ? text : text.replace(RegExp($.regExpEscape(input.trim()), "gi"), "$&"); + return $.create("li", { + innerHTML: html, + "aria-selected": "false" + }); +}; + +_.REPLACE = function (text) { + this.input.value = text.value; +}; + +_.DATA = function (item/*, input*/) { return item; }; // Private functions - function configure(properties, o) { - for (var i in properties) { - var initial = properties[i], - attrValue = this.input.getAttribute("data-" + i.toLowerCase()); - - if (typeof initial === "number") { - this[i] = +attrValue; - } - else if (initial === false) { // Boolean options must be false by default anyway - this[i] = attrValue !== null; - } - else if (initial instanceof Function) { - this[i] = null; - } - else { - this[i] = attrValue; - } - - this[i] = this[i] || o[i] || initial; - } - } +function Suggestion(data) { + var o = Array.isArray(data) + ? { label: data[0], value: data[1] } + : typeof data === "object" && "label" in data && "value" in data ? data : { label: data, value: data }; + + this.label = o.label || o.value; + this.value = o.value; +} +Object.defineProperty(Suggestion.prototype = Object.create(String.prototype), "length", { + get: function() { return this.label.length; } +}); +Suggestion.prototype.toString = Suggestion.prototype.valueOf = function () { + return "" + this.label; +}; + +function configure(instance, properties, o) { + for (var i in properties) { + var initial = properties[i], + attrValue = instance.input.getAttribute("data-" + i.toLowerCase()); + + if (typeof initial === "number") { + instance[i] = parseInt(attrValue); + } + else if (initial === false) { // Boolean options must be false by default anyway + instance[i] = attrValue !== null; + } + else if (initial instanceof Function) { + instance[i] = null; + } + else { + instance[i] = attrValue; + } + + if (!instance[i] && instance[i] !== 0) { + instance[i] = (i in o)? o[i] : initial; + } + } +} // Helpers - var slice = Array.prototype.slice; - - function $(expr, con) { - return typeof expr === "string"? (con || document).querySelector(expr) : expr || null; - } - - function $$(expr, con) { - return slice.call((con || document).querySelectorAll(expr)); - } - - $.create = function(tag, o) { - var element = document.createElement(tag); - - for (var i in o) { - var val = o[i]; - - if (i === "inside") { - $(val).appendChild(element); - } - else if (i === "around") { - var ref = $(val); - ref.parentNode.insertBefore(element, ref); - element.appendChild(ref); - } - else if (i in element) { - element[i] = val; - } - else { - element.setAttribute(i, val); - } - } - - return element; - }; - - $.bind = function(element, o) { - if (element) { - for (var event in o) { - var callback = o[event]; - - event.split(/\s+/).forEach(function (event) { - element.addEventListener(event, callback); - }); - } - } - }; - - $.fire = function(target, type, properties) { - var evt = document.createEvent("HTMLEvents"); - - evt.initEvent(type, true, true ); - - for (var j in properties) { - evt[j] = properties[j]; - } - - target.dispatchEvent(evt); - }; - - $.regExpEscape = function (s) { - return s.replace(/[-\\^$*+?.()|[\]{}]/g, "\\$&"); - } +var slice = Array.prototype.slice; + +function $(expr, con) { + return typeof expr === "string"? (con || document).querySelector(expr) : expr || null; +} + +function $$(expr, con) { + return slice.call((con || document).querySelectorAll(expr)); +} + +$.create = function(tag, o) { + var element = document.createElement(tag); + + for (var i in o) { + var val = o[i]; + + if (i === "inside") { + $(val).appendChild(element); + } + else if (i === "around") { + var ref = $(val); + ref.parentNode.insertBefore(element, ref); + element.appendChild(ref); + } + else if (i in element) { + element[i] = val; + } + else { + element.setAttribute(i, val); + } + } + + return element; +}; + +$.bind = function(element, o) { + if (element) { + for (var event in o) { + var callback = o[event]; + + event.split(/\s+/).forEach(function (event) { + element.addEventListener(event, callback); + }); + } + } +}; + +$.fire = function(target, type, properties) { + var evt = document.createEvent("HTMLEvents"); + + evt.initEvent(type, true, true ); + + for (var j in properties) { + evt[j] = properties[j]; + } + + return target.dispatchEvent(evt); +}; + +$.regExpEscape = function (s) { + return s.replace(/[-\\^$*+?.()|[\]{}]/g, "\\$&"); +}; + +$.siblingIndex = function (el) { + /* eslint-disable no-cond-assign */ + for (var i = 0; el = el.previousElementSibling; i++); + return i; +}; // Initialization - function init() { - $$("input.awesomplete").forEach(function (input) { - new Awesomplete(input); - }); - } +function init() { + $$("input.awesomplete").forEach(function (input) { + new _(input); + }); +} // Are we in a browser? Check for Document constructor - if (typeof Document !== 'undefined') { - // DOM already loaded? - if (document.readyState !== "loading") { - init(); - } - else { - // Wait for it - document.addEventListener("DOMContentLoaded", init); - } - } - - _.$ = $; - _.$$ = $$; +if (typeof Document !== "undefined") { + // DOM already loaded? + if (document.readyState !== "loading") { + init(); + } + else { + // Wait for it + document.addEventListener("DOMContentLoaded", init); + } +} + +_.$ = $; +_.$$ = $$; // Make sure to export Awesomplete on self when in a browser - if (typeof self !== 'undefined') { - self.Awesomplete = _; - } +if (typeof self !== "undefined") { + self.Awesomplete = _; +} // Expose Awesomplete as a CJS module - if (typeof exports === 'object') { - module.exports = _; - } +if (typeof module === "object" && module.exports) { + module.exports = _; +} - return _; +return _; }()); diff --git a/inc/awesomplete.min.js b/inc/awesomplete.min.js index 3bfb05e8..bd750c83 100644 --- a/inc/awesomplete.min.js +++ b/inc/awesomplete.min.js @@ -1,10 +1,12 @@ // Awesomplete - Lea Verou - MIT license -(function(){function m(a,b){for(var c in a){var f=a[c],e=this.input.getAttribute("data-"+c.toLowerCase());this[c]="number"===typeof f?+e:!1===f?null!==e:f instanceof Function?null:e;this[c]=this[c]||b[c]||f}}function d(a,b){return"string"===typeof a?(b||document).querySelector(a):a||null}function h(a,b){return k.call((b||document).querySelectorAll(a))}function l(){h("input.awesomplete").forEach(function(a){new Awesomplete(a)})}var g=self.Awesomplete=function(a,b){var c=this;this.input=d(a);this.input.setAttribute("aria-autocomplete", - "list");b=b||{};m.call(this,{minChars:2,maxItems:10,autoFirst:!1,filter:g.FILTER_CONTAINS,sort:g.SORT_BYLENGTH,item:function(a,b){return d.create("li",{innerHTML:a.replace(RegExp(d.regExpEscape(b.trim()),"gi"),"$&"),"aria-selected":"false"})},replace:function(a){this.input.value=a}},b);this.index=-1;this.container=d.create("div",{className:"awesomplete",around:a});this.ul=d.create("ul",{hidden:"",inside:this.container});this.status=d.create("span",{className:"visually-hidden",role:"status", - "aria-live":"assertive","aria-relevant":"additions",inside:this.container});d.bind(this.input,{input:this.evaluate.bind(this),blur:this.close.bind(this),keydown:function(a){var b=a.keyCode;if(c.opened)if(13===b&&c.selected)a.preventDefault(),c.select();else if(27===b)c.close();else if(38===b||40===b)a.preventDefault(),c[38===b?"previous":"next"]()}});d.bind(this.input.form,{submit:this.close.bind(this)});d.bind(this.ul,{mousedown:function(a){a=a.target;if(a!==this){for(;a&&!/li/i.test(a.nodeName);)a= - a.parentNode;a&&c.select(a)}}});this.input.hasAttribute("list")?(this.list="#"+a.getAttribute("list"),a.removeAttribute("list")):this.list=this.input.getAttribute("data-list")||b.list||[];g.all.push(this)};g.prototype={set list(a){Array.isArray(a)?this._list=a:"string"===typeof a&&-1=this.minChars&&0=this.minChars&&0$&");return c.create("li",{innerHTML:d,"aria-selected":"false"})};e.REPLACE=function(a){this.input.value=a.value};e.DATA=function(a){return a};Object.defineProperty(h.prototype=Object.create(String.prototype),"length",{get:function(){return this.label.length}});h.prototype.toString=h.prototype.valueOf=function(){return""+this.label};var l=Array.prototype.slice;c.create=function(a,b){var d=document.createElement(a), +g;for(g in b){var f=b[g];"inside"===g?c(f).appendChild(d):"around"===g?(f=c(f),f.parentNode.insertBefore(d,f),d.appendChild(f)):g in d?d[g]=f:d.setAttribute(g,f)}return d};c.bind=function(a,b){if(a)for(var d in b){var c=b[d];d.split(/\s+/).forEach(function(b){a.addEventListener(b,c)})}};c.fire=function(a,b,c){var e=document.createEvent("HTMLEvents");e.initEvent(b,!0,!0);for(var f in c)e[f]=c[f];return a.dispatchEvent(e)};c.regExpEscape=function(a){return a.replace(/[-\\^$*+?.()|[\]{}]/g,"\\$&")}; +c.siblingIndex=function(a){for(var b=0;a=a.previousElementSibling;b++);return b};"undefined"!==typeof Document&&("loading"!==document.readyState?m():document.addEventListener("DOMContentLoaded",m));e.$=c;e.$$=k;"undefined"!==typeof self&&(self.Awesomplete=e);"object"===typeof module&&module.exports&&(module.exports=e);return e})(); \ No newline at end of file diff --git a/plugins/markdown/markdown.css b/plugins/markdown/markdown.css index 8f2c0051..33702564 100644 --- a/plugins/markdown/markdown.css +++ b/plugins/markdown/markdown.css @@ -150,10 +150,6 @@ box-shadow: 0 -1px 0 #e5e5e5,0 0 1px rgba(0,0,0,0.12),0 1px 1px rgba(0,0,0,0.24); } -.md_help { - color: white; -} - /* Remove header links style */ diff --git a/tpl/default/editlink.html b/tpl/default/editlink.html new file mode 100644 index 00000000..f831655c --- /dev/null +++ b/tpl/default/editlink.html @@ -0,0 +1,82 @@ + + + + {include="includes"} + + + {if="$source !== 'firefoxsocialapi'"} + {include="page.header"} + {/if} +
+
+
+

Shaare

+ +
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+ +
+ +   +
+ + + +
+ + {if="!$link_is_new"} + + {/if} +
+ + + {if="$http_referer"} + + {/if} +
+
+ {if="$source !== 'firefoxsocialapi'"} + {include="page.footer"} + {/if} + + + -- 2.41.0