Bugfix: Inputosaurus modifications got broken.

Replaced completely with EmailAddressesComponent
This commit is contained in:
djmaze 2021-02-03 23:36:36 +01:00
parent b0e3020aab
commit 6a92912a3d
6 changed files with 81 additions and 139 deletions

View file

@ -13,6 +13,12 @@ export const moveAction = ko.observable(false);
export const leftPanelDisabled = ko.observable(false); export const leftPanelDisabled = ko.observable(false);
export const leftPanelType = ko.observable(''); 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 => { leftPanelDisabled.subscribe(value => {
value && moveAction() && moveAction(false); value && moveAction() && moveAction(false);
$htmlCL.toggle('rl-left-panel-disabled', value); $htmlCL.toggle('rl-left-panel-disabled', value);

View file

@ -1,40 +1,24 @@
/** import { doc, createElement } from 'Common/Globals';
* Inputosaurus Text import { EmailModel } from 'Model/Email';
*
* Must be instantiated on an <input> 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 <dan@sproutsocial.com>
* @created October 3,2012
*
* @modified by RainLoop Team
* @modified by DJMaze
*/
(doc => { const contentType = 'snappymail/emailaddress';
const createEl = (name, attr) => { let dragAddress, datalist;
let el = doc.createElement(name);
attr && Object.entries(attr).forEach(([k,v]) => el.setAttribute(k,v));
return el;
},
datalist = createEl('datalist',{id:"inputosaurus-datalist"}),
contentType = 'inputosaurus/item'; // mailbox-list
export class EmailAddressesComponent {
doc.body.append(datalist);
let dragData;
this.Inputosaurus = class {
constructor(element, options) { constructor(element, options) {
if (!datalist) {
datalist = createElement('datalist',{id:"emailaddresses-datalist"});
doc.body.append(datalist);
}
var self = this, var self = this,
// In Chrome we have no access to dataTransfer.getData unless it's the 'drop' event // 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 // 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(); fnDrag = e => validDropzone() && e.preventDefault();
self.element = element; self.element = element;
@ -46,12 +30,6 @@ this.Inputosaurus = class {
// simply passing an autoComplete source (array, string or function) will instantiate autocomplete functionality // simply passing an autoComplete source (array, string or function) will instantiate autocomplete functionality
autoCompleteSource : '', 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 onChange : null
}, options); }, options);
@ -60,21 +38,21 @@ this.Inputosaurus = class {
self._lastEdit = ''; self._lastEdit = '';
// Create the elements // 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('click', e => self._focus(e));
self.ul.addEventListener('dblclick', e => self._editTag(e)); self.ul.addEventListener('dblclick', e => self._editTag(e));
self.ul.addEventListener("dragenter", fnDrag); self.ul.addEventListener("dragenter", fnDrag);
self.ul.addEventListener("dragover", fnDrag); self.ul.addEventListener("dragover", fnDrag);
self.ul.addEventListener("drop", e => { self.ul.addEventListener("drop", e => {
if (validDropzone() && dragData.value) { if (validDropzone() && dragAddress.value) {
e.preventDefault(); e.preventDefault();
dragData.source._removeDraggedTag(dragData.li); dragAddress.source._removeDraggedTag(dragAddress.li);
self._parseValue(dragData.value); 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"}); autocomplete:"off", autocorrect:"off", autocapitalize:"off", spellcheck:"false"});
self.input.addEventListener('focus', () => self._focusTrigger(true)); self.input.addEventListener('focus', () => self._focusTrigger(true));
@ -111,7 +89,7 @@ this.Inputosaurus = class {
self.input.placeholder = element.placeholder; 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.inputCont.append(self.input);
self.ul.append(self.inputCont); self.ul.append(self.inputCont);
@ -140,7 +118,7 @@ this.Inputosaurus = class {
} }
_focusTrigger(bValue) { _focusTrigger(bValue) {
this.ul.classList.toggle('inputosaurus-focused', bValue); this.ul.classList.toggle('emailaddresses-focused', bValue);
this.options.focusCallback(bValue); this.options.focusCallback(bValue);
} }
@ -157,18 +135,18 @@ this.Inputosaurus = class {
} }
_parseValue(val) { _parseValue(val) {
if (val) {
var self = this, var self = this,
hook,
values = []; values = [];
if (val) { const v = val.trim(),
if ((hook = self.options.splitHook(val))) { hook = (v && [',', ';', '\n'].includes(v.substr(-1)))
values = hook; ? EmailModel.splitEmailLine(val)
} else { : null;
values.push(val);
}
values = self.options.parseHook(values); values = (hook || [val]).map(value => EmailModel.parseEmailLine(value))
.flat(Infinity)
.map(item => (item.toLine ? [item.toLine(false), item] : [item, null]));
if (values.length) { if (values.length) {
self._setChosen(values); self._setChosen(values);
@ -187,7 +165,7 @@ this.Inputosaurus = class {
_editTag(ev) { _editTag(ev) {
var li = ev.target.closest('li'), var li = ev.target.closest('li'),
tagKey = li && li.inputosaurusKey; tagKey = li && li.emailaddress.key;
if (!tagKey) { if (!tagKey) {
return true; return true;
@ -289,15 +267,15 @@ this.Inputosaurus = class {
self._chosenValues.forEach(v => { self._chosenValues.forEach(v => {
if (v.obj) { if (v.obj) {
let li = createEl('li',{title:v.obj.toLine(false, false, true),draggable:'true'}), let li = createElement('li',{title:v.obj.toLine(false, false, true),draggable:'true'}),
el = createEl('span'); el = createElement('span');
el.append(v.obj.toLine(true, false, true)); el.append(v.obj.toLine(true, false, true));
li.append(el); li.append(el);
el = createEl('a',{href:'#', class:'ficon'}); el = createElement('a',{href:'#', class:'ficon'});
el.append('✖'); el.append('✖');
el.addEventListener('click', e => self._removeTag(e, li)); 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('blur', () => li.className = null);
el.addEventListener('keydown', e => { el.addEventListener('keydown', e => {
switch (e.key) { switch (e.key) {
@ -339,23 +317,22 @@ this.Inputosaurus = class {
}); });
li.append(el); li.append(el);
li.inputosaurusKey = v.key; li.emailaddress = v;
li.inputosaurusValue = v.obj.toLine();
li.addEventListener("dragstart", e => { li.addEventListener("dragstart", e => {
dragData = { dragAddress = {
source: self, source: self,
li: li, 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.setData('text/plain', contentType);
// e.dataTransfer.setDragImage(li, 0, 0); // e.dataTransfer.setDragImage(li, 0, 0);
e.dataTransfer.effectAllowed = 'move'; e.dataTransfer.effectAllowed = 'move';
li.style.opacity = 0.25; li.style.opacity = 0.25;
}); });
li.addEventListener("dragend", () => { li.addEventListener("dragend", () => {
dragData = null; dragAddress = null;
li.style.cssText = ''; li.style.cssText = '';
}); });
@ -367,7 +344,7 @@ this.Inputosaurus = class {
_removeTag(ev, li) { _removeTag(ev, li) {
ev.preventDefault(); ev.preventDefault();
var key = li.inputosaurusKey, var key = li.emailaddress.key,
self = this, self = this,
indexFound = self._chosenValues.findIndex(v => key === v.key); indexFound = self._chosenValues.findIndex(v => key === v.key);
@ -381,7 +358,7 @@ this.Inputosaurus = class {
_removeDraggedTag(li) { _removeDraggedTag(li) {
var var
key = li.inputosaurusKey, key = li.emailaddress.key,
self = this, self = this,
indexFound = self._chosenValues.findIndex(v => key === v.key) indexFound = self._chosenValues.findIndex(v => key === v.key)
; ;
@ -403,38 +380,21 @@ this.Inputosaurus = class {
_focus(ev) { _focus(ev) {
var li = ev.target.closest('li'); var li = ev.target.closest('li');
if (li && li.inputosaurusKey) { if (li && li.emailaddress.key) {
li.querySelector('a').focus(); li.querySelector('a').focus();
} else { } else {
this.focus(); this.focus();
} }
} }
refresh() { set value(value) {
var self = this, var self = this;
val = self.element.value, if (self.element.value !== value) {
values = []; // self.input.value = '';
// self._resizeInput();
values.push(val);
if (val) {
var hook = self.options.splitHook(val);
if (hook) {
values = hook;
}
}
if (values.length) {
self._chosenValues = []; self._chosenValues = [];
values = self.options.parseHook(values);
self._setChosen(values);
self._renderTags(); self._renderTags();
self.input.value = ''; self._parseValue(self.element.value = value);
self._resizeInput(); }
} }
} }
};
})(document);

View file

@ -2,8 +2,8 @@ import 'External/ko';
import ko from 'ko'; import ko from 'ko';
import { HtmlEditor } from 'Common/Html'; import { HtmlEditor } from 'Common/Html';
import { timeToNode } from 'Common/Momentor'; import { timeToNode } from 'Common/Momentor';
import { EmailModel } from 'Model/Email';
import { doc } from 'Common/Globals'; import { doc } from 'Common/Globals';
import { EmailAddressesComponent } from 'Component/EmailAddresses';
const rlContentType = 'snappymail/action', const rlContentType = 'snappymail/action',
@ -64,42 +64,22 @@ ko.bindingHandlers.moment = {
ko.bindingHandlers.emailsTags = { ko.bindingHandlers.emailsTags = {
init: (element, fValueAccessor, fAllBindingsAccessor) => { init: (element, fValueAccessor, fAllBindingsAccessor) => {
const fValue = fValueAccessor(), const fValue = fValueAccessor(),
fAllBindings = fAllBindingsAccessor(), fAllBindings = fAllBindingsAccessor();
inputDelimiters = [',', ';', '\n'];
element.inputosaurus = new window.Inputosaurus(element, { element.addresses = new EmailAddressesComponent(element, {
focusCallback: value => fValue.focused && fValue.focused(!!value), focusCallback: value => fValue.focused && fValue.focused(!!value),
autoCompleteSource: fAllBindings.autoCompleteSource || null, autoCompleteSource: fAllBindings.autoCompleteSource || null,
splitHook: value => { onChange: value => fValue(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);
}
}); });
if (fValue.focused && fValue.focused.subscribe) { if (fValue.focused && fValue.focused.subscribe) {
fValue.focused.subscribe(value => fValue.focused.subscribe(value =>
element.inputosaurus[value ? 'focus' : 'blur']() element.addresses[value ? 'focus' : 'blur']()
); );
} }
}, },
update: (element, fValueAccessor) => { update: (element, fValueAccessor) => {
const value = ko.unwrap(fValueAccessor()); element.addresses.value = ko.unwrap(fValueAccessor());
if (element.EmailsTagsValue !== value) {
element.value = value;
element.EmailsTagsValue = value;
element.inputosaurus.refresh();
}
} }
}; };

View file

@ -22,7 +22,6 @@
@import "_FontasticToBoot.less"; @import "_FontasticToBoot.less";
@import "_BootstrapFix.less"; @import "_BootstrapFix.less";
@import "_InputosaurusFix.less";
@import "_CkeFix.less"; @import "_CkeFix.less";
@import "Ui.less"; @import "Ui.less";
@ -50,6 +49,7 @@
@import "MessageView.less"; @import "MessageView.less";
@import "Contacts.less"; @import "Contacts.less";
@import "Compose.less"; @import "Compose.less";
@import "EmailAddresses.less";
@import "Admin.less"; @import "Admin.less";
@import "AdminGeneral.less"; @import "AdminGeneral.less";

View file

@ -1,4 +1,4 @@
.inputosaurus-container { .emailaddresses {
background-color: #fff; background-color: #fff;
border: 1px solid #ccc; border: 1px solid #ccc;
border-radius: 3px; border-radius: 3px;
@ -12,10 +12,16 @@
transition: border linear .2s, box-shadow linear .2s; 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; display: inline-block;
} }
.inputosaurus-container li[draggable] { .emailaddresses li[draggable] {
background-color: #eee; background-color: #eee;
border: 1px solid #aaa; border: 1px solid #aaa;
border-radius: 2px; border-radius: 2px;
@ -32,15 +38,15 @@
white-space: nowrap; white-space: nowrap;
} }
.inputosaurus-container li.pgp { .emailaddresses li.pgp {
background-color: #E5F3E2; background-color: #E5F3E2;
} }
.inputosaurus-container li span { .emailaddresses li span {
padding-right: 3px; padding-right: 3px;
} }
.inputosaurus-container li a { .emailaddresses li a {
font-size: 12px; font-size: 12px;
color: #999; color: #999;
outline: 0; outline: 0;
@ -50,18 +56,18 @@
text-decoration: none; text-decoration: none;
top: 1px; top: 1px;
} }
.inputosaurus-container li a:hover { .emailaddresses li a:hover {
color: #666; color: #666;
} }
.inputosaurus-container .inputosaurus-input { .emailaddresses .emailaddresses-input {
margin: 0 2px; margin: 0 2px;
padding: 0; padding: 0;
} }
.inputosaurus-container input[type="text"], .emailaddresses input[type="text"],
.inputosaurus-container input[type="text"]:focus, .emailaddresses input[type="text"]:focus,
.inputosaurus-container input[type="text"]:hover { .emailaddresses input[type="text"]:hover {
border: 0; border: 0;
box-shadow: none; box-shadow: none;
height: 24px; height: 24px;
@ -71,8 +77,8 @@
vertical-align: baseline; vertical-align: baseline;
} }
.inputosaurus-container li.inputosaurus-selected, .emailaddresses li.emailaddresses-selected,
.inputosaurus-container li.inputosaurus-selected a { .emailaddresses li.emailaddresses-selected a {
background-color: Highlight; background-color: Highlight;
color: HighlightText; color: HighlightText;
} }

View file

@ -1,10 +0,0 @@
.inputosaurus-container {
&.inputosaurus-focused {
background-color: #fff;
border: @rlInputBorderSize solid darken(@inputBorder, 20%);
box-shadow: none;
}
}