From 6a92912a3d6086b78724133e7382aa74f15ed5c7 Mon Sep 17 00:00:00 2001 From: djmaze Date: Wed, 3 Feb 2021 23:36:36 +0100 Subject: [PATCH] Bugfix: Inputosaurus modifications got broken. Replaced completely with EmailAddressesComponent --- dev/Common/Globals.js | 6 + .../Component/EmailAddresses.js | 138 +++++++----------- dev/External/User/ko.js | 32 +--- dev/Styles/@Main.less | 2 +- .../Styles/EmailAddresses.less | 32 ++-- dev/Styles/_InputosaurusFix.less | 10 -- 6 files changed, 81 insertions(+), 139 deletions(-) rename vendors/inputosaurus/inputosaurus.js => dev/Component/EmailAddresses.js (75%) rename vendors/inputosaurus/inputosaurus.css => dev/Styles/EmailAddresses.less (64%) delete mode 100644 dev/Styles/_InputosaurusFix.less diff --git a/dev/Common/Globals.js b/dev/Common/Globals.js index 9b8dccd8a..df774ae39 100644 --- a/dev/Common/Globals.js +++ b/dev/Common/Globals.js @@ -13,6 +13,12 @@ export const moveAction = ko.observable(false); export const leftPanelDisabled = ko.observable(false); export const leftPanelType = ko.observable(''); +export const createElement = (name, attr) => { + let el = doc.createElement(name); + attr && Object.entries(attr).forEach(([k,v]) => el.setAttribute(k,v)); + return el; +}; + leftPanelDisabled.subscribe(value => { value && moveAction() && moveAction(false); $htmlCL.toggle('rl-left-panel-disabled', value); diff --git a/vendors/inputosaurus/inputosaurus.js b/dev/Component/EmailAddresses.js similarity index 75% rename from vendors/inputosaurus/inputosaurus.js rename to dev/Component/EmailAddresses.js index d50851a01..99bf6d3ee 100644 --- a/vendors/inputosaurus/inputosaurus.js +++ b/dev/Component/EmailAddresses.js @@ -1,40 +1,24 @@ -/** - * Inputosaurus Text - * - * Must be instantiated on an element - * Allows multiple input items. Each item is represented with a removable tag that appears to be inside the input area. - * - * @version 0.1.6 - * @author Dan Kielp - * @created October 3,2012 - * - * @modified by RainLoop Team - * @modified by DJMaze - */ +import { doc, createElement } from 'Common/Globals'; +import { EmailModel } from 'Model/Email'; -(doc => { +const contentType = 'snappymail/emailaddress'; -const createEl = (name, attr) => { - let el = doc.createElement(name); - attr && Object.entries(attr).forEach(([k,v]) => el.setAttribute(k,v)); - return el; - }, - datalist = createEl('datalist',{id:"inputosaurus-datalist"}), +let dragAddress, datalist; - contentType = 'inputosaurus/item'; - -doc.body.append(datalist); - -let dragData; - -this.Inputosaurus = class { +// mailbox-list +export class EmailAddressesComponent { constructor(element, options) { + if (!datalist) { + datalist = createElement('datalist',{id:"emailaddresses-datalist"}); + doc.body.append(datalist); + } + var self = this, // In Chrome we have no access to dataTransfer.getData unless it's the 'drop' event // In Chrome Mobile dataTransfer.types.includes(contentType) fails, only text/plain is set - validDropzone = () => dragData && dragData.li.parentNode !== self.ul, + validDropzone = () => dragAddress && dragAddress.li.parentNode !== self.ul, fnDrag = e => validDropzone() && e.preventDefault(); self.element = element; @@ -46,12 +30,6 @@ this.Inputosaurus = class { // simply passing an autoComplete source (array, string or function) will instantiate autocomplete functionality autoCompleteSource : '', - // manipulate and return the input value after parseInput() parsing - // the array of tag names is passed and expected to be returned as an array after manipulation - parseHook : null, - - splitHook : null, - onChange : null }, options); @@ -60,21 +38,21 @@ this.Inputosaurus = class { self._lastEdit = ''; // Create the elements - self.ul = createEl('ul',{class:"inputosaurus-container"}); + self.ul = createElement('ul',{class:"emailaddresses"}); self.ul.addEventListener('click', e => self._focus(e)); self.ul.addEventListener('dblclick', e => self._editTag(e)); self.ul.addEventListener("dragenter", fnDrag); self.ul.addEventListener("dragover", fnDrag); self.ul.addEventListener("drop", e => { - if (validDropzone() && dragData.value) { + if (validDropzone() && dragAddress.value) { e.preventDefault(); - dragData.source._removeDraggedTag(dragData.li); - self._parseValue(dragData.value); + dragAddress.source._removeDraggedTag(dragAddress.li); + self._parseValue(dragAddress.value); } }); - self.input = createEl('input',{type:"text", list:datalist.id, + self.input = createElement('input',{type:"text", list:datalist.id, autocomplete:"off", autocorrect:"off", autocapitalize:"off", spellcheck:"false"}); self.input.addEventListener('focus', () => self._focusTrigger(true)); @@ -111,7 +89,7 @@ this.Inputosaurus = class { self.input.placeholder = element.placeholder; } - self.inputCont = createEl('li',{class:"inputosaurus-input"}); + self.inputCont = createElement('li',{class:"emailaddresses-input"}); self.inputCont.append(self.input); self.ul.append(self.inputCont); @@ -140,7 +118,7 @@ this.Inputosaurus = class { } _focusTrigger(bValue) { - this.ul.classList.toggle('inputosaurus-focused', bValue); + this.ul.classList.toggle('emailaddresses-focused', bValue); this.options.focusCallback(bValue); } @@ -157,18 +135,18 @@ this.Inputosaurus = class { } _parseValue(val) { - var self = this, - hook, - values = []; - if (val) { - if ((hook = self.options.splitHook(val))) { - values = hook; - } else { - values.push(val); - } + var self = this, + values = []; - values = self.options.parseHook(values); + const v = val.trim(), + hook = (v && [',', ';', '\n'].includes(v.substr(-1))) + ? EmailModel.splitEmailLine(val) + : null; + + values = (hook || [val]).map(value => EmailModel.parseEmailLine(value)) + .flat(Infinity) + .map(item => (item.toLine ? [item.toLine(false), item] : [item, null])); if (values.length) { self._setChosen(values); @@ -187,7 +165,7 @@ this.Inputosaurus = class { _editTag(ev) { var li = ev.target.closest('li'), - tagKey = li && li.inputosaurusKey; + tagKey = li && li.emailaddress.key; if (!tagKey) { return true; @@ -289,15 +267,15 @@ this.Inputosaurus = class { self._chosenValues.forEach(v => { if (v.obj) { - let li = createEl('li',{title:v.obj.toLine(false, false, true),draggable:'true'}), - el = createEl('span'); + let li = createElement('li',{title:v.obj.toLine(false, false, true),draggable:'true'}), + el = createElement('span'); el.append(v.obj.toLine(true, false, true)); li.append(el); - el = createEl('a',{href:'#', class:'ficon'}); + el = createElement('a',{href:'#', class:'ficon'}); el.append('✖'); el.addEventListener('click', e => self._removeTag(e, li)); - el.addEventListener('focus', () => li.className = 'inputosaurus-selected'); + el.addEventListener('focus', () => li.className = 'emailaddresses-selected'); el.addEventListener('blur', () => li.className = null); el.addEventListener('keydown', e => { switch (e.key) { @@ -339,23 +317,22 @@ this.Inputosaurus = class { }); li.append(el); - li.inputosaurusKey = v.key; - li.inputosaurusValue = v.obj.toLine(); + li.emailaddress = v; li.addEventListener("dragstart", e => { - dragData = { + dragAddress = { source: self, li: li, - value: li.inputosaurusValue + value: li.emailaddress.obj.toLine() }; -// e.dataTransfer.setData(contentType, li.inputosaurusValue); +// e.dataTransfer.setData(contentType, li.emailaddress.obj.toLine()); e.dataTransfer.setData('text/plain', contentType); // e.dataTransfer.setDragImage(li, 0, 0); e.dataTransfer.effectAllowed = 'move'; li.style.opacity = 0.25; }); li.addEventListener("dragend", () => { - dragData = null; + dragAddress = null; li.style.cssText = ''; }); @@ -367,7 +344,7 @@ this.Inputosaurus = class { _removeTag(ev, li) { ev.preventDefault(); - var key = li.inputosaurusKey, + var key = li.emailaddress.key, self = this, indexFound = self._chosenValues.findIndex(v => key === v.key); @@ -381,7 +358,7 @@ this.Inputosaurus = class { _removeDraggedTag(li) { var - key = li.inputosaurusKey, + key = li.emailaddress.key, self = this, indexFound = self._chosenValues.findIndex(v => key === v.key) ; @@ -403,38 +380,21 @@ this.Inputosaurus = class { _focus(ev) { var li = ev.target.closest('li'); - if (li && li.inputosaurusKey) { + if (li && li.emailaddress.key) { li.querySelector('a').focus(); } else { this.focus(); } } - refresh() { - var self = this, - val = self.element.value, - values = []; - - values.push(val); - - if (val) { - var hook = self.options.splitHook(val); - if (hook) { - values = hook; - } - } - - if (values.length) { + set value(value) { + var self = this; + if (self.element.value !== value) { +// self.input.value = ''; +// self._resizeInput(); self._chosenValues = []; - - values = self.options.parseHook(values); - - self._setChosen(values); self._renderTags(); - self.input.value = ''; - self._resizeInput(); + self._parseValue(self.element.value = value); } } -}; - -})(document); +} diff --git a/dev/External/User/ko.js b/dev/External/User/ko.js index 2aa9cba3b..dd59d117e 100644 --- a/dev/External/User/ko.js +++ b/dev/External/User/ko.js @@ -2,8 +2,8 @@ import 'External/ko'; import ko from 'ko'; import { HtmlEditor } from 'Common/Html'; import { timeToNode } from 'Common/Momentor'; -import { EmailModel } from 'Model/Email'; import { doc } from 'Common/Globals'; +import { EmailAddressesComponent } from 'Component/EmailAddresses'; const rlContentType = 'snappymail/action', @@ -64,42 +64,22 @@ ko.bindingHandlers.moment = { ko.bindingHandlers.emailsTags = { init: (element, fValueAccessor, fAllBindingsAccessor) => { const fValue = fValueAccessor(), - fAllBindings = fAllBindingsAccessor(), - inputDelimiters = [',', ';', '\n']; + fAllBindings = fAllBindingsAccessor(); - element.inputosaurus = new window.Inputosaurus(element, { + element.addresses = new EmailAddressesComponent(element, { focusCallback: value => fValue.focused && fValue.focused(!!value), autoCompleteSource: fAllBindings.autoCompleteSource || null, - splitHook: value => { - const v = value.trim(); - return (v && inputDelimiters.includes(v.substr(-1))) - ? EmailModel.splitEmailLine(value) - : null; - }, - parseHook: input => - input.map(inputValue => EmailModel.parseEmailLine(inputValue)) - .flat(Infinity) - .map(item => (item.toLine ? [item.toLine(false), item] : [item, null])), - onChange: value => { - element.EmailsTagsValue = value; - fValue(value); - } + onChange: value => fValue(value) }); if (fValue.focused && fValue.focused.subscribe) { fValue.focused.subscribe(value => - element.inputosaurus[value ? 'focus' : 'blur']() + element.addresses[value ? 'focus' : 'blur']() ); } }, update: (element, fValueAccessor) => { - const value = ko.unwrap(fValueAccessor()); - - if (element.EmailsTagsValue !== value) { - element.value = value; - element.EmailsTagsValue = value; - element.inputosaurus.refresh(); - } + element.addresses.value = ko.unwrap(fValueAccessor()); } }; diff --git a/dev/Styles/@Main.less b/dev/Styles/@Main.less index 322d84028..65918ee75 100644 --- a/dev/Styles/@Main.less +++ b/dev/Styles/@Main.less @@ -22,7 +22,6 @@ @import "_FontasticToBoot.less"; @import "_BootstrapFix.less"; -@import "_InputosaurusFix.less"; @import "_CkeFix.less"; @import "Ui.less"; @@ -50,6 +49,7 @@ @import "MessageView.less"; @import "Contacts.less"; @import "Compose.less"; +@import "EmailAddresses.less"; @import "Admin.less"; @import "AdminGeneral.less"; diff --git a/vendors/inputosaurus/inputosaurus.css b/dev/Styles/EmailAddresses.less similarity index 64% rename from vendors/inputosaurus/inputosaurus.css rename to dev/Styles/EmailAddresses.less index a3119dc15..ab084bc4a 100644 --- a/vendors/inputosaurus/inputosaurus.css +++ b/dev/Styles/EmailAddresses.less @@ -1,4 +1,4 @@ -.inputosaurus-container { +.emailaddresses { background-color: #fff; border: 1px solid #ccc; border-radius: 3px; @@ -12,10 +12,16 @@ transition: border linear .2s, box-shadow linear .2s; } -.inputosaurus-container li { +.emailaddresses.emailaddresses-focused { + background-color: #fff; + border: @rlInputBorderSize solid darken(@inputBorder, 20%); + box-shadow: none; +} + +.emailaddresses li { display: inline-block; } -.inputosaurus-container li[draggable] { +.emailaddresses li[draggable] { background-color: #eee; border: 1px solid #aaa; border-radius: 2px; @@ -32,15 +38,15 @@ white-space: nowrap; } -.inputosaurus-container li.pgp { +.emailaddresses li.pgp { background-color: #E5F3E2; } -.inputosaurus-container li span { +.emailaddresses li span { padding-right: 3px; } -.inputosaurus-container li a { +.emailaddresses li a { font-size: 12px; color: #999; outline: 0; @@ -50,18 +56,18 @@ text-decoration: none; top: 1px; } -.inputosaurus-container li a:hover { +.emailaddresses li a:hover { color: #666; } -.inputosaurus-container .inputosaurus-input { +.emailaddresses .emailaddresses-input { margin: 0 2px; padding: 0; } -.inputosaurus-container input[type="text"], -.inputosaurus-container input[type="text"]:focus, -.inputosaurus-container input[type="text"]:hover { +.emailaddresses input[type="text"], +.emailaddresses input[type="text"]:focus, +.emailaddresses input[type="text"]:hover { border: 0; box-shadow: none; height: 24px; @@ -71,8 +77,8 @@ vertical-align: baseline; } -.inputosaurus-container li.inputosaurus-selected, -.inputosaurus-container li.inputosaurus-selected a { +.emailaddresses li.emailaddresses-selected, +.emailaddresses li.emailaddresses-selected a { background-color: Highlight; color: HighlightText; } diff --git a/dev/Styles/_InputosaurusFix.less b/dev/Styles/_InputosaurusFix.less deleted file mode 100644 index 6732d958e..000000000 --- a/dev/Styles/_InputosaurusFix.less +++ /dev/null @@ -1,10 +0,0 @@ - -.inputosaurus-container { - - &.inputosaurus-focused { - background-color: #fff; - border: @rlInputBorderSize solid darken(@inputBorder, 20%); - box-shadow: none; - } - -}