Kaynağa Gözat

Replace lodash methods with native ones

JC Brand 5 yıl önce
ebeveyn
işleme
6fe802a96b

+ 14 - 14
src/converse-autocomplete.js

@@ -9,8 +9,8 @@
 import { Events } from 'skeletor.js/src/events.js';
 import converse from "@converse/headless/converse-core";
 
-const { _ } = converse.env,
-      u = converse.env.utils;
+const u = converse.env.utils;
+
 
 converse.plugins.add("converse-autocomplete", {
 
@@ -94,7 +94,7 @@ converse.plugins.add("converse-autocomplete", {
                 this.ul = this.container.querySelector('.suggestion-box__results');
                 this.status = this.container.querySelector('.suggestion-box__additions');
 
-                _.assignIn(this, {
+                Object.assign(this, {
                     'match_current_word': false, // Match only the current word, otherwise all input is matched
                     'ac_triggers': [], // Array of keys (`ev.key`) values that will trigger auto-complete
                     'include_triggers': [], // Array of trigger keys which should be included in the returned value
@@ -102,7 +102,7 @@ converse.plugins.add("converse-autocomplete", {
                     'max_items': 10,
                     'auto_evaluate': true, // Should evaluation happen automatically without any particular key as trigger?
                     'auto_first': false, // Should the first element be automatically selected?
-                    'data': _.identity,
+                    'data': a => a,
                     'filter': _converse.FILTER_CONTAINS,
                     'sort': config.sort === false ? false : SORT_BYLENGTH,
                     'item': ITEM
@@ -147,7 +147,7 @@ converse.plugins.add("converse-autocomplete", {
             set list (list) {
                 if (Array.isArray(list) || typeof list === "function") {
                     this._list = list;
-                } else if (typeof list === "string" && _.includes(list, ",")) {
+                } else if (typeof list === "string" && list.includes(",")) {
                     this._list = list.split(/\s*,\s*/);
                 } else { // Element or CSS selector
                     list = helpers.getElement(list);
@@ -279,7 +279,7 @@ converse.plugins.add("converse-autocomplete", {
 
             onKeyDown (ev) {
                 if (this.opened) {
-                    if (_.includes([converse.keycodes.ENTER, converse.keycodes.TAB], ev.keyCode) && this.selected) {
+                    if ([converse.keycodes.ENTER, converse.keycodes.TAB].includes(ev.keyCode) && this.selected) {
                         ev.preventDefault();
                         ev.stopPropagation();
                         this.select();
@@ -287,7 +287,7 @@ converse.plugins.add("converse-autocomplete", {
                     } else if (ev.keyCode === converse.keycodes.ESCAPE) {
                         this.close({'reason': 'esc'});
                         return true;
-                    } else if (_.includes([converse.keycodes.UP_ARROW, converse.keycodes.DOWN_ARROW], ev.keyCode)) {
+                    } else if ([converse.keycodes.UP_ARROW, converse.keycodes.DOWN_ARROW].includes(ev.keyCode)) {
                         ev.preventDefault();
                         ev.stopPropagation();
                         this[ev.keyCode === converse.keycodes.UP_ARROW ? "previous" : "next"]();
@@ -295,13 +295,13 @@ converse.plugins.add("converse-autocomplete", {
                     }
                 }
 
-                if (_.includes([
-                            converse.keycodes.SHIFT,
-                            converse.keycodes.META,
-                            converse.keycodes.META_RIGHT,
-                            converse.keycodes.ESCAPE,
-                            converse.keycodes.ALT]
-                        , ev.keyCode)) {
+                if ([converse.keycodes.SHIFT,
+                     converse.keycodes.META,
+                     converse.keycodes.META_RIGHT,
+                     converse.keycodes.ESCAPE,
+                     converse.keycodes.ALT
+                    ].includes(ev.keyCode)) {
+
                     return;
                 }
 

+ 2 - 4
src/converse-minimize.js

@@ -293,8 +293,7 @@ converse.plugins.add('converse-minimize', {
 
             getMinimizedWidth () {
                 const minimized_el = _.get(_converse.minimized_chats, 'el');
-                return _.includes(this.model.pluck('minimized'), true) ?
-                    u.getOuterWidth(minimized_el, true) : 0;
+                return this.model.pluck('minimized').includes(true) ? u.getOuterWidth(minimized_el, true) : 0;
             },
 
             getBoxesWidth (newchat) {
@@ -356,8 +355,7 @@ converse.plugins.add('converse-minimize', {
                 exclude_ids.push('controlbox');
                 let i = 0;
                 let model = this.model.sort().at(i);
-                while (_.includes(exclude_ids, model.get('id')) ||
-                    model.get('minimized') === true) {
+                while (exclude_ids.includes(model.get('id')) || model.get('minimized') === true) {
                     i++;
                     model = this.model.at(i);
                     if (!model) {

+ 19 - 24
src/converse-omemo.js

@@ -8,11 +8,12 @@
 import "converse-profile";
 import { Collection } from "skeletor.js/src/collection";
 import { Model } from 'skeletor.js/src/model.js';
+import { concat, debounce, difference, get, invokeMap, range, omit } from "lodash";
 import converse from "@converse/headless/converse-core";
 import log from "@converse/headless/log";
 import tpl_toolbar_omemo from "templates/toolbar_omemo.html";
 
-const { Strophe, sizzle, $build, $iq, $msg, _ } = converse.env;
+const { Strophe, sizzle, $build, $iq, $msg } = converse.env;
 const u = converse.env.utils;
 
 Strophe.addNamespace('OMEMO_DEVICELIST', Strophe.NS.OMEMO+".devicelist");
@@ -81,7 +82,7 @@ converse.plugins.add('converse-omemo', {
 
             initialize () {
                 const { _converse } = this.__super__;
-                this.debouncedRender = _.debounce(this.render, 50);
+                this.debouncedRender = debounce(this.render, 50);
                 this.devicelist = _converse.devicelists.get(_converse.bare_jid);
                 this.listenTo(this.devicelist.devices, 'change:bundle', this.debouncedRender);
                 this.listenTo(this.devicelist.devices, 'reset', this.debouncedRender);
@@ -376,8 +377,8 @@ converse.plugins.add('converse-omemo', {
                         'device_id': header.getAttribute('sid'),
                         'iv': header.querySelector('iv').textContent,
                         'key': key.textContent,
-                        'payload': _.get(encrypted.querySelector('payload'), 'textContent', null),
-                        'prekey': _.includes(['true', '1'], key.getAttribute('prekey'))
+                        'payload': get(encrypted.querySelector('payload'), 'textContent', null),
+                        'prekey': ['true', '1'].includes(key.getAttribute('prekey'))
                     }
                     return this.decrypt(attrs);
                 } else {
@@ -480,7 +481,7 @@ converse.plugins.add('converse-omemo', {
 
 
         async function generateFingerprint (device) {
-            if (_.get(device.get('bundle'), 'fingerprint')) {
+            if (get(device.get('bundle'), 'fingerprint')) {
                 return;
             }
             const bundle = await device.getBundle();
@@ -516,7 +517,7 @@ converse.plugins.add('converse-omemo', {
             const existing_ids = _converse.devicelists.get(_converse.bare_jid).devices.pluck('id');
             let device_id = libsignal.KeyHelper.generateRegistrationId();
             let i = 0;
-            while (_.includes(existing_ids, device_id)) {
+            while (existing_ids.includes(device_id)) {
                 device_id = libsignal.KeyHelper.generateRegistrationId();
                 i++;
                 if (i == 10) {
@@ -569,7 +570,7 @@ converse.plugins.add('converse-omemo', {
             let devices;
             if (chatbox.get('type') === _converse.CHATROOMS_TYPE) {
                 const collections = await Promise.all(chatbox.occupants.map(o => getDevicesForContact(o.get('jid'))));
-                devices = collections.reduce((a, b) => _.concat(a, b.models), []);
+                devices = collections.reduce((a, b) => concat(a, b.models), []);
             } else if (chatbox.get('type') === _converse.PRIVATE_CHAT_TYPE) {
                 const their_devices = await getDevicesForContact(chatbox.get('jid'));
                 if (their_devices.length === 0) {
@@ -749,7 +750,7 @@ converse.plugins.add('converse-omemo', {
             },
 
             removePreKey (key_id) {
-                this.save('prekeys', _.omit(this.getPreKeys(), key_id));
+                this.save('prekeys', omit(this.getPreKeys(), key_id));
                 return Promise.resolve();
             },
 
@@ -807,13 +808,9 @@ converse.plugins.add('converse-omemo', {
             },
 
             removeAllSessions (identifier) {
-                const keys = _.filter(Object.keys(this.attributes), (key) => {
-                    if (key.startsWith('session'+identifier)) {
-                        return key;
-                    }
-                });
+                const keys = Object.keys(this.attributes).filter(key => key.startsWith('session'+identifier) ? key : false);
                 const attrs = {};
-                _.forEach(keys, (key) => {attrs[key] = undefined});
+                keys.forEach(key => {attrs[key] = undefined});
                 this.save(attrs);
                 return Promise.resolve();
             },
@@ -828,17 +825,15 @@ converse.plugins.add('converse-omemo', {
                         .c('signedPreKeySignature').t(signed_prekey.signature).up()
                         .c('identityKey').t(this.get('identity_keypair').pubKey).up()
                         .c('prekeys');
-                _.forEach(
-                    this.get('prekeys'),
-                    (prekey, id) => item.c('preKeyPublic', {'preKeyId': id}).t(prekey.pubKey).up()
-                );
+
+                Object.values(this.get('prekeys')).forEach((prekey, id) => item.c('preKeyPublic', {'preKeyId': id}).t(prekey.pubKey).up());
                 const options = {'pubsub#access_model': 'open'};
                 return _converse.api.pubsub.publish(null, node, item, options, false);
             },
 
             async generateMissingPreKeys () {
-                const missing_keys = _.difference(
-                    _.invokeMap(_.range(0, _converse.NUM_PREKEYS), Number.prototype.toString),
+                const missing_keys = difference(
+                    invokeMap(range(0, _converse.NUM_PREKEYS), Number.prototype.toString),
                     Object.keys(this.getPreKeys())
                 );
                 if (missing_keys.length < 1) {
@@ -884,7 +879,7 @@ converse.plugins.add('converse-omemo', {
                     'public_key': u.arrayBufferToBase64(signed_prekey.keyPair.privKey),
                     'signature': u.arrayBufferToBase64(signed_prekey.signature)
                 }
-                const keys = await Promise.all(_.range(0, _converse.NUM_PREKEYS).map(id => libsignal.KeyHelper.generatePreKey(id)));
+                const keys = await Promise.all(range(0, _converse.NUM_PREKEYS).map(id => libsignal.KeyHelper.generatePreKey(id)));
                 keys.forEach(k => _converse.omemo_store.storePreKey(k.keyId, k.keyPair));
                 const devicelist = _converse.devicelists.get(_converse.bare_jid);
                 const device = await devicelist.devices.create({'id': bundle.device_id, 'jid': _converse.bare_jid}, {'promise': true});
@@ -1027,7 +1022,7 @@ converse.plugins.add('converse-omemo', {
                     await _converse.omemo_store.generateBundle();
                     device_id = _converse.omemo_store.get('device_id');
                 }
-                if (!_.includes(device_ids, device_id)) {
+                if (!device_ids.includes(device_id)) {
                     return this.publishDevices();
                 }
             },
@@ -1066,7 +1061,7 @@ converse.plugins.add('converse-omemo', {
                 if (this.get('jid') !== _converse.bare_jid) {
                     throw new Error("Cannot remove devices from someone else's device list");
                 }
-                _.forEach(device_ids, (device_id) => this.devices.get(device_id).destroy());
+                device_ids.forEach(device_id => this.devices.get(device_id).destroy());
                 return this.publishDevices();
             }
         });
@@ -1129,7 +1124,7 @@ converse.plugins.add('converse-omemo', {
             const jid = stanza.getAttribute('from');
             const devicelist = _converse.devicelists.getDeviceList(jid);
             const devices = devicelist.devices;
-            const removed_ids = _.difference(devices.pluck('id'), device_ids);
+            const removed_ids = difference(devices.pluck('id'), device_ids);
 
             removed_ids.forEach(id => {
                 if (jid === _converse.bare_jid && id === _converse.omemo_store.get('device_id')) {

+ 1 - 1
src/converse-push.js

@@ -93,7 +93,7 @@ converse.plugins.add('converse-push', {
         async function enablePush (domain) {
             domain = domain || _converse.bare_jid;
             const push_enabled = _converse.session.get('push_enabled') || [];
-            if (_.includes(push_enabled, domain)) {
+            if (push_enabled.includes(domain)) {
                 return;
             }
             const enabled_services = _.reject(_converse.push_app_servers, 'disable');

+ 17 - 18
src/converse-register.js

@@ -8,6 +8,7 @@
  */
 import "converse-controlbox";
 import { View } from "skeletor.js/src/view";
+import { get, pick } from "lodash";
 import converse from "@converse/headless/converse-core";
 import log from "@converse/headless/log";
 import tpl_form_input from "templates/form_input.html";
@@ -19,7 +20,7 @@ import tpl_spinner from "templates/spinner.html";
 import utils from "@converse/headless/utils/form";
 
 // Strophe methods for building stanzas
-const { Strophe, sizzle, $iq, _ } = converse.env;
+const { Strophe, sizzle, $iq } = converse.env;
 const u = converse.env.utils;
 
 // Add Strophe Namespaces
@@ -258,7 +259,7 @@ converse.plugins.add('converse-register', {
                 };
                 Object.assign(this, defaults);
                 if (settings) {
-                    Object.assign(this, _.pick(settings, Object.keys(defaults)));
+                    Object.assign(this, pick(settings, Object.keys(defaults)));
                 }
             },
 
@@ -286,7 +287,7 @@ converse.plugins.add('converse-register', {
              */
             onProviderChosen (form) {
                 const domain_input = form.querySelector('input[name=domain]'),
-                    domain = _.get(domain_input, 'value');
+                    domain = get(domain_input, 'value');
                 if (!domain) {
                     // TODO: add validation message
                     domain_input.classList.add('error');
@@ -365,13 +366,12 @@ converse.plugins.add('converse-register', {
              */
             onConnectStatusChanged(status_code) {
                 log.debug('converse-register: onConnectStatusChanged');
-                if (_.includes([
-                            Strophe.Status.DISCONNECTED,
-                            Strophe.Status.CONNFAIL,
-                            Strophe.Status.REGIFAIL,
-                            Strophe.Status.NOTACCEPTABLE,
-                            Strophe.Status.CONFLICT
-                        ], status_code)) {
+                if ([Strophe.Status.DISCONNECTED,
+                     Strophe.Status.CONNFAIL,
+                     Strophe.Status.REGIFAIL,
+                     Strophe.Status.NOTACCEPTABLE,
+                     Strophe.Status.CONFLICT
+                    ].includes(status_code)) {
 
                     log.error(
                         `Problem during registration: Strophe.Status is ${_converse.CONNECTION_STATUS[status_code]}`
@@ -540,9 +540,8 @@ converse.plugins.add('converse-register', {
              * @param { HTMLElement } form - The HTML form that was submitted
              */
             submitRegistrationForm (form) {
-                const has_empty_inputs = _.reduce(
-                    this.el.querySelectorAll('input.required'),
-                    function (result, input) {
+                const has_empty_inputs = Array.from(this.el.querySelectorAll('input.required'))
+                    .reduce((result, input) => {
                         if (input.value === '') {
                             input.classList.add('error');
                             return result + 1;
@@ -551,8 +550,8 @@ converse.plugins.add('converse-register', {
                     }, 0);
                 if (has_empty_inputs) { return; }
 
-                const inputs = sizzle(':input:not([type=button]):not([type=submit])', form),
-                      iq = $iq({'type': 'set', 'id': u.getUniqueId()})
+                const inputs = sizzle(':input:not([type=button]):not([type=submit])', form);
+                const iq = $iq({'type': 'set', 'id': u.getUniqueId()})
                             .c("query", {xmlns:Strophe.NS.REGISTER});
 
                 if (this.form_type === 'xform') {
@@ -598,12 +597,12 @@ converse.plugins.add('converse-register', {
             },
 
             _setFieldsFromXForm (xform) {
-                this.title = _.get(xform.querySelector('title'), 'textContent');
-                this.instructions = _.get(xform.querySelector('instructions'), 'textContent');
+                this.title = get(xform.querySelector('title'), 'textContent');
+                this.instructions = get(xform.querySelector('instructions'), 'textContent');
                 xform.querySelectorAll('field').forEach(field => {
                     const _var = field.getAttribute('var');
                     if (_var) {
-                        this.fields[_var.toLowerCase()] = _.get(field.querySelector('value'), 'textContent', '');
+                        this.fields[_var.toLowerCase()] = get(field.querySelector('value'), 'textContent', '');
                     } else {
                         // TODO: other option seems to be type="fixed"
                         log.warn("Found field we couldn't parse");

+ 4 - 7
src/headless/converse-caps.js

@@ -5,8 +5,9 @@
  */
 import SHA1 from 'strophe.js/src/sha1';
 import converse from "@converse/headless/converse-core";
+import { get } from "lodash";
 
-const { Strophe, $build, _ } = converse.env;
+const { Strophe, $build } = converse.env;
 
 Strophe.addNamespace('CAPS', "http://jabber.org/protocol/caps");
 
@@ -24,13 +25,9 @@ function generateVerificationString (_converse) {
         propertySort(identities, "lang");
     }
 
-    let S = _.reduce(
-        identities,
-        (result, id) => `${result}${id.category}/${id.type}/${_.get(id, 'lang', '')}/${id.name}<`,
-        "");
-
+    let S = identities.reduce((result, id) => `${result}${id.category}/${id.type}/${get(id, 'lang', '')}/${id.name}<`, "");
     features.sort();
-    S = _.reduce(features, (result, feature) => `${result}${feature}<`, S);
+    S = features.reduce((result, feature) => `${result}${feature}<`, S);
     return SHA1.b64_sha1(S);
 }
 

+ 3 - 3
src/headless/converse-emoji.js

@@ -4,8 +4,8 @@
  * @license Mozilla Public License (MPLv2)
  */
 import { Model } from 'skeletor.js/src/model.js';
+import { find, uniq } from "lodash";
 import * as twemoji from "twemoji";
-import _ from "./lodash.noconflict";
 import converse from "./converse-core";
 
 const u = converse.env.utils;
@@ -118,7 +118,7 @@ converse.plugins.add('converse-emoji', {
 
         function getTonedEmojis () {
             if (!_converse.toned_emojis) {
-                _converse.toned_emojis = _.uniq(
+                _converse.toned_emojis = uniq(
                     Object.values(_converse.emojis.json.people)
                         .filter(person => person.sn.includes('_tone'))
                         .map(person => person.sn.replace(/_tone[1-5]/, ''))
@@ -254,7 +254,7 @@ converse.plugins.add('converse-emoji', {
                     .filter((c, i, arr) => arr.indexOf(c) == i);
 
                 emojis_by_attribute[attr] = {};
-                all_variants.forEach(v => (emojis_by_attribute[attr][v] = _.find(_converse.emojis_list, i => (i[attr] === v))));
+                all_variants.forEach(v => (emojis_by_attribute[attr][v] = find(_converse.emojis_list, i => (i[attr] === v))));
                 return emojis_by_attribute[attr];
             }
         });

+ 15 - 18
src/headless/utils/core.js

@@ -5,7 +5,7 @@
  */
 import * as strophe from 'strophe.js/src/core';
 import { Model } from 'skeletor.js/src/model.js';
-import _ from "../lodash.noconflict";
+import { compact, last, isElement, isObject, isString } from "lodash";
 import log from "@converse/headless/log";
 import sizzle from "sizzle";
 
@@ -81,8 +81,8 @@ u.prefixMentions = function (message) {
 };
 
 u.isValidJID = function (jid) {
-    if (_.isString(jid)) {
-        return _.compact(jid.split('@')).length === 2 && !jid.startsWith('@') && !jid.endsWith('@');
+    if (isString(jid)) {
+        return compact(jid.split('@')).length === 2 && !jid.startsWith('@') && !jid.endsWith('@');
     }
     return false;
 };
@@ -92,7 +92,7 @@ u.isValidMUCJID = function (jid) {
 };
 
 u.isSameBareJID = function (jid1, jid2) {
-    if (!_.isString(jid1) || !_.isString(jid2)) {
+    if (!isString(jid1) || !isString(jid2)) {
         return false;
     }
     return Strophe.getBareJidFromJid(jid1).toLowerCase() ===
@@ -101,7 +101,7 @@ u.isSameBareJID = function (jid1, jid2) {
 
 
 u.isSameDomain = function (jid1, jid2) {
-    if (!_.isString(jid1) || !_.isString(jid2)) {
+    if (!isString(jid1) || !isString(jid2)) {
         return false;
     }
     return Strophe.getDomainFromJid(jid1).toLowerCase() ===
@@ -184,7 +184,7 @@ u.isHeadlineMessage = function (_converse, message) {
     if (u.isChatRoom(chatbox)) {
         return false;
     }
-    if (message.getAttribute('type') !== 'error' && from_jid && !_.includes(from_jid, '@')) {
+    if (message.getAttribute('type') !== 'error' && from_jid && !from_jid.includes('@')) {
         // Some servers (I'm looking at you Prosody) don't set the message
         // type to "headline" when sending server messages. For now we
         // check if an @ signal is included, and if not, we assume it's
@@ -199,21 +199,21 @@ u.isErrorObject = function (o) {
 }
 
 u.isErrorStanza = function (stanza) {
-    if (!_.isElement(stanza)) {
+    if (!isElement(stanza)) {
         return false;
     }
     return stanza.getAttribute('type') === 'error';
 }
 
 u.isForbiddenError = function (stanza) {
-    if (!_.isElement(stanza)) {
+    if (!isElement(stanza)) {
         return false;
     }
     return sizzle(`error[type="auth"] forbidden[xmlns="${Strophe.NS.STANZAS}"]`, stanza).length > 0;
 }
 
 u.isServiceUnavailableError = function (stanza) {
-    if (!_.isElement(stanza)) {
+    if (!isElement(stanza)) {
         return false;
     }
     return sizzle(`error[type="cancel"] service-unavailable[xmlns="${Strophe.NS.STANZAS}"]`, stanza).length > 0;
@@ -223,7 +223,7 @@ u.merge = function merge (first, second) {
     /* Merge the second object into the first one.
      */
     for (var k in second) {
-        if (_.isObject(first[k])) {
+        if (isObject(first[k])) {
             merge(first[k], second[k]);
         } else {
             first[k] = second[k];
@@ -239,7 +239,7 @@ u.applyUserSettings = function applyUserSettings (context, settings, user_settin
         if (user_settings[k] === undefined) {
             continue;
         }
-        if (_.isObject(settings[k]) && !Array.isArray(settings[k])) {
+        if (isObject(settings[k]) && !Array.isArray(settings[k])) {
             applyUserSettings(context[k], settings[k], user_settings[k]);
         } else {
             context[k] = user_settings[k];
@@ -317,15 +317,12 @@ u.queryChildren = function (el, selector) {
 };
 
 u.contains = function (attr, query) {
+    const checker = (item, key) => item.get(key).toLowerCase().includes(query.toLowerCase());
     return function (item) {
         if (typeof attr === 'object') {
-            var value = false;
-            _.forEach(attr, function (a) {
-                value = value || _.includes(item.get(a).toLowerCase(), query.toLowerCase());
-            });
-            return value;
+            return Object.keys(attr).reduce((acc, k) => acc || checker(item, k), false);
         } else if (typeof attr === 'string') {
-            return _.includes(item.get(attr).toLowerCase(), query.toLowerCase());
+            return checker(item, attr);
         } else {
             throw new TypeError('contains: wrong attribute type. Must be string or array.');
         }
@@ -478,7 +475,7 @@ u.getCurrentWord = function (input, index, delineator) {
 
 u.replaceCurrentWord = function (input, new_value) {
     const caret = input.selectionEnd || undefined,
-          current_word = _.last(input.value.slice(0, caret).split(' ')),
+          current_word = last(input.value.slice(0, caret).split(' ')),
           value = input.value;
     input.value = value.slice(0, caret - current_word.length) + `${new_value} ` + value.slice(caret);
     input.selectionEnd = caret - current_word.length + new_value.length + 1;

+ 1 - 3
src/headless/utils/form.js

@@ -3,8 +3,6 @@
  * @license Mozilla Public License (MPLv2)
  * @description This is the form utilities module.
  */
-
-import _ from "../lodash.noconflict";
 import tpl_field from "../templates/field.html";
 import u from "./core";
 
@@ -19,7 +17,7 @@ u.webForm2xForm = function (field) {
     if (field.getAttribute('type') === 'checkbox') {
         value = field.checked && 1 || 0;
     } else if (field.tagName == "TEXTAREA") {
-        value = _.filter(field.value.split('\n'), _.trim);
+        value = field.value.split('\n').filter(s => s.trim());
     } else if (field.tagName == "SELECT") {
         value = u.getSelectValues(field);
     } else {