mirror of
https://github.com/tenrok/OverlayScrollbars.git
synced 2026-06-06 21:32:37 +03:00
sophisticated rollup setup and eslint base setup
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"legacy": {
|
||||
"name": "OverlayScrollbars",
|
||||
"exports": "auto",
|
||||
"globals": {
|
||||
"jquery": "jQuery"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
export { default as not } from 'dir/not.png';
|
||||
import j from 'jquery';
|
||||
var abc = 'abc';
|
||||
const a = 1 + 1;
|
||||
var file = {
|
||||
a
|
||||
};
|
||||
const a$1 = 'a';
|
||||
const b = 'b';
|
||||
const c = 'c';
|
||||
var index = j('div');
|
||||
export default index;
|
||||
export { a$1 as a, abc, b, c, file };
|
||||
//# sourceMappingURL=overlayscrollbars-jquery.esm.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"overlayscrollbars-jquery.esm.js","sources":["../src/dir/abc.js","../src/file.js","../src/test.js","../src/index.js"],"sourcesContent":["export default 'abc';\n","const a = 1 + 1;\nexport default {\n a,\n};\n","export const a = 'a';\nexport const b = 'b';\nexport const c = 'c';\n","import abc from 'dir/abc';\nimport not from 'dir/not.png';\nimport file from 'file';\nimport j from 'jquery';\nimport { a, b, c } from 'test';\n\nexport default j('div');\nexport { a, b, c, file, abc, not };\n"],"names":["a","b","c","j"],"mappings":";;AAAA,UAAe,KAAf;ACAA,MAAMA,CAAC,GAAG,IAAI,CAAd;AACA,WAAe;AACbA,EAAAA;AADa,CAAf;ACDY,MAACA,GAAC,GAAG,GAAL;AACA,MAACC,CAAC,GAAG,GAAL;AACA,MAACC,CAAC,GAAG,GAAL;ACIZ,YAAeC,CAAC,CAAC,KAAD,CAAhB;;"}
|
||||
@@ -0,0 +1 @@
|
||||
export{default as not}from"dir/not.png";import a from"jquery";var r="abc";var o={a:2};const t="a",e="b",p="c";var d=a("div");export default d;export{t as a,r as abc,e as b,p as c,o as file};
|
||||
@@ -0,0 +1,24 @@
|
||||
var OverlayScrollbars = function (exports, not_png, j) {
|
||||
'use strict';
|
||||
|
||||
not_png = not_png && Object.prototype.hasOwnProperty.call(not_png, 'default') ? not_png['default'] : not_png;
|
||||
j = j && Object.prototype.hasOwnProperty.call(j, 'default') ? j['default'] : j;
|
||||
var abc = 'abc';
|
||||
var a = 1 + 1;
|
||||
var file = {
|
||||
a: a
|
||||
};
|
||||
var a$1 = 'a';
|
||||
var b = 'b';
|
||||
var c = 'c';
|
||||
var index = j('div');
|
||||
exports.not = not_png;
|
||||
exports.a = a$1;
|
||||
exports.abc = abc;
|
||||
exports.b = b;
|
||||
exports.c = c;
|
||||
exports.default = index;
|
||||
exports.file = file;
|
||||
return exports;
|
||||
}({}, not_png, jQuery);
|
||||
//# sourceMappingURL=overlayscrollbars-jquery.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"overlayscrollbars-jquery.js","sources":["../src/dir/abc.js","../src/file.js","../src/test.js","../src/index.js"],"sourcesContent":["export default 'abc';\n","const a = 1 + 1;\nexport default {\n a,\n};\n","export const a = 'a';\nexport const b = 'b';\nexport const c = 'c';\n","import abc from 'dir/abc';\nimport not from 'dir/not.png';\nimport file from 'file';\nimport j from 'jquery';\nimport { a, b, c } from 'test';\n\nexport default j('div');\nexport { a, b, c, file, abc, not };\n"],"names":["a","b","c","j"],"mappings":";;;;;YAAe;ACAf,MAAMA,CAAC,GAAG,IAAI,CAAd;aACe;AACbA,IAAAA,CAAC,EAADA;AADa;MCDFA,GAAC,GAAG;MACJC,CAAC,GAAG;MACJC,CAAC,GAAG;cCIFC,CAAC,CAAC,KAAD;;;;;;;;;"}
|
||||
@@ -0,0 +1 @@
|
||||
var OverlayScrollbars=function(t,a,e){"use strict";a=a&&Object.prototype.hasOwnProperty.call(a,"default")?a.default:a;var r={a:2},l=(e=e&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e)("div");return t.not=a,t.a="a",t.abc="abc",t.b="b",t.c="c",t.default=l,t.file=r,t}({},not_png,jQuery);
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"version": "0.0.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"@types/jquery": {
|
||||
"version": "3.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.0.tgz",
|
||||
"integrity": "sha512-C7qQUjpMWDUNYQRTXsP5nbYYwCwwgy84yPgoTT7fPN69NH92wLeCtFaMsWeolJD1AF/6uQw3pYt62rzv83sMmw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/sizzle": "*"
|
||||
}
|
||||
},
|
||||
"@types/sizzle": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.2.tgz",
|
||||
"integrity": "sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg==",
|
||||
"dev": true
|
||||
},
|
||||
"jquery": {
|
||||
"version": "3.5.1",
|
||||
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.5.1.tgz",
|
||||
"integrity": "sha512-XwIBPqcMn57FxfT+Go5pzySnm4KWkT1Tv7gjrpT1srtf8Weynl6R273VJ5GjkRb51IzMp5nbaPjJXMWeju2MKg=="
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"private": true,
|
||||
"description": "OverlayScrollbars version 2",
|
||||
"version": "0.0.1",
|
||||
"peerDependencies": {
|
||||
"jquery": "^3.5.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jquery": "^3.5.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export default 'abc';
|
||||
@@ -0,0 +1,4 @@
|
||||
const a = 1 + 1;
|
||||
export default {
|
||||
a,
|
||||
};
|
||||
@@ -0,0 +1,8 @@
|
||||
import abc from 'dir/abc';
|
||||
import not from 'dir/not.png';
|
||||
import file from 'file';
|
||||
import j from 'jquery';
|
||||
import { a, b, c } from 'test';
|
||||
|
||||
export default j('div');
|
||||
export { a, b, c, file, abc, not };
|
||||
@@ -0,0 +1,3 @@
|
||||
export const a = 'a';
|
||||
export const b = 'b';
|
||||
export const c = 'c';
|
||||
@@ -1,10 +1,9 @@
|
||||
{
|
||||
"minVersions": true,
|
||||
"umd": {
|
||||
"legacy": {
|
||||
"name": "OverlayScrollbars",
|
||||
"exports": "auto",
|
||||
"globals": {
|
||||
"jquery": "jQuery"
|
||||
}
|
||||
},
|
||||
"esm": {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
function isNumber(obj) {
|
||||
return typeof obj === 'number';
|
||||
}
|
||||
|
||||
function isFunction(obj) {
|
||||
return typeof obj === 'function';
|
||||
}
|
||||
|
||||
function isArray(obj) {
|
||||
return Array.isArray(obj);
|
||||
}
|
||||
|
||||
function isArrayLike(obj) {
|
||||
const length = !!obj && obj.length;
|
||||
return isArray(obj) || !isFunction(obj) && isNumber(length) && length > -1 && length % 1 == 0;
|
||||
}
|
||||
|
||||
const keys = obj => Object.keys(obj);
|
||||
|
||||
function each(source, callback) {
|
||||
if (isArrayLike(source)) {
|
||||
for (let i = 0; i < source.length; i++) {
|
||||
if (callback(source[i], i, source) === false) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (source) {
|
||||
each(keys(source), key => callback(source[key], key, source));
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
const contents = elm => elm ? Array.from(elm.childNodes) : [];
|
||||
|
||||
const removeElements = nodes => {
|
||||
if (isArrayLike(nodes)) {
|
||||
each(Array.from(nodes), e => removeElements(e));
|
||||
} else if (nodes) {
|
||||
const {
|
||||
parentNode
|
||||
} = nodes;
|
||||
|
||||
if (parentNode) {
|
||||
parentNode.removeChild(nodes);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const createDiv = () => document.createElement('div');
|
||||
|
||||
const createDOM = html => {
|
||||
const createdDiv = createDiv();
|
||||
createdDiv.innerHTML = html.trim();
|
||||
return each(contents(createdDiv), elm => removeElements(elm));
|
||||
};
|
||||
|
||||
const abc = {
|
||||
a: 1,
|
||||
b: 1,
|
||||
c: 1
|
||||
};
|
||||
|
||||
var index = () => {
|
||||
const {
|
||||
a,
|
||||
b,
|
||||
c
|
||||
} = abc;
|
||||
return [createDOM('\
|
||||
<div class="os-host">\
|
||||
<div class="os-resize-observer-host"></div>\
|
||||
<div class="os-padding">\
|
||||
<div class="os-viewport">\
|
||||
<div class="os-content">\
|
||||
fdfhdfgh\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>\
|
||||
<div class="os-scrollbar os-scrollbar-horizontal">\
|
||||
<div class="os-scrollbar-track">\
|
||||
<div class="os-scrollbar-handle"></div>\
|
||||
</div>\
|
||||
</div>\
|
||||
<div class="os-scrollbar os-scrollbar-vertical">\
|
||||
<div class="os-scrollbar-track">\
|
||||
<div class="os-scrollbar-handle"></div>\
|
||||
</div>\
|
||||
</div>\
|
||||
<div class="os-scrollbar-corner"></div>\
|
||||
</div>'), a, b, c];
|
||||
};
|
||||
|
||||
const a = 1;
|
||||
export default index;
|
||||
export { a };
|
||||
//# sourceMappingURL=overlayscrollbars.esm.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
function r(r){const s=!!r&&r.length;return function(r){return Array.isArray(r)}(r)||!function(r){return"function"==typeof r}(r)&&function(r){return"number"==typeof r}(s)&&s>-1&&s%1==0}function s(o,c){if(r(o))for(let r=0;r<o.length&&!1!==c(o[r],r,o);r++);else o&&s((i=o,Object.keys(i)),r=>c(o[r],r,o));var i;return o}const o=c=>{if(r(c))s(Array.from(c),r=>o(r));else if(c){const{parentNode:r}=c;r&&r.removeChild(c)}},c=r=>{const c=document.createElement("div");return c.innerHTML=r.trim(),s((i=c)?Array.from(i.childNodes):[],r=>o(r));var i},i={a:1,b:1,c:1};const e=1;export default()=>{const{a:r,b:s,c:o}=i;return[c(' <div class="os-host"> <div class="os-resize-observer-host"></div> <div class="os-padding"> <div class="os-viewport"> <div class="os-content"> fdfhdfgh </div> </div> </div> <div class="os-scrollbar os-scrollbar-horizontal"> <div class="os-scrollbar-track"> <div class="os-scrollbar-handle"></div> </div> </div> <div class="os-scrollbar os-scrollbar-vertical"> <div class="os-scrollbar-track"> <div class="os-scrollbar-handle"></div> </div> </div> <div class="os-scrollbar-corner"></div> </div>'),r,s,o]};export{e as a};
|
||||
@@ -0,0 +1,110 @@
|
||||
var OverlayScrollbars = function (exports) {
|
||||
'use strict';
|
||||
|
||||
function isNumber(obj) {
|
||||
return typeof obj === 'number';
|
||||
}
|
||||
|
||||
function isFunction(obj) {
|
||||
return typeof obj === 'function';
|
||||
}
|
||||
|
||||
function isArray(obj) {
|
||||
return Array.isArray(obj);
|
||||
}
|
||||
|
||||
function isArrayLike(obj) {
|
||||
var length = !!obj && obj.length;
|
||||
return isArray(obj) || !isFunction(obj) && isNumber(length) && length > -1 && length % 1 == 0;
|
||||
}
|
||||
|
||||
var keys = function keys(obj) {
|
||||
return Object.keys(obj);
|
||||
};
|
||||
|
||||
function each(source, callback) {
|
||||
if (isArrayLike(source)) {
|
||||
for (var i = 0; i < source.length; i++) {
|
||||
if (callback(source[i], i, source) === false) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (source) {
|
||||
each(keys(source), function (key) {
|
||||
return callback(source[key], key, source);
|
||||
});
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
var contents = function contents(elm) {
|
||||
return elm ? Array.from(elm.childNodes) : [];
|
||||
};
|
||||
|
||||
var removeElements = function removeElements(nodes) {
|
||||
if (isArrayLike(nodes)) {
|
||||
each(Array.from(nodes), function (e) {
|
||||
return removeElements(e);
|
||||
});
|
||||
} else if (nodes) {
|
||||
var parentNode = nodes.parentNode;
|
||||
|
||||
if (parentNode) {
|
||||
parentNode.removeChild(nodes);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var createDiv = function createDiv() {
|
||||
return document.createElement('div');
|
||||
};
|
||||
|
||||
var createDOM = function createDOM(html) {
|
||||
var createdDiv = createDiv();
|
||||
createdDiv.innerHTML = html.trim();
|
||||
return each(contents(createdDiv), function (elm) {
|
||||
return removeElements(elm);
|
||||
});
|
||||
};
|
||||
|
||||
var abc = {
|
||||
a: 1,
|
||||
b: 1,
|
||||
c: 1
|
||||
};
|
||||
|
||||
var index = function index() {
|
||||
var a = abc.a,
|
||||
b = abc.b,
|
||||
c = abc.c;
|
||||
return [createDOM('\
|
||||
<div class="os-host">\
|
||||
<div class="os-resize-observer-host"></div>\
|
||||
<div class="os-padding">\
|
||||
<div class="os-viewport">\
|
||||
<div class="os-content">\
|
||||
fdfhdfgh\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>\
|
||||
<div class="os-scrollbar os-scrollbar-horizontal">\
|
||||
<div class="os-scrollbar-track">\
|
||||
<div class="os-scrollbar-handle"></div>\
|
||||
</div>\
|
||||
</div>\
|
||||
<div class="os-scrollbar os-scrollbar-vertical">\
|
||||
<div class="os-scrollbar-track">\
|
||||
<div class="os-scrollbar-handle"></div>\
|
||||
</div>\
|
||||
</div>\
|
||||
<div class="os-scrollbar-corner"></div>\
|
||||
</div>'), a, b, c];
|
||||
};
|
||||
|
||||
var a = 1;
|
||||
exports.a = a;
|
||||
exports.default = index;
|
||||
return exports;
|
||||
}({});
|
||||
//# sourceMappingURL=overlayscrollbars.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
var OverlayScrollbars=function(r){"use strict";function s(r){var s=!!r&&r.length;return function(r){return Array.isArray(r)}(r)||!function(r){return"function"==typeof r}(r)&&function(r){return"number"==typeof r}(s)&&s>-1&&s%1==0}function o(r,i){if(s(r))for(var n=0;n<r.length&&!1!==i(r[n],n,r);n++);else r&&o((a=r,Object.keys(a)),(function(s){return i(r[s],s,r)}));var a;return r}var i=function(r){var i,n=document.createElement("div");return n.innerHTML=r.trim(),o((i=n)?Array.from(i.childNodes):[],(function(r){return function r(i){if(s(i))o(Array.from(i),(function(s){return r(s)}));else if(i){var n=i.parentNode;n&&n.removeChild(i)}}(r)}))},n=1,a=1,e=1;return r.a=1,r.default=function(){var r=n,s=a,o=e;return[i(' <div class="os-host"> <div class="os-resize-observer-host"></div> <div class="os-padding"> <div class="os-viewport"> <div class="os-content"> fdfhdfgh </div> </div> </div> <div class="os-scrollbar os-scrollbar-horizontal"> <div class="os-scrollbar-track"> <div class="os-scrollbar-handle"></div> </div> </div> <div class="os-scrollbar os-scrollbar-vertical"> <div class="os-scrollbar-track"> <div class="os-scrollbar-handle"></div> </div> </div> <div class="os-scrollbar-corner"></div> </div>'),r,s,o]},r}({});
|
||||
@@ -1,16 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="description" content="Server Syncing API Code Challenge" />
|
||||
<title>Server Syncing API</title>
|
||||
</head>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<body>
|
||||
<div id="hi">hi</div>
|
||||
<script type="text/javascript" src="./dist/overlayscrollbars.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+19
-19
@@ -1,22 +1,22 @@
|
||||
{
|
||||
"version": "0.0.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"@types/jquery": {
|
||||
"version": "3.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.0.tgz",
|
||||
"integrity": "sha512-C7qQUjpMWDUNYQRTXsP5nbYYwCwwgy84yPgoTT7fPN69NH92wLeCtFaMsWeolJD1AF/6uQw3pYt62rzv83sMmw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/sizzle": "*"
|
||||
}
|
||||
},
|
||||
"@types/sizzle": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.2.tgz",
|
||||
"integrity": "sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg==",
|
||||
"dev": true
|
||||
}
|
||||
"version": "0.0.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"@types/jquery": {
|
||||
"version": "3.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.0.tgz",
|
||||
"integrity": "sha512-C7qQUjpMWDUNYQRTXsP5nbYYwCwwgy84yPgoTT7fPN69NH92wLeCtFaMsWeolJD1AF/6uQw3pYt62rzv83sMmw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/sizzle": "*"
|
||||
}
|
||||
},
|
||||
"@types/sizzle": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.2.tgz",
|
||||
"integrity": "sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
{
|
||||
"private": true,
|
||||
"description": "OverlayScrollbars version 2",
|
||||
"version": "0.0.1",
|
||||
"peerDependencies": {
|
||||
"jquery": "^3.5.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jquery": "^3.5.0"
|
||||
}
|
||||
"private": true,
|
||||
"description": "OverlayScrollbars version 2",
|
||||
"version": "0.0.1"
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import { jsAPI } from 'core/compatibility/vendors';
|
||||
|
||||
export const resizeObserver: any | undefined = jsAPI('ResizeObserver');
|
||||
export const resizeObserver: any | undefined = jsAPI('ResizeObserver');
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export const mouseButton: (event: MouseEvent) => number = (event) => {
|
||||
const button: number = event.button;
|
||||
if (!event.which && button !== undefined)
|
||||
return (button & 1 ? 1 : (button & 2 ? 3 : (button & 4 ? 2 : 0)));
|
||||
else
|
||||
return event.which;
|
||||
}
|
||||
const { button } = event;
|
||||
if (!event.which && button !== undefined) {
|
||||
return button & 1 ? 1 : button & 2 ? 3 : button & 4 ? 2 : 0; // eslint-disable-line no-bitwise
|
||||
}
|
||||
return event.which;
|
||||
};
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
export * from 'core/compatibility/vendors';
|
||||
export * from 'core/compatibility/apis';
|
||||
export * from 'core/compatibility/events';
|
||||
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
import { each } from 'core/utils';
|
||||
import { each, hasOwnProperty } from 'core/utils';
|
||||
import { createDiv } from 'core/dom';
|
||||
|
||||
const firstLetterToUpper: (str: string) => string = (str) => {
|
||||
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||
}
|
||||
const getDummyStyle: () => CSSStyleDeclaration = () => {
|
||||
return createDiv().style;
|
||||
}
|
||||
const firstLetterToUpper: (str: string) => string = (str) => str.charAt(0).toUpperCase() + str.slice(1);
|
||||
const getDummyStyle: () => CSSStyleDeclaration = () => createDiv().style;
|
||||
|
||||
//https://developer.mozilla.org/en-US/docs/Glossary/Vendor_Prefix
|
||||
// https://developer.mozilla.org/en-US/docs/Glossary/Vendor_Prefix
|
||||
|
||||
export const cssPrefixes: ReadonlyArray<string> = ['-webkit-', '-moz-', '-o-', '-ms-'];
|
||||
export const jsPrefixes: ReadonlyArray<string> = ['WebKit', 'Moz', 'O', 'MS', 'webkit', 'moz', 'o', 'ms'];
|
||||
@@ -21,79 +17,82 @@ export const cssCache: { [key: string]: string } = {};
|
||||
* @param name The name of the CSS property which shall be get.
|
||||
*/
|
||||
export const cssProperty: (name: string) => string | undefined = (name) => {
|
||||
let result: string | undefined = cssCache[name];
|
||||
let result: string | undefined = cssCache[name];
|
||||
|
||||
if (cssCache.hasOwnProperty(name))
|
||||
return result;
|
||||
|
||||
const uppercasedName: string = firstLetterToUpper(name);
|
||||
const elmStyle: CSSStyleDeclaration = getDummyStyle();
|
||||
|
||||
each(cssPrefixes, (prefix: string) => {
|
||||
const prefixWithoutDashes: string = prefix.replace(/-/g, '');
|
||||
const resultPossibilities: Array<string> = [
|
||||
name, //transition
|
||||
prefix + name, //-webkit-transition
|
||||
prefixWithoutDashes + uppercasedName, //webkitTransition
|
||||
firstLetterToUpper(prefixWithoutDashes) + uppercasedName //WebkitTransition
|
||||
];
|
||||
result = resultPossibilities.find((resultPossibility: string) => elmStyle[resultPossibility] !== undefined);
|
||||
return !result;
|
||||
});
|
||||
|
||||
cssCache[name] = result;
|
||||
if (hasOwnProperty(cssCache, name)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
const uppercasedName: string = firstLetterToUpper(name);
|
||||
const elmStyle: CSSStyleDeclaration = getDummyStyle();
|
||||
|
||||
each(cssPrefixes, (prefix: string) => {
|
||||
const prefixWithoutDashes: string = prefix.replace(/-/g, '');
|
||||
const resultPossibilities: Array<string> = [
|
||||
name, // transition
|
||||
prefix + name, // -webkit-transition
|
||||
prefixWithoutDashes + uppercasedName, // webkitTransition
|
||||
firstLetterToUpper(prefixWithoutDashes) + uppercasedName, // WebkitTransition
|
||||
];
|
||||
result = resultPossibilities.find((resultPossibility: string) => elmStyle[resultPossibility] !== undefined);
|
||||
return !result;
|
||||
});
|
||||
|
||||
cssCache[name] = result;
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the name of the given CSS property value(s), with vendor prefix if it isn't supported wuthout, or undefined if no value is supported.
|
||||
* Get the name of the given CSS property value(s), with vendor prefix if it isn't supported wuthout, or undefined if no value is supported.
|
||||
* @param property The CSS property to which the CSS property value(s) belong.
|
||||
* @param values The value(s) separated by spaces which shall be get.
|
||||
* @param suffix A suffix which is added to each value in case the value is a function or something else more advanced.
|
||||
*/
|
||||
export const cssPropertyValue: (property: string, values: string, suffix?: string) => string | undefined = (property, values, suffix) => {
|
||||
const name: string = property + ' ' + values;
|
||||
let result: string | undefined = cssCache[name];
|
||||
const name = `${property} ${values}`;
|
||||
let result: string | undefined = cssCache[name];
|
||||
|
||||
if (cssCache.hasOwnProperty(name))
|
||||
return result;
|
||||
|
||||
const dummyStyle: CSSStyleDeclaration = getDummyStyle();
|
||||
const possbleValues: Array<string> = values.split(' ');
|
||||
const preparedSuffix: string = suffix || '';
|
||||
const cssPrefixesWithFirstEmpty = [''].concat(cssPrefixes);
|
||||
|
||||
each(possbleValues, (possibleValue: string) => {
|
||||
each(cssPrefixesWithFirstEmpty, (prefix: string) => {
|
||||
const prop = prefix + possibleValue;
|
||||
dummyStyle.cssText = property + ':' + prop + preparedSuffix;
|
||||
if (dummyStyle.length) {
|
||||
result = prop;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
return !result;
|
||||
});
|
||||
|
||||
cssCache[name] = result;
|
||||
if (hasOwnProperty(cssCache, name)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
const dummyStyle: CSSStyleDeclaration = getDummyStyle();
|
||||
const possbleValues: Array<string> = values.split(' ');
|
||||
const preparedSuffix: string = suffix || '';
|
||||
const cssPrefixesWithFirstEmpty = [''].concat(cssPrefixes);
|
||||
|
||||
each(possbleValues, (possibleValue: string) => {
|
||||
each(cssPrefixesWithFirstEmpty, (prefix: string) => {
|
||||
const prop = prefix + possibleValue;
|
||||
dummyStyle.cssText = `${property}:${prop}${preparedSuffix}`;
|
||||
if (dummyStyle.length) {
|
||||
result = prop;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
return !result;
|
||||
});
|
||||
|
||||
cssCache[name] = result;
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the requested JS function, object or constructor with vendor prefix if it isn't supported without or undefined if unsupported.
|
||||
* @param name The name of the JS function, object or constructor.
|
||||
*/
|
||||
export const jsAPI: (name: string) => any = (name) => {
|
||||
let result: any = jsCache[name] || window[name];
|
||||
let result: any = jsCache[name] || window[name];
|
||||
|
||||
if (jsCache.hasOwnProperty(name))
|
||||
return result;
|
||||
|
||||
each(jsPrefixes, (prefix: string) => {
|
||||
result = result || window[prefix + firstLetterToUpper(name)];
|
||||
return !result;
|
||||
});
|
||||
|
||||
jsCache[name] = result;
|
||||
if (hasOwnProperty(jsCache, name)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
each(jsPrefixes, (prefix: string) => {
|
||||
result = result || window[prefix + firstLetterToUpper(name)];
|
||||
return !result;
|
||||
});
|
||||
|
||||
jsCache[name] = result;
|
||||
return result;
|
||||
};
|
||||
|
||||
+22
-18
@@ -6,10 +6,11 @@
|
||||
* @param value The value of the attribute which shall be set.
|
||||
*/
|
||||
export const attr: (elm: Element, attrName: string, value?: string) => string | null | void = (elm, attrName, value) => {
|
||||
if (value === undefined)
|
||||
return elm.getAttribute(attrName);
|
||||
elm.setAttribute(attrName, value);
|
||||
}
|
||||
if (value === undefined) {
|
||||
return elm.getAttribute(attrName);
|
||||
}
|
||||
elm.setAttribute(attrName, value);
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes the given attribute from the given element.
|
||||
@@ -17,8 +18,8 @@ export const attr: (elm: Element, attrName: string, value?: string) => string |
|
||||
* @param attrName The attribute name.
|
||||
*/
|
||||
export const removeAttr: (elm: Element, attrName: string) => void = (elm, attrName) => {
|
||||
elm.removeAttribute(attrName);
|
||||
}
|
||||
elm.removeAttribute(attrName);
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets or sets the scrollLeft value of the given element depending whether the value attribute is given.
|
||||
@@ -26,10 +27,11 @@ export const removeAttr: (elm: Element, attrName: string) => void = (elm, attrNa
|
||||
* @param value The scrollLeft value which shall be set.
|
||||
*/
|
||||
export const scrollLeft: (elm: HTMLElement, value?: number) => number | void = (elm, value) => {
|
||||
if (value === undefined)
|
||||
return elm.scrollLeft;
|
||||
elm.scrollLeft = value;
|
||||
}
|
||||
if (value === undefined) {
|
||||
return elm.scrollLeft;
|
||||
}
|
||||
elm.scrollLeft = value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets or sets the scrollTop value of the given element depending whether the value attribute is given.
|
||||
@@ -37,10 +39,11 @@ export const scrollLeft: (elm: HTMLElement, value?: number) => number | void = (
|
||||
* @param value The scrollTop value which shall be set.
|
||||
*/
|
||||
export const scrollTop: (elm: HTMLElement, value?: number) => number | void = (elm, value) => {
|
||||
if (value === undefined)
|
||||
return elm.scrollTop;
|
||||
elm.scrollTop = value;
|
||||
}
|
||||
if (value === undefined) {
|
||||
return elm.scrollTop;
|
||||
}
|
||||
elm.scrollTop = value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets or sets the value of the given input element depending whether the value attribute is given.
|
||||
@@ -48,7 +51,8 @@ export const scrollTop: (elm: HTMLElement, value?: number) => number | void = (e
|
||||
* @param value The value which shall be set.
|
||||
*/
|
||||
export const val: (elm: HTMLInputElement, value?: string) => string | void = (elm, value) => {
|
||||
if (value === undefined)
|
||||
return elm.value;
|
||||
elm.value = value;
|
||||
}
|
||||
if (value === undefined) {
|
||||
return elm.value;
|
||||
}
|
||||
elm.value = value;
|
||||
};
|
||||
+24
-25
@@ -1,15 +1,13 @@
|
||||
import { isString } from 'core/utils/types';
|
||||
|
||||
const rnothtmlwhite: RegExp = (/[^\x20\t\r\n\f]+/g);
|
||||
const rnothtmlwhite = /[^\x20\t\r\n\f]+/g;
|
||||
|
||||
/**
|
||||
* Check whether the given element has the given class name.
|
||||
* @param elm The element.
|
||||
* @param className The class name.
|
||||
*/
|
||||
export const hasClass: (elm: Element, className: string) => boolean = (elm, className) => {
|
||||
return elm.classList.contains(className);
|
||||
}
|
||||
export const hasClass: (elm: Element, className: string) => boolean = (elm, className) => elm.classList.contains(className);
|
||||
|
||||
/**
|
||||
* Adds the given class name(s) to the given element.
|
||||
@@ -17,15 +15,16 @@ export const hasClass: (elm: Element, className: string) => boolean = (elm, clas
|
||||
* @param className The class name(s) which shall be added. (separated by spaces)
|
||||
*/
|
||||
export const addClass: (elm: Element, className: string) => void = (elm, className) => {
|
||||
let clazz: string;
|
||||
let i: number = 0;
|
||||
let clazz: string;
|
||||
let i = 0;
|
||||
|
||||
if (isString(className)) {
|
||||
const classes: Array<string> = className.match(rnothtmlwhite) || [];
|
||||
while ((clazz = classes[i++]))
|
||||
elm.classList.add(clazz);
|
||||
if (isString(className)) {
|
||||
const classes: Array<string> = className.match(rnothtmlwhite) || [];
|
||||
while ((clazz = classes[i++])) {
|
||||
elm.classList.add(clazz);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes the given class name(s) from the given element.
|
||||
@@ -33,15 +32,16 @@ export const addClass: (elm: Element, className: string) => void = (elm, classNa
|
||||
* @param className The class name(s) which shall be removed. (separated by spaces)
|
||||
*/
|
||||
export const removeClass: (elm: Element, className: string) => void = (elm, className) => {
|
||||
let clazz: string;
|
||||
let i: number = 0;
|
||||
let clazz: string;
|
||||
let i = 0;
|
||||
|
||||
if (isString(className)) {
|
||||
const classes: Array<string> = className.match(rnothtmlwhite) || [];
|
||||
while ((clazz = classes[i++]))
|
||||
elm.classList.remove(clazz);
|
||||
if (isString(className)) {
|
||||
const classes: Array<string> = className.match(rnothtmlwhite) || [];
|
||||
while ((clazz = classes[i++])) {
|
||||
elm.classList.remove(clazz);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds or removes the given class name(s) from the given element depending on the given condition.
|
||||
@@ -50,10 +50,9 @@ export const removeClass: (elm: Element, className: string) => void = (elm, clas
|
||||
* @param className The class name(s) which shall be added or removed. (separated by spaces)
|
||||
*/
|
||||
export const conditionalClass: (elm: Element, className: string, condition: boolean) => void = (elm, className, condition) => {
|
||||
if (condition) {
|
||||
addClass(elm, className);
|
||||
}
|
||||
else {
|
||||
removeClass(elm, className);
|
||||
}
|
||||
}
|
||||
if (condition) {
|
||||
addClass(elm, className);
|
||||
} else {
|
||||
removeClass(elm, className);
|
||||
}
|
||||
};
|
||||
@@ -1,14 +1,12 @@
|
||||
import { each } from 'core/utils/arrays';
|
||||
import { each } from 'core/utils/array';
|
||||
import { contents } from 'core/dom/traversal';
|
||||
import { removeElements } from 'core/dom/manipulation';
|
||||
|
||||
export const createDiv: () => HTMLDivElement = () => {
|
||||
return document.createElement('div');
|
||||
}
|
||||
export const createDiv: () => HTMLDivElement = () => document.createElement('div');
|
||||
|
||||
export const createDOM: (html: string) => ReadonlyArray<Node> = (html) => {
|
||||
const elm = createDiv();
|
||||
elm.innerHTML = html.trim();
|
||||
const createdDiv = createDiv();
|
||||
createdDiv.innerHTML = html.trim();
|
||||
|
||||
return each(contents(elm), (elm) => removeElements(elm));
|
||||
}
|
||||
return each(contents(createdDiv), (elm) => removeElements(elm));
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export * from 'core/dom/attributes';
|
||||
export * from 'core/dom/classes';
|
||||
export * from 'core/dom/attribute';
|
||||
export * from 'core/dom/class';
|
||||
export * from 'core/dom/create';
|
||||
export * from 'core/dom/style';
|
||||
export * from 'core/dom/manipulation';
|
||||
export * from 'core/dom/offset';
|
||||
export * from 'core/dom/traversal';
|
||||
export * from 'core/dom/traversal';
|
||||
|
||||
@@ -1,91 +1,101 @@
|
||||
import { isArrayLike, isHTMLElement } from 'core/utils/types';
|
||||
import { each } from 'core/utils/arrays';
|
||||
import { isArrayLike } from 'core/utils/types';
|
||||
import { each } from 'core/utils/array';
|
||||
import { parent } from 'core/dom/traversal';
|
||||
|
||||
type NodeCollection = ArrayLike<Node> | Node | undefined | null;
|
||||
|
||||
/**
|
||||
* Inserts Nodes before the given preferredAnchor element.
|
||||
* @param parent The parent of the preferredAnchor element or the element which shall be the parent of the inserted Nodes.
|
||||
* @param parentElm The parent of the preferredAnchor element or the element which shall be the parent of the inserted Nodes.
|
||||
* @param preferredAnchor The element before which the Nodes shall be inserted or null if the elements shall be appended at the end.
|
||||
* @param insertedElms The Nodes which shall be inserted.
|
||||
*/
|
||||
const before: (parent: Node | null, preferredAnchor: Node | null, insertedElms: NodeCollection) => void = (parent, preferredAnchor, insertedElms) => {
|
||||
if (insertedElms) {
|
||||
let anchor: Node | null = preferredAnchor;
|
||||
let fragment: DocumentFragment | Node | undefined | null;
|
||||
const before: (parentElm: Node | null, preferredAnchor: Node | null, insertedElms: NodeCollection) => void = (
|
||||
parentElm,
|
||||
preferredAnchor,
|
||||
insertedElms,
|
||||
) => {
|
||||
if (insertedElms) {
|
||||
let anchor: Node | null = preferredAnchor;
|
||||
let fragment: DocumentFragment | Node | undefined | null;
|
||||
|
||||
// parent must be defined
|
||||
if (parent) {
|
||||
if (isArrayLike(insertedElms)) {
|
||||
fragment = document.createDocumentFragment();
|
||||
// parent must be defined
|
||||
if (parentElm) {
|
||||
if (isArrayLike(insertedElms)) {
|
||||
fragment = document.createDocumentFragment();
|
||||
|
||||
// append all insertedElms to the fragment and if one of these is the anchor, change the anchor
|
||||
each(insertedElms, (insertedElm) => {
|
||||
if (insertedElm === anchor) {
|
||||
anchor = insertedElm.previousSibling;
|
||||
}
|
||||
fragment!.appendChild(insertedElm);
|
||||
});
|
||||
}
|
||||
else {
|
||||
fragment = insertedElms;
|
||||
}
|
||||
// append all insertedElms to the fragment and if one of these is the anchor, change the anchor
|
||||
each(insertedElms, (insertedElm) => {
|
||||
if (insertedElm === anchor) {
|
||||
anchor = insertedElm.previousSibling;
|
||||
}
|
||||
fragment!.appendChild(insertedElm);
|
||||
});
|
||||
} else {
|
||||
fragment = insertedElms;
|
||||
}
|
||||
|
||||
// if the preferred anchor isn't null set it to a valid anchor
|
||||
if (preferredAnchor) {
|
||||
if (!anchor) {
|
||||
anchor = parent.firstChild;
|
||||
}
|
||||
else if (anchor !== preferredAnchor) {
|
||||
anchor = anchor.nextSibling;
|
||||
}
|
||||
}
|
||||
|
||||
parent.insertBefore(fragment, anchor);
|
||||
// if the preferred anchor isn't null set it to a valid anchor
|
||||
if (preferredAnchor) {
|
||||
if (!anchor) {
|
||||
anchor = parentElm.firstChild;
|
||||
} else if (anchor !== preferredAnchor) {
|
||||
anchor = anchor.nextSibling;
|
||||
}
|
||||
}
|
||||
|
||||
parentElm.insertBefore(fragment, anchor);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Appends the given children at the end of the given Node.
|
||||
* @param node The Node to which the children shall be appended.
|
||||
* @param children The Nodes which shall be appended.
|
||||
*/
|
||||
export const appendChildren: (node: Node | null, children: NodeCollection) => void = (node, children) => { before(node, null, children) };
|
||||
export const appendChildren: (node: Node | null, children: NodeCollection) => void = (node, children) => {
|
||||
before(node, null, children);
|
||||
};
|
||||
|
||||
/**
|
||||
* Prepends the given children at the start of the given Node.
|
||||
* @param node The Node to which the children shall be prepended.
|
||||
* @param children The Nodes which shall be prepended.
|
||||
*/
|
||||
export const prependChildren: (node: Node | null, children: NodeCollection) => void = (node, children) => { before(node, node && node.firstChild, children) };
|
||||
export const prependChildren: (node: Node | null, children: NodeCollection) => void = (node, children) => {
|
||||
before(node, node && node.firstChild, children);
|
||||
};
|
||||
|
||||
/**
|
||||
* Inserts the given Nodes before the given Node.
|
||||
* @param node The Node before which the given Nodes shall be inserted.
|
||||
* @param insertedNodes The Nodes which shall be inserted.
|
||||
*/
|
||||
export const insertBefore: (node: Node | null, insertedNodes: NodeCollection) => void = (node, insertedNodes) => { before(parent(node), node, insertedNodes) };
|
||||
export const insertBefore: (node: Node | null, insertedNodes: NodeCollection) => void = (node, insertedNodes) => {
|
||||
before(parent(node), node, insertedNodes);
|
||||
};
|
||||
|
||||
/**
|
||||
* Inserts the given Nodes after the given Node.
|
||||
* @param node The Node after which the given Nodes shall be inserted.
|
||||
* @param insertedNodes The Nodes which shall be inserted.
|
||||
*/
|
||||
export const insertAfter: (node: Node | null, insertedNodes: NodeCollection) => void = (node, insertedNodes) => { before(parent(node), node && node.nextSibling, insertedNodes) };
|
||||
export const insertAfter: (node: Node | null, insertedNodes: NodeCollection) => void = (node, insertedNodes) => {
|
||||
before(parent(node), node && node.nextSibling, insertedNodes);
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes the given Nodes from their parent.
|
||||
* @param nodes The Nodes which shall be removed.
|
||||
*/
|
||||
export const removeElements: (nodes: NodeCollection) => void = (nodes) => {
|
||||
if (isArrayLike(nodes)) {
|
||||
each(Array.from(nodes), (e) => removeElements(e));
|
||||
if (isArrayLike(nodes)) {
|
||||
each(Array.from(nodes), (e) => removeElements(e));
|
||||
} else if (nodes) {
|
||||
const { parentNode } = nodes;
|
||||
if (parentNode) {
|
||||
parentNode.removeChild(nodes);
|
||||
}
|
||||
else if (nodes) {
|
||||
const parentNode = nodes.parentNode;
|
||||
if (parentNode)
|
||||
parentNode.removeChild(nodes);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
export const offset = (elm: HTMLElement) => {
|
||||
const rect = elm.getBoundingClientRect();
|
||||
return {
|
||||
top: rect.top + window.pageXOffset,
|
||||
left: rect.left + window.pageYOffset
|
||||
};
|
||||
}
|
||||
const rect = elm.getBoundingClientRect();
|
||||
return {
|
||||
top: rect.top + window.pageXOffset,
|
||||
left: rect.left + window.pageYOffset,
|
||||
};
|
||||
};
|
||||
|
||||
export const position = (elm: HTMLElement) => {
|
||||
return {
|
||||
top: elm.offsetTop,
|
||||
left: elm.offsetLeft
|
||||
};
|
||||
}
|
||||
export const position = (elm: HTMLElement) => ({
|
||||
top: elm.offsetTop,
|
||||
left: elm.offsetLeft,
|
||||
});
|
||||
|
||||
@@ -1,62 +1,57 @@
|
||||
import { keys } from 'core/utils/object';
|
||||
import { isString, isNumber, isUndefined } from 'core/utils/types';
|
||||
|
||||
type cssStyleObj = { [key: string]: string | number };
|
||||
|
||||
const cssNumber = {
|
||||
animationIterationCount: true,
|
||||
columnCount: true,
|
||||
fillOpacity: true,
|
||||
flexGrow: true,
|
||||
flexShrink: true,
|
||||
fontWeight: true,
|
||||
lineHeight: true,
|
||||
opacity: true,
|
||||
order: true,
|
||||
orphans: true,
|
||||
widows: true,
|
||||
zIndex: true,
|
||||
zoom: true
|
||||
animationIterationCount: true,
|
||||
columnCount: true,
|
||||
fillOpacity: true,
|
||||
flexGrow: true,
|
||||
flexShrink: true,
|
||||
fontWeight: true,
|
||||
lineHeight: true,
|
||||
opacity: true,
|
||||
order: true,
|
||||
orphans: true,
|
||||
widows: true,
|
||||
zIndex: true,
|
||||
zoom: true,
|
||||
};
|
||||
|
||||
const setCSSVal: (elm: HTMLElement, prop: string, val: string | number) => void = (elm, prop, val) => {
|
||||
try {
|
||||
if (elm.style[prop] !== undefined) {
|
||||
elm.style[prop] = parseCSSVal(prop, val);
|
||||
}
|
||||
} catch (e) { }
|
||||
}
|
||||
const parseCSSVal: (prop: string, val: string | number) => string | number = (prop, val) =>
|
||||
!cssNumber[prop.toLowerCase()] && isNumber(val) ? `${val}px` : val;
|
||||
|
||||
const parseCSSVal: (prop: string, val: string | number) => string | number = (prop, val) => {
|
||||
return !cssNumber[prop.toLowerCase()] && isNumber(val) ? val + 'px' : val;
|
||||
}
|
||||
const setCSSVal: (elm: HTMLElement, prop: string, val: string | number) => void = (elm, prop, val) => {
|
||||
try {
|
||||
if (elm.style[prop] !== undefined) {
|
||||
elm.style[prop] = parseCSSVal(prop, val);
|
||||
}
|
||||
} catch (e) {}
|
||||
};
|
||||
|
||||
export function style(elm: HTMLElement, styles: string | cssStyleObj): string;
|
||||
export function style(elm: HTMLElement, styles: string | cssStyleObj, val: string | number): void;
|
||||
export function style(elm: HTMLElement, styles: string | cssStyleObj, val?: string | number): string | void {
|
||||
const getCptStyle: Function = window.getComputedStyle;
|
||||
const getCptStyle = window.getComputedStyle;
|
||||
|
||||
if (isString(styles)) {
|
||||
if (isUndefined(val)) {
|
||||
const cptStyle: CSSStyleDeclaration = getCptStyle(elm, null);
|
||||
if (isString(styles)) {
|
||||
if (isUndefined(val)) {
|
||||
const cptStyle: CSSStyleDeclaration = getCptStyle(elm, null);
|
||||
|
||||
//https://bugzilla.mozilla.org/show_bug.cgi?id=548397 can be null sometimes if iframe with display: none (firefox only!)
|
||||
return cptStyle != null ? cptStyle.getPropertyValue(styles) : elm.style[styles];
|
||||
}
|
||||
else {
|
||||
setCSSVal(elm, styles, val);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (const key in styles)
|
||||
setCSSVal(elm, key, styles[key]);
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=548397 can be null sometimes if iframe with display: none (firefox only!)
|
||||
return cptStyle != null ? cptStyle.getPropertyValue(styles) : elm.style[styles];
|
||||
}
|
||||
setCSSVal(elm, styles, val);
|
||||
} else {
|
||||
keys(styles).forEach((key) => setCSSVal(elm, key, styles[key]));
|
||||
}
|
||||
}
|
||||
|
||||
export const hide: (elm: HTMLElement) => void = (elm) => {
|
||||
elm.style.display = 'none';
|
||||
}
|
||||
elm.style.display = 'none';
|
||||
};
|
||||
|
||||
export const show: (elm: HTMLElement) => void = (elm) => {
|
||||
elm.style.display = 'block';
|
||||
}
|
||||
|
||||
elm.style.display = 'block';
|
||||
};
|
||||
|
||||
@@ -1,52 +1,50 @@
|
||||
import { each } from 'core/utils/arrays';
|
||||
import { each } from 'core/utils/array';
|
||||
|
||||
const elementIsVisible: (elm: HTMLElement) => boolean = (elm) => {
|
||||
return !!(elm.offsetWidth || elm.offsetHeight || elm.getClientRects().length);
|
||||
}
|
||||
const elementIsVisible: (elm: HTMLElement) => boolean = (elm) => !!(elm.offsetWidth || elm.offsetHeight || elm.getClientRects().length);
|
||||
|
||||
export const find: (selector: string, elm?: Element | null) => ReadonlyArray<Element> = (selector, elm?) => {
|
||||
const arr: Array<Element> = [];
|
||||
const arr: Array<Element> = [];
|
||||
|
||||
each((elm || document).querySelectorAll(selector), (e: Element) => {
|
||||
arr.push(e);
|
||||
});
|
||||
each((elm || document).querySelectorAll(selector), (e: Element) => {
|
||||
arr.push(e);
|
||||
});
|
||||
|
||||
return arr;
|
||||
}
|
||||
return arr;
|
||||
};
|
||||
|
||||
export const findFirst: (selector: string, elm?: Element | null) => Element | null = (selector, elm?) => {
|
||||
return (elm || document).querySelector(selector);
|
||||
}
|
||||
export const findFirst: (selector: string, elm?: Element | null) => Element | null = (selector, elm?) => (elm || document).querySelector(selector);
|
||||
|
||||
export const is: (elm: Element | null, selector: string) => boolean = (elm, selector) => {
|
||||
if (elm) {
|
||||
if (selector === ':visible')
|
||||
return elementIsVisible(elm as HTMLElement);
|
||||
if (selector === ':hidden')
|
||||
return !elementIsVisible(elm as HTMLElement);
|
||||
if (elm.matches(selector))
|
||||
return true;
|
||||
if (elm) {
|
||||
if (selector === ':visible') {
|
||||
return elementIsVisible(elm as HTMLElement);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (selector === ':hidden') {
|
||||
return !elementIsVisible(elm as HTMLElement);
|
||||
}
|
||||
if (elm.matches(selector)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
export const children: (elm: Element | null, selector?: string) => ReadonlyArray<Element> = (elm, selector?) => {
|
||||
const children: Array<Element> = [];
|
||||
const childs: Array<Element> = [];
|
||||
|
||||
each(elm && elm.children, (child: Element) => {
|
||||
if (selector) {
|
||||
if (child.matches(selector))
|
||||
children.push(child);
|
||||
}
|
||||
else
|
||||
children.push(child);
|
||||
});
|
||||
each(elm && elm.children, (child: Element) => {
|
||||
if (selector) {
|
||||
if (child.matches(selector)) {
|
||||
childs.push(child);
|
||||
}
|
||||
} else {
|
||||
childs.push(child);
|
||||
}
|
||||
});
|
||||
|
||||
return children;
|
||||
}
|
||||
return childs;
|
||||
};
|
||||
|
||||
export const contents: (elm: Element | null) => ReadonlyArray<ChildNode> = (elm) => {
|
||||
return elm ? Array.from<ChildNode>(elm.childNodes) : [];
|
||||
}
|
||||
export const contents: (elm: Element | null) => ReadonlyArray<ChildNode> = (elm) => (elm ? Array.from<ChildNode>(elm.childNodes) : []);
|
||||
|
||||
export const parent: (elm: Node | null) => Node | null = (elm) => elm ? elm.parentElement : null;
|
||||
export const parent: (elm: Node | null) => Node | null = (elm) => (elm ? elm.parentElement : null);
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
export * from 'core/options/validation';
|
||||
export * from 'core/options/transformation';
|
||||
export * from 'core/options/transformation';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { OptionsTemplate, OptionsAndOptionsTemplate, PlainObject, OptionsTemplateTypes } from "core/typings";
|
||||
import { isArray, isObject } from "core/utils/types";
|
||||
import { each } from "core/utils/arrays";
|
||||
import { OptionsTemplate, OptionsAndOptionsTemplate, PlainObject, OptionsTemplateTypes } from 'core/typings';
|
||||
import { isArray, isObject } from 'core/utils/types';
|
||||
import { each, keys } from 'core/utils';
|
||||
|
||||
/**
|
||||
* Transforms the given OptionsAndOptionsTemplate<T> object to its corresponding generic (T) Object or its corresponding Template object.
|
||||
@@ -8,19 +8,26 @@ import { each } from "core/utils/arrays";
|
||||
* @param toTemplate True if the given OptionsAndOptionsTemplate<T> shall be converted to its corresponding Template object.
|
||||
*/
|
||||
export function transform<T extends Required<T>>(optionsWithOptionsTemplate: OptionsAndOptionsTemplate<T>): T;
|
||||
export function transform<T extends Required<T>>(optionsWithOptionsTemplate: OptionsAndOptionsTemplate<T>, toTemplate: true | void): OptionsTemplate<T>;
|
||||
export function transform<T extends Required<T>>(optionsWithOptionsTemplate: OptionsAndOptionsTemplate<T>, toTemplate?: true | void): OptionsTemplate<T> | T {
|
||||
const result: any = {};
|
||||
export function transform<T extends Required<T>>(
|
||||
optionsWithOptionsTemplate: OptionsAndOptionsTemplate<T>,
|
||||
toTemplate: true | void,
|
||||
): OptionsTemplate<T>;
|
||||
export function transform<T extends Required<T>>(
|
||||
optionsWithOptionsTemplate: OptionsAndOptionsTemplate<T>,
|
||||
toTemplate?: true | void,
|
||||
): OptionsTemplate<T> | T {
|
||||
const result: any = {};
|
||||
|
||||
each(Object.keys(optionsWithOptionsTemplate), (key: Extract<keyof T, string>) => {
|
||||
const val: PlainObject | OptionsTemplateTypes | Array<OptionsTemplateTypes> = optionsWithOptionsTemplate[key];
|
||||
each(keys(optionsWithOptionsTemplate), (key: Extract<keyof T, string>) => {
|
||||
const val: PlainObject | OptionsTemplateTypes | Array<OptionsTemplateTypes> = optionsWithOptionsTemplate[key];
|
||||
|
||||
/* istanbul ignore else */
|
||||
if (isArray(val))
|
||||
result[key] = val[toTemplate ? 1 : 0];
|
||||
else if (isObject(val))
|
||||
result[key] = transform(val as OptionsAndOptionsTemplate<typeof val>, toTemplate);
|
||||
});
|
||||
/* istanbul ignore else */
|
||||
if (isArray(val)) {
|
||||
result[key] = val[toTemplate ? 1 : 0];
|
||||
} else if (isObject(val)) {
|
||||
result[key] = transform(val as OptionsAndOptionsTemplate<typeof val>, toTemplate);
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,16 @@
|
||||
import { each, indexOf } from 'core/utils/arrays';
|
||||
import { each, indexOf, hasOwnProperty, keys } from 'core/utils';
|
||||
import { type, isArray, isUndefined, isEmptyObject, isPlainObject, isString } from 'core/utils/types';
|
||||
import { PlainObject, OptionsTemplate, OptionsTemplateTypes, OptionsTemplateType, OptionsValidated, Func, OptionsValidatedResult } from 'core/typings';
|
||||
import {
|
||||
PlainObject,
|
||||
OptionsTemplate,
|
||||
OptionsTemplateTypes,
|
||||
OptionsTemplateType,
|
||||
OptionsValidated,
|
||||
Func,
|
||||
OptionsValidatedResult,
|
||||
} from 'core/typings';
|
||||
|
||||
const stringify = JSON.stringify;
|
||||
const { stringify } = JSON;
|
||||
|
||||
/**
|
||||
* A prefix and suffix tuple which serves as recognition pattern for template types.
|
||||
@@ -13,18 +21,13 @@ const templateTypePrefixSuffix: readonly [string, string] = ['__TPL_', '_TYPE__'
|
||||
* Key = normal type string
|
||||
* value = template type string
|
||||
*/
|
||||
const optionsTemplateTypes: OptionsTemplateTypesDictionary = [
|
||||
'boolean',
|
||||
'number',
|
||||
'string',
|
||||
'array',
|
||||
'object',
|
||||
'function',
|
||||
'null'
|
||||
].reduce((result, item) => {
|
||||
const optionsTemplateTypes: OptionsTemplateTypesDictionary = ['boolean', 'number', 'string', 'array', 'object', 'function', 'null'].reduce(
|
||||
(result, item) => {
|
||||
result[item] = templateTypePrefixSuffix[0] + item + templateTypePrefixSuffix[1];
|
||||
return result;
|
||||
}, {} as OptionsTemplateTypesDictionary);
|
||||
},
|
||||
{} as OptionsTemplateTypesDictionary,
|
||||
);
|
||||
|
||||
/**
|
||||
* Validates the given options object according to the given template object and returns a object which looks like:
|
||||
@@ -35,7 +38,7 @@ const optionsTemplateTypes: OptionsTemplateTypesDictionary = [
|
||||
* @param options The options object which shall be validated.
|
||||
* @param template The template according to which the options object shall be validated.
|
||||
* @param optionsDiff When provided the returned validated object will only have properties which are different to this objects properties.
|
||||
* Example (assume all properties are valid to the template):
|
||||
* Example (assume all properties are valid to the template):
|
||||
* Options object : { a: 'a', b: 'b', c: 'c' }
|
||||
* optionsDiff object : { a: 'a', b: 'b', c: undefined }
|
||||
* Returned validated object : { c: 'c' }
|
||||
@@ -44,80 +47,87 @@ const optionsTemplateTypes: OptionsTemplateTypesDictionary = [
|
||||
* @param doWriteErrors True if errors shall be logged into the console, false otherwise.
|
||||
* @param propPath The propertyPath which lead to this object. (used for error logging)
|
||||
*/
|
||||
const validateRecursive = function <T extends PlainObject>(options: T, template: OptionsTemplate<Required<T>>, optionsDiff: OptionsValidated<T>, doWriteErrors?: boolean, propPath?: string): OptionsValidatedResult<T> {
|
||||
const validatedOptions: OptionsValidated<T> = {};
|
||||
const optionsCopy: T = Object.assign({}, options);
|
||||
const props = Object.keys(template).filter(prop => options.hasOwnProperty(prop));
|
||||
const validateRecursive = function <T extends PlainObject>(
|
||||
options: T,
|
||||
template: OptionsTemplate<Required<T>>,
|
||||
optionsDiff: OptionsValidated<T>,
|
||||
doWriteErrors?: boolean,
|
||||
propPath?: string,
|
||||
): OptionsValidatedResult<T> {
|
||||
const validatedOptions: OptionsValidated<T> = {};
|
||||
const optionsCopy: T = { ...options };
|
||||
const props = keys(template).filter((prop) => hasOwnProperty(options, prop));
|
||||
|
||||
each(props, (prop: Extract<keyof T, string>) => {
|
||||
const optionsDiffValue: any = isUndefined(optionsDiff[prop]) ? {} : optionsDiff[prop];
|
||||
const optionsValue: any = options[prop];
|
||||
const templateValue: PlainObject | string | OptionsTemplateTypes | Array<OptionsTemplateTypes> = template[prop];
|
||||
const templateIsComplex = isPlainObject(templateValue);
|
||||
const propPrefix = propPath ? propPath + '.' : '';
|
||||
each(props, (prop: Extract<keyof T, string>) => {
|
||||
const optionsDiffValue: any = isUndefined(optionsDiff[prop]) ? {} : optionsDiff[prop];
|
||||
const optionsValue: any = options[prop];
|
||||
const templateValue: PlainObject | string | OptionsTemplateTypes | Array<OptionsTemplateTypes> = template[prop];
|
||||
const templateIsComplex = isPlainObject(templateValue);
|
||||
const propPrefix = propPath ? `${propPath}.` : '';
|
||||
|
||||
//if the template has a object as value, it means that the options are complex (verschachtelt)
|
||||
if (templateIsComplex && isPlainObject(optionsValue)) {
|
||||
const validatedResult = validateRecursive(optionsValue, templateValue as PlainObject, optionsDiffValue, doWriteErrors, propPrefix + prop);
|
||||
validatedOptions[prop] = validatedResult.validated;
|
||||
optionsCopy[prop] = validatedResult.foreign as any;
|
||||
// if the template has a object as value, it means that the options are complex (verschachtelt)
|
||||
if (templateIsComplex && isPlainObject(optionsValue)) {
|
||||
const validatedResult = validateRecursive(optionsValue, templateValue as PlainObject, optionsDiffValue, doWriteErrors, propPrefix + prop);
|
||||
validatedOptions[prop] = validatedResult.validated;
|
||||
optionsCopy[prop] = validatedResult.foreign as any;
|
||||
|
||||
each([optionsCopy, validatedOptions], (value) => {
|
||||
if (isEmptyObject(value[prop])) {
|
||||
delete value[prop];
|
||||
}
|
||||
});
|
||||
each([optionsCopy, validatedOptions], (value) => {
|
||||
if (isEmptyObject(value[prop])) {
|
||||
delete value[prop];
|
||||
}
|
||||
else if (!templateIsComplex) {
|
||||
let isValid = false;
|
||||
const errorEnumStrings: Array<string> = [];
|
||||
const errorPossibleTypes: Array<string> = [];
|
||||
const optionsValueType = type(optionsValue);
|
||||
const templateValueArr: Array<string | OptionsTemplateTypes> = !isArray(templateValue) ? [templateValue as string | OptionsTemplateTypes] : templateValue as Array<OptionsTemplateTypes>;
|
||||
});
|
||||
} else if (!templateIsComplex) {
|
||||
let isValid = false;
|
||||
const errorEnumStrings: Array<string> = [];
|
||||
const errorPossibleTypes: Array<string> = [];
|
||||
const optionsValueType = type(optionsValue);
|
||||
const templateValueArr: Array<string | OptionsTemplateTypes> = !isArray(templateValue)
|
||||
? [templateValue as string | OptionsTemplateTypes]
|
||||
: (templateValue as Array<OptionsTemplateTypes>);
|
||||
|
||||
each(templateValueArr, (currTemplateType) => {
|
||||
//if currType value isn't inside possibleTemplateTypes we assume its a enum string value
|
||||
const isEnumString = indexOf(Object.values(optionsTemplateTypes), currTemplateType) < 0;
|
||||
if (isEnumString && isString(optionsValue)) {
|
||||
//split it into a array which contains all possible values for example: ["yes", "no", "maybe"]
|
||||
const enumStringSplit = currTemplateType.split(' ');
|
||||
isValid = !!enumStringSplit.find(possibility => possibility === optionsValue);
|
||||
each(templateValueArr, (currTemplateType) => {
|
||||
// if currType value isn't inside possibleTemplateTypes we assume its a enum string value
|
||||
const isEnumString = indexOf(Object.values(optionsTemplateTypes), currTemplateType) < 0;
|
||||
if (isEnumString && isString(optionsValue)) {
|
||||
// split it into a array which contains all possible values for example: ["yes", "no", "maybe"]
|
||||
const enumStringSplit = currTemplateType.split(' ');
|
||||
isValid = !!enumStringSplit.find((possibility) => possibility === optionsValue);
|
||||
|
||||
// build error message
|
||||
errorEnumStrings.push(...enumStringSplit);
|
||||
}
|
||||
else {
|
||||
isValid = optionsTemplateTypes[optionsValueType] === currTemplateType;
|
||||
}
|
||||
|
||||
// build error message
|
||||
errorPossibleTypes.push(isEnumString ? optionsTemplateTypes.string : currTemplateType);
|
||||
|
||||
// continue if invalid, break if valid
|
||||
return !isValid;
|
||||
});
|
||||
|
||||
|
||||
if (isValid) {
|
||||
const doStringifyComparison = isArray(optionsValue) || isPlainObject(optionsValue);
|
||||
if (doStringifyComparison ? stringify(optionsValue) !== stringify(optionsDiffValue) : optionsValue !== optionsDiffValue) {
|
||||
validatedOptions[prop] = optionsValue;
|
||||
}
|
||||
}
|
||||
else if (doWriteErrors) {
|
||||
console.warn(`The option "${propPrefix}${prop}" wasn't set, because it doesn't accept the type [ ${optionsValueType.toUpperCase()} ] with the value of "${optionsValue}".\r\n` +
|
||||
`Accepted types are: [ ${errorPossibleTypes.join(', ').toUpperCase()} ].\r\n` +
|
||||
(errorEnumStrings.length > 0 ? `\r\nValid strings are: [ ${errorEnumStrings.join(', ')} ].` : ''))
|
||||
}
|
||||
|
||||
delete optionsCopy[prop];
|
||||
// build error message
|
||||
errorEnumStrings.push(...enumStringSplit);
|
||||
} else {
|
||||
isValid = optionsTemplateTypes[optionsValueType] === currTemplateType;
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
foreign: optionsCopy,
|
||||
validated: validatedOptions
|
||||
};
|
||||
// build error message
|
||||
errorPossibleTypes.push(isEnumString ? optionsTemplateTypes.string : currTemplateType);
|
||||
|
||||
// continue if invalid, break if valid
|
||||
return !isValid;
|
||||
});
|
||||
|
||||
if (isValid) {
|
||||
const doStringifyComparison = isArray(optionsValue) || isPlainObject(optionsValue);
|
||||
if (doStringifyComparison ? stringify(optionsValue) !== stringify(optionsDiffValue) : optionsValue !== optionsDiffValue) {
|
||||
validatedOptions[prop] = optionsValue;
|
||||
}
|
||||
} else if (doWriteErrors) {
|
||||
console.warn(
|
||||
`${
|
||||
`The option "${propPrefix}${prop}" wasn't set, because it doesn't accept the type [ ${optionsValueType.toUpperCase()} ] with the value of "${optionsValue}".\r\n` +
|
||||
`Accepted types are: [ ${errorPossibleTypes.join(', ').toUpperCase()} ].\r\n`
|
||||
}${errorEnumStrings.length > 0 ? `\r\nValid strings are: [ ${errorEnumStrings.join(', ')} ].` : ''}`,
|
||||
);
|
||||
}
|
||||
|
||||
delete optionsCopy[prop];
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
foreign: optionsCopy,
|
||||
validated: validatedOptions,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -129,7 +139,7 @@ const validateRecursive = function <T extends PlainObject>(options: T, template:
|
||||
* @param options The options object which shall be validated.
|
||||
* @param template The template according to which the options object shall be validated.
|
||||
* @param optionsDiff When provided the returned validated object will only have properties which are different to this objects properties.
|
||||
* Example (assume all properties are valid to the template):
|
||||
* Example (assume all properties are valid to the template):
|
||||
* Options object : { a: 'a', b: 'b', c: 'c' }
|
||||
* optionsDiff object : { a: 'a', b: 'b', c: undefined }
|
||||
* Returned validated object : { c: 'c' }
|
||||
@@ -137,28 +147,32 @@ const validateRecursive = function <T extends PlainObject>(options: T, template:
|
||||
* Without the optionsDiff object the returned validated object would be: { a: 'a', b: 'b', c: 'c' }
|
||||
* @param doWriteErrors True if errors shall be logged into the console, false otherwise.
|
||||
*/
|
||||
const validate = function <T extends PlainObject>(options: T, template: OptionsTemplate<Required<T>>, optionsDiff?: OptionsValidated<T>, doWriteErrors?: boolean): OptionsValidatedResult<T> {
|
||||
/*
|
||||
const validate = function <T extends PlainObject>(
|
||||
options: T,
|
||||
template: OptionsTemplate<Required<T>>,
|
||||
optionsDiff?: OptionsValidated<T>,
|
||||
doWriteErrors?: boolean,
|
||||
): OptionsValidatedResult<T> {
|
||||
/*
|
||||
if (!isEmptyObject(foreign) && doWriteErrors)
|
||||
console.warn(`The following options are discarded due to invalidity:\r\n ${window.JSON.stringify(foreign, null, 2)}`);
|
||||
|
||||
|
||||
//add values, which aren't specified in the template, to the finished validated object to prevent them from being discarded
|
||||
if (keepForeignProps) {
|
||||
Object.assign(result.validated, foreign);
|
||||
}
|
||||
*/
|
||||
return validateRecursive(options, template, optionsDiff || {}, doWriteErrors || false);
|
||||
return validateRecursive(options, template, optionsDiff || {}, doWriteErrors || false);
|
||||
};
|
||||
|
||||
export { validate, optionsTemplateTypes };
|
||||
|
||||
type OptionsTemplateTypesDictionary = {
|
||||
readonly boolean: OptionsTemplateType<boolean>;
|
||||
readonly number: OptionsTemplateType<number>;
|
||||
readonly string: OptionsTemplateType<string>;
|
||||
readonly array: OptionsTemplateType<Array<any>>;
|
||||
readonly object: OptionsTemplateType<object>;
|
||||
readonly function: OptionsTemplateType<Func>;
|
||||
readonly null: OptionsTemplateType<null>;
|
||||
}
|
||||
readonly boolean: OptionsTemplateType<boolean>;
|
||||
readonly number: OptionsTemplateType<number>;
|
||||
readonly string: OptionsTemplateType<string>;
|
||||
readonly array: OptionsTemplateType<Array<any>>;
|
||||
readonly object: OptionsTemplateType<object>; // eslint-disable-line @typescript-eslint/ban-types
|
||||
readonly function: OptionsTemplateType<Func>;
|
||||
readonly null: OptionsTemplateType<null>;
|
||||
};
|
||||
|
||||
@@ -5,32 +5,46 @@ export type Func = (this: any, ...args: any[]) => any;
|
||||
export type OptionsTemplateType<T extends OptionsTemplateNativeTypes> = ExtractPropsKey<OptionsTemplateTypeMap, T>;
|
||||
export type OptionsTemplateTypes = keyof OptionsTemplateTypeMap;
|
||||
export type OptionsTemplateNativeTypes = OptionsTemplateTypeMap[keyof OptionsTemplateTypeMap];
|
||||
export type OptionsTemplateValue<T extends OptionsTemplateNativeTypes = string> = T extends string ? string extends T ? OptionsTemplateValueNonEnum<T> : string : OptionsTemplateValueNonEnum<T>;
|
||||
export type OptionsTemplateValue<T extends OptionsTemplateNativeTypes = string> = T extends string
|
||||
? string extends T
|
||||
? OptionsTemplateValueNonEnum<T>
|
||||
: string
|
||||
: OptionsTemplateValueNonEnum<T>;
|
||||
export type OptionsTemplate<T extends Required<T>> = {
|
||||
[P in keyof T]: PlainObject extends T[P] ? OptionsTemplate<Required<T[P]>> : T[P] extends OptionsTemplateNativeTypes ? OptionsTemplateValue<T[P]> : never
|
||||
[P in keyof T]: PlainObject extends T[P]
|
||||
? OptionsTemplate<Required<T[P]>>
|
||||
: T[P] extends OptionsTemplateNativeTypes
|
||||
? OptionsTemplateValue<T[P]>
|
||||
: never;
|
||||
};
|
||||
export type OptionsValidated<T> = {
|
||||
[P in keyof T]?: OptionsValidated<T[P]>;
|
||||
[P in keyof T]?: OptionsValidated<T[P]>;
|
||||
};
|
||||
export type OptionsValidatedResult<T> = {
|
||||
readonly foreign: PlainObject;
|
||||
readonly validated: OptionsValidated<T>;
|
||||
}
|
||||
readonly foreign: PlainObject;
|
||||
readonly validated: OptionsValidated<T>;
|
||||
};
|
||||
// Options With Options Template Typings:
|
||||
export type OptionsAndOptionsTemplateValue<T extends OptionsTemplateNativeTypes> = [T, OptionsTemplateValue<T>];
|
||||
export type OptionsAndOptionsTemplate<T extends Required<T>> = {
|
||||
[P in keyof T]: PlainObject extends T[P] ? OptionsAndOptionsTemplate<Required<T[P]>> : T[P] extends OptionsTemplateNativeTypes ? OptionsAndOptionsTemplateValue<T[P]> : never
|
||||
}
|
||||
[P in keyof T]: PlainObject extends T[P]
|
||||
? OptionsAndOptionsTemplate<Required<T[P]>>
|
||||
: T[P] extends OptionsTemplateNativeTypes
|
||||
? OptionsAndOptionsTemplateValue<T[P]>
|
||||
: never;
|
||||
};
|
||||
type OptionsTemplateTypeMap = {
|
||||
'__TPL_boolean_TYPE__': boolean;
|
||||
'__TPL_number_TYPE__': number;
|
||||
'__TPL_string_TYPE__': string;
|
||||
'__TPL_array_TYPE__': Array<any>
|
||||
'__TPL_function_TYPE__': Func
|
||||
'__TPL_null_TYPE__': null;
|
||||
'__TPL_object_TYPE__': object;
|
||||
}
|
||||
__TPL_boolean_TYPE__: boolean;
|
||||
__TPL_number_TYPE__: number;
|
||||
__TPL_string_TYPE__: string;
|
||||
__TPL_array_TYPE__: Array<any>;
|
||||
__TPL_function_TYPE__: Func;
|
||||
__TPL_null_TYPE__: null;
|
||||
__TPL_object_TYPE__: object; // eslint-disable-line @typescript-eslint/ban-types
|
||||
};
|
||||
type ExtractPropsKey<T, TProps extends T[keyof T]> = {
|
||||
[P in keyof T]: TProps extends T[P] ? P : never;
|
||||
[P in keyof T]: TProps extends T[P] ? P : never;
|
||||
}[keyof T];
|
||||
type OptionsTemplateValueNonEnum<T extends OptionsTemplateNativeTypes> = OptionsTemplateType<T> | [OptionsTemplateType<T>, ...Array<OptionsTemplateTypes>];
|
||||
type OptionsTemplateValueNonEnum<T extends OptionsTemplateNativeTypes> =
|
||||
| OptionsTemplateType<T>
|
||||
| [OptionsTemplateType<T>, ...Array<OptionsTemplateTypes>];
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
import { keys } from 'core/utils/object';
|
||||
import { isArrayLike } from 'core/utils/types';
|
||||
import { PlainObject } from 'core/typings';
|
||||
|
||||
/**
|
||||
* Iterates through a array or object
|
||||
* @param arrayLikeOrObject The array or object through which shall be iterated.
|
||||
* @param callback The function which is responsible for the iteration.
|
||||
* If the function returns true its treated like a "continue" statement.
|
||||
* If the function returns false its treated like a "break" statement.
|
||||
*/
|
||||
export function each<T>(
|
||||
array: Array<T> | ReadonlyArray<T>,
|
||||
callback: (value: T, indexOrKey: number, source: Array<T>) => boolean | void,
|
||||
): Array<T> | ReadonlyArray<T>;
|
||||
export function each<T>(
|
||||
array: Array<T> | ReadonlyArray<T> | null,
|
||||
callback: (value: T, indexOrKey: number, source: Array<T>) => boolean | void,
|
||||
): Array<T> | ReadonlyArray<T> | null;
|
||||
export function each<T>(
|
||||
arrayLikeObject: ArrayLike<T>,
|
||||
callback: (value: T, indexOrKey: number, source: ArrayLike<T>) => boolean | void,
|
||||
): ArrayLike<T>;
|
||||
export function each<T>(
|
||||
arrayLikeObject: ArrayLike<T> | null,
|
||||
callback: (value: T, indexOrKey: number, source: ArrayLike<T>) => boolean | void,
|
||||
): ArrayLike<T> | null;
|
||||
export function each(obj: PlainObject, callback: (value: any, indexOrKey: string, source: PlainObject) => boolean | void): PlainObject;
|
||||
export function each(obj: PlainObject | null, callback: (value: any, indexOrKey: string, source: PlainObject) => boolean | void): PlainObject | null;
|
||||
export function each<T>(
|
||||
source: ArrayLike<T> | PlainObject | null,
|
||||
callback: (value: T | any, indexOrKey: any, source: any) => boolean | void,
|
||||
): Array<T> | ReadonlyArray<T> | ArrayLike<T> | PlainObject | null {
|
||||
if (isArrayLike(source)) {
|
||||
for (let i = 0; i < source.length; i++) {
|
||||
if (callback(source[i], i, source) === false) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (source) {
|
||||
each(keys(source), (key) => callback(source[key], key, source));
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the given inside the given array or -1 if the given item isn't part of the given array.
|
||||
* @param arr The array.
|
||||
* @param item The item.
|
||||
* @param fromIndex The array index at which to begin the search. If fromIndex is omitted, the search starts at index 0.
|
||||
*/
|
||||
export const indexOf: <T = any>(arr: Array<T>, item: T, fromIndex?: number) => number = (arr, item, fromIndex) => arr.indexOf(item, fromIndex);
|
||||
@@ -1,44 +0,0 @@
|
||||
import { isArrayLike } from 'core/utils/types';
|
||||
import { PlainObject } from 'core/typings';
|
||||
|
||||
|
||||
/**
|
||||
* Iterates through a array or object
|
||||
* @param arrayLikeOrObject The array or object through which shall be iterated.
|
||||
* @param callback The function which is responsible for the iteration.
|
||||
* If the function returns true its treated like a "continue" statement.
|
||||
* If the function returns false its treated like a "break" statement.
|
||||
*/
|
||||
export function each<T>(array: Array<T> | ReadonlyArray<T>, callback: (value: T, indexOrKey: number, source: Array<T>) => boolean | void): Array<T> | ReadonlyArray<T>;
|
||||
export function each<T>(array: Array<T> | ReadonlyArray<T> | null, callback: (value: T, indexOrKey: number, source: Array<T>) => boolean | void): Array<T> | ReadonlyArray<T> | null;
|
||||
export function each<T>(arrayLikeObject: ArrayLike<T>, callback: (value: T, indexOrKey: number, source: ArrayLike<T>) => boolean | void): ArrayLike<T>;
|
||||
export function each<T>(arrayLikeObject: ArrayLike<T> | null, callback: (value: T, indexOrKey: number, source: ArrayLike<T>) => boolean | void): ArrayLike<T> | null;
|
||||
export function each(obj: PlainObject, callback: (value: any, indexOrKey: string, source: PlainObject) => boolean | void): PlainObject;
|
||||
export function each(obj: PlainObject | null, callback: (value: any, indexOrKey: string, source: PlainObject) => boolean | void): PlainObject | null;
|
||||
export function each<T>(source: ArrayLike<T> | PlainObject | null, callback: (value: T | any, indexOrKey: any, source: any) => boolean | void): Array<T> | ReadonlyArray<T> | ArrayLike<T> | PlainObject | null {
|
||||
let i: number | string = 0;
|
||||
|
||||
if (isArrayLike(source)) {
|
||||
for (; i < source.length; i++) {
|
||||
if (callback(source[i], i, source) === false)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (source) {
|
||||
for (i in source) {
|
||||
if (callback(source[i], i, source) === false)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return source;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the index of the given inside the given array or -1 if the given item isn't part of the given array.
|
||||
* @param arr The array.
|
||||
* @param item The item.
|
||||
* @param fromIndex The array index at which to begin the search. If fromIndex is omitted, the search starts at index 0.
|
||||
*/
|
||||
export const indexOf: <T = any>(arr: Array<T>, item: T, fromIndex?: number) => number = (arr, item, fromIndex) => {
|
||||
return arr.indexOf(item, fromIndex);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { isArray, isFunction, isPlainObject, isNull } from 'core/utils/types';
|
||||
import { each } from 'core/utils/arrays';
|
||||
import { each } from 'core/utils/array';
|
||||
|
||||
// https://github.com/jquery/jquery/blob/master/src/core.js#L116
|
||||
export function extend<T, U>(target: T, object1: U): T & U;
|
||||
@@ -7,53 +7,62 @@ export function extend<T, U, V>(target: T, object1: U, object2: V): T & U & V;
|
||||
export function extend<T, U, V, W>(target: T, object1: U, object2: V, object3: W): T & U & V & W;
|
||||
export function extend<T, U, V, W, X>(target: T, object1: U, object2: V, object3: W, object4: X): T & U & V & W & X;
|
||||
export function extend<T, U, V, W, X, Y>(target: T, object1: U, object2: V, object3: W, object4: X, object5: Y): T & U & V & W & X & Y;
|
||||
export function extend<T, U, V, W, X, Y, Z>(target: T, object1?: U, object2?: V, object3?: W, object4?: X, object5?: Y, object6?: Z): T & U & V & W & X & Y & Z {
|
||||
const sources: Array<any> = [object1, object2, object3, object4, object5, object6];
|
||||
export function extend<T, U, V, W, X, Y, Z>(
|
||||
target: T,
|
||||
object1?: U,
|
||||
object2?: V,
|
||||
object3?: W,
|
||||
object4?: X,
|
||||
object5?: Y,
|
||||
object6?: Z,
|
||||
): T & U & V & W & X & Y & Z {
|
||||
/* eslint-disable no-restricted-syntax, guard-for-in */
|
||||
const sources: Array<any> = [object1, object2, object3, object4, object5, object6];
|
||||
|
||||
// Handle case when target is a string or something (possible in deep copy)
|
||||
if ((typeof target !== "object" || isNull(target)) && !isFunction(target)) {
|
||||
target = {} as T;
|
||||
}
|
||||
// Handle case when target is a string or something (possible in deep copy)
|
||||
if ((typeof target !== 'object' || isNull(target)) && !isFunction(target)) {
|
||||
target = {} as T;
|
||||
}
|
||||
|
||||
each(sources, (source) => {
|
||||
// Only deal with non-null/undefined values
|
||||
if (source != null) {
|
||||
each(sources, (source) => {
|
||||
// Only deal with non-null/undefined values
|
||||
if (source != null) {
|
||||
// Extend the base object
|
||||
for (const name in source) {
|
||||
const copy: any = source[name];
|
||||
|
||||
// Extend the base object
|
||||
for (const name in source) {
|
||||
const copy: any = source[name];
|
||||
|
||||
// Prevent Object.prototype pollution
|
||||
// Prevent never-ending loop
|
||||
if (name === "__proto__" || target === copy) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const copyIsArray = isArray(copy);
|
||||
|
||||
// Recurse if we're merging plain objects or arrays
|
||||
if (copy && (isPlainObject(copy) || copyIsArray)) {
|
||||
const src = target[name];
|
||||
let clone: any = src;
|
||||
|
||||
// Ensure proper type for the source value
|
||||
if (copyIsArray && !isArray(src)) {
|
||||
clone = [];
|
||||
} else if (!copyIsArray && !isPlainObject(src)) {
|
||||
clone = {};
|
||||
}
|
||||
|
||||
// Never move original objects, clone them
|
||||
target[name] = extend(clone, copy) as any;
|
||||
|
||||
// Don't bring in undefined values
|
||||
} else if (copy !== undefined) {
|
||||
target[name] = copy;
|
||||
}
|
||||
}
|
||||
// Prevent Object.prototype pollution
|
||||
// Prevent never-ending loop
|
||||
if (name === '__proto__' || target === copy) {
|
||||
continue;
|
||||
}
|
||||
});
|
||||
|
||||
// Return the modified object
|
||||
return target as any;
|
||||
}
|
||||
const copyIsArray = isArray(copy);
|
||||
|
||||
// Recurse if we're merging plain objects or arrays
|
||||
if (copy && (isPlainObject(copy) || copyIsArray)) {
|
||||
const src = target[name];
|
||||
let clone: any = src;
|
||||
|
||||
// Ensure proper type for the source value
|
||||
if (copyIsArray && !isArray(src)) {
|
||||
clone = [];
|
||||
} else if (!copyIsArray && !isPlainObject(src)) {
|
||||
clone = {};
|
||||
}
|
||||
|
||||
// Never move original objects, clone them
|
||||
target[name] = extend(clone, copy) as any;
|
||||
|
||||
// Don't bring in undefined values
|
||||
} else if (copy !== undefined) {
|
||||
target[name] = copy;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Return the modified object
|
||||
return target as any;
|
||||
/* eslint-enable */
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from 'core/utils/arrays';
|
||||
export * from 'core/utils/array';
|
||||
export * from 'core/utils/object';
|
||||
export * from 'core/utils/extend';
|
||||
export * from 'core/utils/types';
|
||||
export * from 'core/utils/types';
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Determines whether the passed object has a property with the passed name.
|
||||
* @param obj The object.
|
||||
* @param prop The name of the property.
|
||||
*/
|
||||
export const hasOwnProperty: (obj: any, prop: string | number | symbol) => boolean = (obj: any, prop: string | number | symbol) =>
|
||||
Object.prototype.hasOwnProperty.call(obj, prop);
|
||||
|
||||
/**
|
||||
* Returns the names of the enumerable string properties and methods of an object.
|
||||
* @param obj The object of which the properties shall be returned.
|
||||
*/
|
||||
export const keys: (obj: any) => Array<string> = (obj: any) => Object.keys(obj);
|
||||
@@ -1,88 +1,89 @@
|
||||
import { PlainObject } from 'core/typings';
|
||||
|
||||
export const type: (obj: any) => string = (obj) => {
|
||||
if (obj === undefined)
|
||||
return obj + '';
|
||||
if (obj === null)
|
||||
return obj + '';
|
||||
return Object.prototype.toString.call(obj).replace(/^\[object (.+)\]$/, '$1').toLowerCase();
|
||||
}
|
||||
|
||||
export function isNumber(obj: any): obj is number {
|
||||
return typeof obj === 'number';
|
||||
if (obj === undefined) return `${obj}`;
|
||||
if (obj === null) return `${obj}`;
|
||||
return Object.prototype.toString
|
||||
.call(obj)
|
||||
.replace(/^\[object (.+)\]$/, '$1')
|
||||
.toLowerCase();
|
||||
};
|
||||
|
||||
export function isNumber(obj: any): obj is number {
|
||||
return typeof obj === 'number';
|
||||
}
|
||||
|
||||
export function isString(obj: any): obj is string {
|
||||
return typeof obj === 'string';
|
||||
return typeof obj === 'string';
|
||||
}
|
||||
|
||||
export function isBoolean(obj: any): obj is boolean {
|
||||
return typeof obj === 'boolean';
|
||||
return typeof obj === 'boolean';
|
||||
}
|
||||
|
||||
export function isObject(obj: any): boolean {
|
||||
return typeof obj === 'object' && !isArray(obj) && !isNull(obj);
|
||||
}
|
||||
|
||||
export function isFunction(obj: any): obj is Function {
|
||||
return typeof obj === 'function';
|
||||
export function isFunction(obj: any): obj is (...args: Array<unknown>) => unknown {
|
||||
return typeof obj === 'function';
|
||||
}
|
||||
|
||||
export function isUndefined(obj: any): obj is undefined {
|
||||
return obj === undefined;
|
||||
return obj === undefined;
|
||||
}
|
||||
|
||||
export function isNull(obj: any): obj is null {
|
||||
return obj === null;
|
||||
return obj === null;
|
||||
}
|
||||
|
||||
export function isArray(obj: any): obj is Array<any> {
|
||||
return Array.isArray(obj);
|
||||
return Array.isArray(obj);
|
||||
}
|
||||
|
||||
export function isObject(obj: any): boolean {
|
||||
return typeof obj === 'object' && !isArray(obj) && !isNull(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given object is array like, false otherwise.
|
||||
* @param obj The Object
|
||||
*/
|
||||
export function isArrayLike<T extends PlainObject = any>(obj: any): obj is ArrayLike<T> {
|
||||
const length = !!obj && obj.length;
|
||||
return isArray(obj) || (!isFunction(obj) && isNumber(length) && length > -1 && length % 1 == 0);
|
||||
const length = !!obj && obj.length;
|
||||
return isArray(obj) || (!isFunction(obj) && isNumber(length) && length > -1 && length % 1 == 0); // eslint-disable-line eqeqeq
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given object is a "plain" (e.g. { key: value }) object, false otherwise.
|
||||
* Returns true if the given object is a "plain" (e.g. { key: value }) object, false otherwise.
|
||||
* @param obj The Object.
|
||||
*/
|
||||
export function isPlainObject<T = any>(obj: any): obj is PlainObject<T> {
|
||||
if (!obj || !isObject(obj) || type(obj) !== 'object')
|
||||
return false;
|
||||
if (!obj || !isObject(obj) || type(obj) !== 'object') return false;
|
||||
|
||||
let key;
|
||||
const proto = 'prototype';
|
||||
const hasOwnProperty = Object[proto].hasOwnProperty;
|
||||
const hasOwnConstructor = hasOwnProperty.call(obj, 'constructor');
|
||||
const hasIsPrototypeOf = obj.constructor && obj.constructor[proto] && hasOwnProperty.call(obj.constructor[proto], 'isPrototypeOf');
|
||||
let key;
|
||||
const proto = 'prototype';
|
||||
const { hasOwnProperty } = Object[proto];
|
||||
const hasOwnConstructor = hasOwnProperty.call(obj, 'constructor');
|
||||
const hasIsPrototypeOf = obj.constructor && obj.constructor[proto] && hasOwnProperty.call(obj.constructor[proto], 'isPrototypeOf');
|
||||
|
||||
if (obj.constructor && !hasOwnConstructor && !hasIsPrototypeOf) {
|
||||
return false;
|
||||
}
|
||||
if (obj.constructor && !hasOwnConstructor && !hasIsPrototypeOf) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (key in obj) { /**/ }
|
||||
/* eslint-disable no-restricted-syntax */
|
||||
for (key in obj) {
|
||||
/**/
|
||||
}
|
||||
/* eslint-enable */
|
||||
|
||||
return isUndefined(key) || hasOwnProperty.call(obj, key);
|
||||
};
|
||||
return isUndefined(key) || hasOwnProperty.call(obj, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given object is a HTMLElement.
|
||||
* @param obj The object which shall be checked.
|
||||
*/
|
||||
export function isHTMLElement(obj: any): obj is HTMLElement {
|
||||
const instaceOfRightHandSide = window.HTMLElement;
|
||||
const doInstanceOf = isObject(instaceOfRightHandSide) || isFunction(instaceOfRightHandSide);
|
||||
return !!(
|
||||
doInstanceOf ? obj instanceof instaceOfRightHandSide : (obj && isObject(obj) && obj.nodeType === 1 && isString(obj.nodeName))
|
||||
);
|
||||
const instaceOfRightHandSide = window.HTMLElement;
|
||||
const doInstanceOf = isObject(instaceOfRightHandSide) || isFunction(instaceOfRightHandSide);
|
||||
return !!(doInstanceOf ? obj instanceof instaceOfRightHandSide : obj && isObject(obj) && obj.nodeType === 1 && isString(obj.nodeName));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -90,7 +91,8 @@ export function isHTMLElement(obj: any): obj is HTMLElement {
|
||||
* @param obj The Object.
|
||||
*/
|
||||
export function isEmptyObject(obj: any): boolean {
|
||||
for (let name in obj)
|
||||
return false;
|
||||
return true;
|
||||
};
|
||||
/* eslint-disable no-restricted-syntax, guard-for-in */
|
||||
for (const name in obj) return false;
|
||||
return true;
|
||||
/* eslint-enable */
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
|
||||
import { createDOM } from 'core/dom';
|
||||
import j from 'jquery';
|
||||
|
||||
/*
|
||||
export * from 'core/compatibility';
|
||||
export * from 'core/utils';
|
||||
@@ -10,14 +9,16 @@ export * from 'instances';
|
||||
*/
|
||||
|
||||
const abc = {
|
||||
a: 1,
|
||||
b: 1,
|
||||
c: 1,
|
||||
}
|
||||
a: 1,
|
||||
b: 1,
|
||||
c: 1,
|
||||
};
|
||||
|
||||
export default () => {
|
||||
const { a, b, c } = abc;
|
||||
return [createDOM(`\
|
||||
const { a, b, c } = abc;
|
||||
return [
|
||||
createDOM(
|
||||
'\
|
||||
<div class="os-host">\
|
||||
<div class="os-resize-observer-host"></div>\
|
||||
<div class="os-padding">\
|
||||
@@ -38,5 +39,12 @@ export default () => {
|
||||
</div>\
|
||||
</div>\
|
||||
<div class="os-scrollbar-corner"></div>\
|
||||
</div>`), j('div'), a, b, c];
|
||||
};
|
||||
</div>',
|
||||
),
|
||||
a,
|
||||
b,
|
||||
c,
|
||||
];
|
||||
};
|
||||
|
||||
export const a = 1;
|
||||
|
||||
@@ -7,46 +7,44 @@ const targetInstanceMap: WeakMap<Element, any> = new WeakMap();
|
||||
* @param osInstance The OverlayScrollbars instance.
|
||||
*/
|
||||
export const addInstance: (target: Element, osInstance: any) => void = (target, osInstance) => {
|
||||
targetInstanceMap.set(target, osInstance);
|
||||
targets.add(target);
|
||||
}
|
||||
targetInstanceMap.set(target, osInstance);
|
||||
targets.add(target);
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes a OverlayScrollbars instance from the given element.
|
||||
* @param target The element from which its OverlayScrollbars instance shall be removed.
|
||||
*/
|
||||
export const removeInstance: (target: Element) => void = (target) => {
|
||||
targetInstanceMap.delete(target);
|
||||
targets.delete(target);
|
||||
}
|
||||
targetInstanceMap.delete(target);
|
||||
targets.delete(target);
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the OverlayScrollbars from the given element or undefined if it doesn't have one.
|
||||
* @param target The element of which its OverlayScrollbars instance shall be get.
|
||||
*/
|
||||
export const getInstance: (target: Element) => any = (target) => {
|
||||
return targetInstanceMap.get(target);
|
||||
}
|
||||
export const getInstance: (target: Element) => any = (target) => targetInstanceMap.get(target);
|
||||
|
||||
/**
|
||||
* Gets a Map which represents all active OverayScrollbars instances.
|
||||
* Gets a Map which represents all active OverayScrollbars instances.
|
||||
* The Key is the ekement and the value is the instance.
|
||||
*/
|
||||
export const allInstances: () => ReadonlyMap<Element, any> = () => {
|
||||
const validTargetInstanceMap: Map<Element, any> = new Map();
|
||||
const validTargetInstanceMap: Map<Element, any> = new Map();
|
||||
|
||||
targets.forEach((target: Element) => {
|
||||
/* istanbul ignore else */
|
||||
if (targetInstanceMap.has(target)) {
|
||||
validTargetInstanceMap.set(target, targetInstanceMap.get(target))
|
||||
}
|
||||
});
|
||||
targets.forEach((target: Element) => {
|
||||
/* istanbul ignore else */
|
||||
if (targetInstanceMap.has(target)) {
|
||||
validTargetInstanceMap.set(target, targetInstanceMap.get(target));
|
||||
}
|
||||
});
|
||||
|
||||
targets.clear();
|
||||
targets.clear();
|
||||
|
||||
validTargetInstanceMap.forEach((instance: any, validTarget: Element) => {
|
||||
targets.add(validTarget);
|
||||
});
|
||||
validTargetInstanceMap.forEach((instance: any, validTarget: Element) => {
|
||||
targets.add(validTarget);
|
||||
});
|
||||
|
||||
return validTargetInstanceMap;
|
||||
}
|
||||
return validTargetInstanceMap;
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { OptionsTemplate, OptionsTemplateValue, OptionsAndOptionsTemplateValue, OptionsAndOptionsTemplate, Func } from "core/typings";
|
||||
import { optionsTemplateTypes as oTypes, transform } from "core/options";
|
||||
import { OverlayScrollbars } from "typings";
|
||||
import { OptionsTemplate, OptionsTemplateValue, OptionsAndOptionsTemplateValue, OptionsAndOptionsTemplate, Func } from 'core/typings';
|
||||
import { optionsTemplateTypes as oTypes, transform } from 'core/options';
|
||||
import { ResizeBehavior, OverflowBehavior, VisibilityBehavior, AutoHideBehavior, Options } from 'typings';
|
||||
|
||||
const classNameAllowedValues: OptionsTemplateValue<string | null> = [oTypes.string, oTypes.null];
|
||||
const numberAllowedValues: OptionsTemplateValue<number> = oTypes.number;
|
||||
@@ -9,15 +9,15 @@ const stringArrayNullAllowedValues: OptionsTemplateValue<string | Array<string>
|
||||
const booleanTrueTemplate: OptionsAndOptionsTemplateValue<boolean> = [true, oTypes.boolean];
|
||||
const booleanFalseTemplate: OptionsAndOptionsTemplateValue<boolean> = [false, oTypes.boolean];
|
||||
const callbackTemplate: OptionsAndOptionsTemplateValue<Func | null> = [null, [oTypes.function, oTypes.null]];
|
||||
const resizeAllowedValues: OptionsTemplateValue<OverlayScrollbars.ResizeBehavior> = 'none both horizontal vertical';
|
||||
const overflowBehaviorAllowedValues: OptionsTemplateValue<OverlayScrollbars.OverflowBehavior> = 'visible-hidden visible-scroll scroll hidden';
|
||||
const scrollbarsVisibilityAllowedValues: OptionsTemplateValue<OverlayScrollbars.VisibilityBehavior> = 'visible hidden auto';
|
||||
const scrollbarsAutoHideAllowedValues: OptionsTemplateValue<OverlayScrollbars.AutoHideBehavior> = 'never scroll leavemove';
|
||||
const resizeAllowedValues: OptionsTemplateValue<ResizeBehavior> = 'none both horizontal vertical';
|
||||
const overflowBehaviorAllowedValues: OptionsTemplateValue<OverflowBehavior> = 'visible-hidden visible-scroll scroll hidden';
|
||||
const scrollbarsVisibilityAllowedValues: OptionsTemplateValue<VisibilityBehavior> = 'visible hidden auto';
|
||||
const scrollbarsAutoHideAllowedValues: OptionsTemplateValue<AutoHideBehavior> = 'never scroll leavemove';
|
||||
|
||||
/**
|
||||
* A object which serves as "default options object" and "options template object".
|
||||
* I combined these two into one object so that I don't have to define two separate big objects, instead I define one big object.
|
||||
*
|
||||
*
|
||||
* The property value is a tuple:
|
||||
* the first value is the default value
|
||||
* the second value is the template value
|
||||
@@ -29,54 +29,53 @@ const scrollbarsAutoHideAllowedValues: OptionsTemplateValue<OverlayScrollbars.Au
|
||||
* Property "a" has a default value of 'default' and it can be a string or null
|
||||
* Property "b" has a default value of 250 and it can be number
|
||||
*/
|
||||
const defaultOptionsWithTemplate: OptionsAndOptionsTemplate<Required<OverlayScrollbars.Options>> = {
|
||||
className: ['os-theme-dark', classNameAllowedValues], //null || string
|
||||
resize: ['none', resizeAllowedValues], //none || both || horizontal || vertical || n || b || h || v
|
||||
sizeAutoCapable: booleanTrueTemplate, //true || false
|
||||
clipAlways: booleanTrueTemplate, //true || false
|
||||
normalizeRTL: booleanTrueTemplate, //true || false
|
||||
paddingAbsolute: booleanFalseTemplate, //true || false
|
||||
autoUpdate: [null, booleanNullAllowedValues], //true || false || null
|
||||
autoUpdateInterval: [33, numberAllowedValues], //number
|
||||
updateOnLoad: [['img'], stringArrayNullAllowedValues], //string || array || null
|
||||
nativeScrollbarsOverlaid: {
|
||||
showNativeScrollbars: booleanFalseTemplate, //true || false
|
||||
initialize: booleanFalseTemplate //true || false
|
||||
},
|
||||
overflowBehavior: {
|
||||
x: ['scroll', overflowBehaviorAllowedValues], //visible-hidden || visible-scroll || hidden || scroll || v-h || v-s || h || s
|
||||
y: ['scroll', overflowBehaviorAllowedValues] //visible-hidden || visible-scroll || hidden || scroll || v-h || v-s || h || s
|
||||
},
|
||||
scrollbars: {
|
||||
visibility: ['auto', scrollbarsVisibilityAllowedValues], //visible || hidden || auto || v || h || a
|
||||
autoHide: ['never', scrollbarsAutoHideAllowedValues], //never || scroll || leave || move || n || s || l || m
|
||||
autoHideDelay: [800, numberAllowedValues], //number
|
||||
dragScrolling: booleanTrueTemplate, //true || false
|
||||
clickScrolling: booleanFalseTemplate, //true || false
|
||||
touchSupport: booleanTrueTemplate, //true || false
|
||||
snapHandle: booleanFalseTemplate //true || false
|
||||
},
|
||||
textarea: {
|
||||
dynWidth: booleanFalseTemplate, //true || false
|
||||
dynHeight: booleanFalseTemplate, //true || false
|
||||
inheritedAttrs: [['style', 'class'], stringArrayNullAllowedValues], //string || array || null
|
||||
},
|
||||
callbacks: {
|
||||
onInitialized: callbackTemplate, //null || function
|
||||
onInitializationWithdrawn: callbackTemplate, //null || function
|
||||
onDestroyed: callbackTemplate, //null || function
|
||||
onScrollStart: callbackTemplate, //null || function
|
||||
onScroll: callbackTemplate, //null || function
|
||||
onScrollStop: callbackTemplate, //null || function
|
||||
onOverflowChanged: callbackTemplate, //null || function
|
||||
onOverflowAmountChanged: callbackTemplate, //null || function
|
||||
onDirectionChanged: callbackTemplate, //null || function
|
||||
onContentSizeChanged: callbackTemplate, //null || function
|
||||
onHostSizeChanged: callbackTemplate, //null || function
|
||||
onUpdated: callbackTemplate //null || function
|
||||
}
|
||||
}
|
||||
|
||||
export const optionsTemplate: OptionsTemplate<Required<OverlayScrollbars.Options>> = transform(defaultOptionsWithTemplate, true);
|
||||
export const defaultOptions: OverlayScrollbars.Options = transform(defaultOptionsWithTemplate);
|
||||
const defaultOptionsWithTemplate: OptionsAndOptionsTemplate<Required<Options>> = {
|
||||
className: ['os-theme-dark', classNameAllowedValues], // null || string
|
||||
resize: ['none', resizeAllowedValues], // none || both || horizontal || vertical || n || b || h || v
|
||||
sizeAutoCapable: booleanTrueTemplate, // true || false
|
||||
clipAlways: booleanTrueTemplate, // true || false
|
||||
normalizeRTL: booleanTrueTemplate, // true || false
|
||||
paddingAbsolute: booleanFalseTemplate, // true || false
|
||||
autoUpdate: [null, booleanNullAllowedValues], // true || false || null
|
||||
autoUpdateInterval: [33, numberAllowedValues], // number
|
||||
updateOnLoad: [['img'], stringArrayNullAllowedValues], // string || array || null
|
||||
nativeScrollbarsOverlaid: {
|
||||
showNativeScrollbars: booleanFalseTemplate, // true || false
|
||||
initialize: booleanFalseTemplate, // true || false
|
||||
},
|
||||
overflowBehavior: {
|
||||
x: ['scroll', overflowBehaviorAllowedValues], // visible-hidden || visible-scroll || hidden || scroll || v-h || v-s || h || s
|
||||
y: ['scroll', overflowBehaviorAllowedValues], // visible-hidden || visible-scroll || hidden || scroll || v-h || v-s || h || s
|
||||
},
|
||||
scrollbars: {
|
||||
visibility: ['auto', scrollbarsVisibilityAllowedValues], // visible || hidden || auto || v || h || a
|
||||
autoHide: ['never', scrollbarsAutoHideAllowedValues], // never || scroll || leave || move || n || s || l || m
|
||||
autoHideDelay: [800, numberAllowedValues], // number
|
||||
dragScrolling: booleanTrueTemplate, // true || false
|
||||
clickScrolling: booleanFalseTemplate, // true || false
|
||||
touchSupport: booleanTrueTemplate, // true || false
|
||||
snapHandle: booleanFalseTemplate, // true || false
|
||||
},
|
||||
textarea: {
|
||||
dynWidth: booleanFalseTemplate, // true || false
|
||||
dynHeight: booleanFalseTemplate, // true || false
|
||||
inheritedAttrs: [['style', 'class'], stringArrayNullAllowedValues], // string || array || null
|
||||
},
|
||||
callbacks: {
|
||||
onInitialized: callbackTemplate, // null || function
|
||||
onInitializationWithdrawn: callbackTemplate, // null || function
|
||||
onDestroyed: callbackTemplate, // null || function
|
||||
onScrollStart: callbackTemplate, // null || function
|
||||
onScroll: callbackTemplate, // null || function
|
||||
onScrollStop: callbackTemplate, // null || function
|
||||
onOverflowChanged: callbackTemplate, // null || function
|
||||
onOverflowAmountChanged: callbackTemplate, // null || function
|
||||
onDirectionChanged: callbackTemplate, // null || function
|
||||
onContentSizeChanged: callbackTemplate, // null || function
|
||||
onHostSizeChanged: callbackTemplate, // null || function
|
||||
onUpdated: callbackTemplate, // null || function
|
||||
},
|
||||
};
|
||||
|
||||
export const optionsTemplate: OptionsTemplate<Required<Options>> = transform(defaultOptionsWithTemplate, true);
|
||||
export const defaultOptions: Options = transform(defaultOptionsWithTemplate);
|
||||
|
||||
@@ -1,369 +1,477 @@
|
||||
export namespace OverlayScrollbars {
|
||||
export type ResizeBehavior = "none" | "both" | "horizontal" | "vertical";
|
||||
export type ResizeBehavior = 'none' | 'both' | 'horizontal' | 'vertical';
|
||||
|
||||
export type OverflowBehavior = "hidden" | "scroll" | "visible-hidden" | "visible-scroll";
|
||||
export type OverflowBehavior = 'hidden' | 'scroll' | 'visible-hidden' | 'visible-scroll';
|
||||
|
||||
export type VisibilityBehavior = "visible" | "hidden" | "auto";
|
||||
export type VisibilityBehavior = 'visible' | 'hidden' | 'auto';
|
||||
|
||||
export type AutoHideBehavior = "never" | "scroll" | "leave" | "move";
|
||||
export type AutoHideBehavior = 'never' | 'scroll' | 'leave' | 'move';
|
||||
|
||||
export type ScrollBehavior = "always" | "ifneeded" | "never";
|
||||
export type ScrollBehavior = 'always' | 'ifneeded' | 'never';
|
||||
|
||||
export type BlockBehavior = "begin" | "end" | "center" | "nearest";
|
||||
export type BasicEventCallback = (this: any) => void;
|
||||
|
||||
export type Easing = string | null | undefined;
|
||||
export type ScrollEventCallback = (this: any, args?: UIEvent) => void;
|
||||
|
||||
export type Margin = number | boolean;
|
||||
export type OverflowChangedCallback = (this: any, args?: OverflowChangedArgs) => void;
|
||||
|
||||
export type Position = number | string;
|
||||
export type OverflowAmountChangedCallback = (this: any, args?: OverflowAmountChangedArgs) => void;
|
||||
|
||||
export type Extensions = string | ReadonlyArray<string> | { [extensionName: string]: {} };
|
||||
export type DirectionChangedCallback = (this: any, args?: DirectionChangedArgs) => void;
|
||||
|
||||
export type BasicEventCallback = (this: OverlayScrollbars) => void;
|
||||
export type SizeChangedCallback = (this: any, args?: SizeChangedArgs) => void;
|
||||
|
||||
export type ScrollEventCallback = (this: OverlayScrollbars, args?: UIEvent) => void;
|
||||
export type UpdatedCallback = (this: any, args?: UpdatedArgs) => void;
|
||||
|
||||
export type OverflowChangedCallback = (this: OverlayScrollbars, args?: OverflowChangedArgs) => void;
|
||||
|
||||
export type OverflowAmountChangedCallback = (this: OverlayScrollbars, args?: OverflowAmountChangedArgs) => void;
|
||||
|
||||
export type DirectionChangedCallback = (this: OverlayScrollbars, args?: DirectionChangedArgs) => void;
|
||||
|
||||
export type SizeChangedCallback = (this: OverlayScrollbars, args?: SizeChangedArgs) => void;
|
||||
|
||||
export type UpdatedCallback = (this: OverlayScrollbars, args?: UpdatedArgs) => void;
|
||||
|
||||
export type Coordinates = { x?: Position; y?: Position }
|
||||
| { l?: Position; t?: Position }
|
||||
| { left?: Position; top?: Position }
|
||||
| [Position, Position]
|
||||
| Position
|
||||
| HTMLElement
|
||||
| {
|
||||
el: HTMLElement;
|
||||
scroll?: ScrollBehavior | { x?: ScrollBehavior; y?: ScrollBehavior } | [ScrollBehavior, ScrollBehavior];
|
||||
block?: BlockBehavior | { x?: BlockBehavior; y?: BlockBehavior } | [BlockBehavior, BlockBehavior];
|
||||
margin?: Margin
|
||||
| {
|
||||
top?: Margin;
|
||||
right?: Margin;
|
||||
bottom?: Margin;
|
||||
left?: Margin;
|
||||
}
|
||||
| [Margin, Margin]
|
||||
| [Margin, Margin, Margin, Margin];
|
||||
};
|
||||
|
||||
export interface OverflowChangedArgs {
|
||||
x: boolean;
|
||||
y: boolean;
|
||||
xScrollable: boolean;
|
||||
yScrollable: boolean;
|
||||
clipped: boolean;
|
||||
}
|
||||
|
||||
export interface OverflowAmountChangedArgs {
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
export interface DirectionChangedArgs {
|
||||
isRTL: number;
|
||||
dir: string;
|
||||
}
|
||||
|
||||
export interface SizeChangedArgs {
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
|
||||
export interface UpdatedArgs {
|
||||
forced: boolean;
|
||||
}
|
||||
|
||||
export interface Options {
|
||||
className?: string | null;
|
||||
resize?: ResizeBehavior;
|
||||
sizeAutoCapable?: boolean;
|
||||
clipAlways?: boolean;
|
||||
normalizeRTL?: boolean;
|
||||
paddingAbsolute?: boolean;
|
||||
autoUpdate?: boolean | null;
|
||||
autoUpdateInterval?: number;
|
||||
updateOnLoad?: string | ReadonlyArray<string> | null;
|
||||
nativeScrollbarsOverlaid?: {
|
||||
showNativeScrollbars?: boolean;
|
||||
initialize?: boolean;
|
||||
};
|
||||
overflowBehavior?: {
|
||||
x?: OverflowBehavior;
|
||||
y?: OverflowBehavior;
|
||||
};
|
||||
scrollbars?: {
|
||||
visibility?: VisibilityBehavior;
|
||||
autoHide?: AutoHideBehavior;
|
||||
autoHideDelay?: number;
|
||||
dragScrolling?: boolean;
|
||||
clickScrolling?: boolean;
|
||||
touchSupport?: boolean;
|
||||
snapHandle?: boolean;
|
||||
};
|
||||
textarea?: {
|
||||
dynWidth?: boolean;
|
||||
dynHeight?: boolean;
|
||||
inheritedAttrs?: string | ReadonlyArray<string> | null;
|
||||
};
|
||||
callbacks?: {
|
||||
onInitialized?: BasicEventCallback | null;
|
||||
onInitializationWithdrawn?: BasicEventCallback | null;
|
||||
onDestroyed?: BasicEventCallback | null;
|
||||
onScrollStart?: ScrollEventCallback | null;
|
||||
onScroll?: ScrollEventCallback | null;
|
||||
onScrollStop?: ScrollEventCallback | null;
|
||||
onOverflowChanged?: OverflowChangedCallback | null;
|
||||
onOverflowAmountChanged?: OverflowAmountChangedCallback | null;
|
||||
onDirectionChanged?: DirectionChangedCallback | null;
|
||||
onContentSizeChanged?: SizeChangedCallback | null;
|
||||
onHostSizeChanged?: SizeChangedCallback | null;
|
||||
onUpdated?: UpdatedCallback | null;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ScrollInfo {
|
||||
position: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
ratio: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
max: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
handleOffset: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
handleLength: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
handleLengthRatio: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
trackLength: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
snappedHandleOffset: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
isRTL: boolean;
|
||||
isRTLNormalized: boolean;
|
||||
}
|
||||
|
||||
export interface Elements {
|
||||
target: HTMLElement;
|
||||
host: HTMLElement;
|
||||
padding: HTMLElement;
|
||||
viewport: HTMLElement;
|
||||
content: HTMLElement;
|
||||
scrollbarHorizontal: {
|
||||
scrollbar: HTMLElement;
|
||||
track: HTMLElement;
|
||||
handle: HTMLElement;
|
||||
};
|
||||
scrollbarVertical: {
|
||||
scrollbar: HTMLElement;
|
||||
track: HTMLElement;
|
||||
handle: HTMLElement;
|
||||
};
|
||||
scrollbarCorner: HTMLElement;
|
||||
}
|
||||
|
||||
export interface State {
|
||||
destroyed: boolean;
|
||||
sleeping: boolean;
|
||||
autoUpdate: boolean;
|
||||
widthAuto: boolean;
|
||||
heightAuto: boolean;
|
||||
documentMixed: boolean;
|
||||
padding: {
|
||||
t: number;
|
||||
r: number;
|
||||
b: number;
|
||||
l: number;
|
||||
};
|
||||
overflowAmount: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
hideOverflow: {
|
||||
x: boolean;
|
||||
y: boolean;
|
||||
xs: boolean;
|
||||
ys: boolean;
|
||||
};
|
||||
hasOverflow: {
|
||||
x: boolean;
|
||||
y: boolean;
|
||||
};
|
||||
contentScrollSize: {
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
viewportSize: {
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
hostSize: {
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface Extension {
|
||||
contract(global: any): boolean;
|
||||
|
||||
added(options?: {}): void;
|
||||
|
||||
removed(): void;
|
||||
|
||||
on(callbackName: string, callbackArgs?: UIEvent | OverflowChangedArgs | OverflowAmountChangedArgs | DirectionChangedArgs | SizeChangedArgs | UpdatedArgs): void;
|
||||
}
|
||||
|
||||
export interface ExtensionInfo {
|
||||
name: string;
|
||||
extensionFactory: (this: OverlayScrollbars, defaultOptions: {}, compatibility: Compatibility, framework: any) => Extension;
|
||||
defaultOptions?: {};
|
||||
}
|
||||
|
||||
export interface Globals {
|
||||
defaultOptions: {};
|
||||
autoUpdateLoop: boolean;
|
||||
autoUpdateRecommended: boolean;
|
||||
supportMutationObserver: boolean;
|
||||
supportResizeObserver: boolean;
|
||||
supportPassiveEvents: boolean;
|
||||
supportTransform: boolean;
|
||||
supportTransition: boolean;
|
||||
restrictedMeasuring: boolean;
|
||||
nativeScrollbarStyling: boolean;
|
||||
cssCalc: string | null;
|
||||
nativeScrollbarSize: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
nativeScrollbarIsOverlaid: {
|
||||
x: boolean;
|
||||
y: boolean;
|
||||
};
|
||||
overlayScrollbarDummySize: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
rtlScrollBehavior: {
|
||||
i: boolean;
|
||||
n: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export interface Compatibility {
|
||||
wW(): number;
|
||||
wH(): number;
|
||||
mO(): any;
|
||||
rO(): any;
|
||||
rAF(): (callback: (...args: any[]) => any) => number;
|
||||
cAF(): (requestID: number) => void;
|
||||
now(): number;
|
||||
stpP(event: Event): void;
|
||||
prvD(event: Event): void;
|
||||
page(event: MouseEvent): { x: number, y: number };
|
||||
mBtn(event: MouseEvent): number;
|
||||
inA<T>(item: T, array: T[]): number;
|
||||
isA(obj: any): boolean;
|
||||
type(obj: any): string;
|
||||
bind(func: (...args: any[]) => any, thisObj: any, ...args: any[]): any;
|
||||
}
|
||||
export interface Options {
|
||||
className?: string | null;
|
||||
resize?: ResizeBehavior;
|
||||
sizeAutoCapable?: boolean;
|
||||
clipAlways?: boolean;
|
||||
normalizeRTL?: boolean;
|
||||
paddingAbsolute?: boolean;
|
||||
autoUpdate?: boolean | null;
|
||||
autoUpdateInterval?: number;
|
||||
updateOnLoad?: string | ReadonlyArray<string> | null;
|
||||
nativeScrollbarsOverlaid?: {
|
||||
showNativeScrollbars?: boolean;
|
||||
initialize?: boolean;
|
||||
};
|
||||
overflowBehavior?: {
|
||||
x?: OverflowBehavior;
|
||||
y?: OverflowBehavior;
|
||||
};
|
||||
scrollbars?: {
|
||||
visibility?: VisibilityBehavior;
|
||||
autoHide?: AutoHideBehavior;
|
||||
autoHideDelay?: number;
|
||||
dragScrolling?: boolean;
|
||||
clickScrolling?: boolean;
|
||||
touchSupport?: boolean;
|
||||
snapHandle?: boolean;
|
||||
};
|
||||
textarea?: {
|
||||
dynWidth?: boolean;
|
||||
dynHeight?: boolean;
|
||||
inheritedAttrs?: string | ReadonlyArray<string> | null;
|
||||
};
|
||||
callbacks?: {
|
||||
onInitialized?: BasicEventCallback | null;
|
||||
onInitializationWithdrawn?: BasicEventCallback | null;
|
||||
onDestroyed?: BasicEventCallback | null;
|
||||
onScrollStart?: ScrollEventCallback | null;
|
||||
onScroll?: ScrollEventCallback | null;
|
||||
onScrollStop?: ScrollEventCallback | null;
|
||||
onOverflowChanged?: OverflowChangedCallback | null;
|
||||
onOverflowAmountChanged?: OverflowAmountChangedCallback | null;
|
||||
onDirectionChanged?: DirectionChangedCallback | null;
|
||||
onContentSizeChanged?: SizeChangedCallback | null;
|
||||
onHostSizeChanged?: SizeChangedCallback | null;
|
||||
onUpdated?: UpdatedCallback | null;
|
||||
};
|
||||
}
|
||||
|
||||
export interface OverflowChangedArgs {
|
||||
x: boolean;
|
||||
y: boolean;
|
||||
xScrollable: boolean;
|
||||
yScrollable: boolean;
|
||||
clipped: boolean;
|
||||
}
|
||||
|
||||
export interface OverflowAmountChangedArgs {
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
export interface DirectionChangedArgs {
|
||||
isRTL: number;
|
||||
dir: string;
|
||||
}
|
||||
|
||||
export interface SizeChangedArgs {
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
|
||||
export interface UpdatedArgs {
|
||||
forced: boolean;
|
||||
}
|
||||
|
||||
/*
|
||||
export namespace OverlayScrollbars {
|
||||
export type ResizeBehavior = 'none' | 'both' | 'horizontal' | 'vertical';
|
||||
|
||||
export type OverflowBehavior = 'hidden' | 'scroll' | 'visible-hidden' | 'visible-scroll';
|
||||
|
||||
export type VisibilityBehavior = 'visible' | 'hidden' | 'auto';
|
||||
|
||||
export type AutoHideBehavior = 'never' | 'scroll' | 'leave' | 'move';
|
||||
|
||||
export type ScrollBehavior = 'always' | 'ifneeded' | 'never';
|
||||
|
||||
export type BlockBehavior = 'begin' | 'end' | 'center' | 'nearest';
|
||||
|
||||
export type Easing = string | null | undefined;
|
||||
|
||||
export type Margin = number | boolean;
|
||||
|
||||
export type Position = number | string;
|
||||
|
||||
export type Extensions = string | ReadonlyArray<string> | { [extensionName: string]: {} };
|
||||
|
||||
export type BasicEventCallback = (this: OverlayScrollbars) => void;
|
||||
|
||||
export type ScrollEventCallback = (this: OverlayScrollbars, args?: UIEvent) => void;
|
||||
|
||||
export type OverflowChangedCallback = (this: OverlayScrollbars, args?: OverflowChangedArgs) => void;
|
||||
|
||||
export type OverflowAmountChangedCallback = (this: OverlayScrollbars, args?: OverflowAmountChangedArgs) => void;
|
||||
|
||||
export type DirectionChangedCallback = (this: OverlayScrollbars, args?: DirectionChangedArgs) => void;
|
||||
|
||||
export type SizeChangedCallback = (this: OverlayScrollbars, args?: SizeChangedArgs) => void;
|
||||
|
||||
export type UpdatedCallback = (this: OverlayScrollbars, args?: UpdatedArgs) => void;
|
||||
|
||||
export type Coordinates =
|
||||
| { x?: Position; y?: Position }
|
||||
| { l?: Position; t?: Position }
|
||||
| { left?: Position; top?: Position }
|
||||
| [Position, Position]
|
||||
| Position
|
||||
| HTMLElement
|
||||
| {
|
||||
el: HTMLElement;
|
||||
scroll?: ScrollBehavior | { x?: ScrollBehavior; y?: ScrollBehavior } | [ScrollBehavior, ScrollBehavior];
|
||||
block?: BlockBehavior | { x?: BlockBehavior; y?: BlockBehavior } | [BlockBehavior, BlockBehavior];
|
||||
margin?:
|
||||
| Margin
|
||||
| {
|
||||
top?: Margin;
|
||||
right?: Margin;
|
||||
bottom?: Margin;
|
||||
left?: Margin;
|
||||
}
|
||||
| [Margin, Margin]
|
||||
| [Margin, Margin, Margin, Margin];
|
||||
};
|
||||
|
||||
export interface OverflowChangedArgs {
|
||||
x: boolean;
|
||||
y: boolean;
|
||||
xScrollable: boolean;
|
||||
yScrollable: boolean;
|
||||
clipped: boolean;
|
||||
}
|
||||
|
||||
export interface OverflowAmountChangedArgs {
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
export interface DirectionChangedArgs {
|
||||
isRTL: number;
|
||||
dir: string;
|
||||
}
|
||||
|
||||
export interface SizeChangedArgs {
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
|
||||
export interface UpdatedArgs {
|
||||
forced: boolean;
|
||||
}
|
||||
|
||||
export interface Options {
|
||||
className?: string | null;
|
||||
resize?: ResizeBehavior;
|
||||
sizeAutoCapable?: boolean;
|
||||
clipAlways?: boolean;
|
||||
normalizeRTL?: boolean;
|
||||
paddingAbsolute?: boolean;
|
||||
autoUpdate?: boolean | null;
|
||||
autoUpdateInterval?: number;
|
||||
updateOnLoad?: string | ReadonlyArray<string> | null;
|
||||
nativeScrollbarsOverlaid?: {
|
||||
showNativeScrollbars?: boolean;
|
||||
initialize?: boolean;
|
||||
};
|
||||
overflowBehavior?: {
|
||||
x?: OverflowBehavior;
|
||||
y?: OverflowBehavior;
|
||||
};
|
||||
scrollbars?: {
|
||||
visibility?: VisibilityBehavior;
|
||||
autoHide?: AutoHideBehavior;
|
||||
autoHideDelay?: number;
|
||||
dragScrolling?: boolean;
|
||||
clickScrolling?: boolean;
|
||||
touchSupport?: boolean;
|
||||
snapHandle?: boolean;
|
||||
};
|
||||
textarea?: {
|
||||
dynWidth?: boolean;
|
||||
dynHeight?: boolean;
|
||||
inheritedAttrs?: string | ReadonlyArray<string> | null;
|
||||
};
|
||||
callbacks?: {
|
||||
onInitialized?: BasicEventCallback | null;
|
||||
onInitializationWithdrawn?: BasicEventCallback | null;
|
||||
onDestroyed?: BasicEventCallback | null;
|
||||
onScrollStart?: ScrollEventCallback | null;
|
||||
onScroll?: ScrollEventCallback | null;
|
||||
onScrollStop?: ScrollEventCallback | null;
|
||||
onOverflowChanged?: OverflowChangedCallback | null;
|
||||
onOverflowAmountChanged?: OverflowAmountChangedCallback | null;
|
||||
onDirectionChanged?: DirectionChangedCallback | null;
|
||||
onContentSizeChanged?: SizeChangedCallback | null;
|
||||
onHostSizeChanged?: SizeChangedCallback | null;
|
||||
onUpdated?: UpdatedCallback | null;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ScrollInfo {
|
||||
position: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
ratio: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
max: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
handleOffset: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
handleLength: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
handleLengthRatio: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
trackLength: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
snappedHandleOffset: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
isRTL: boolean;
|
||||
isRTLNormalized: boolean;
|
||||
}
|
||||
|
||||
export interface Elements {
|
||||
target: HTMLElement;
|
||||
host: HTMLElement;
|
||||
padding: HTMLElement;
|
||||
viewport: HTMLElement;
|
||||
content: HTMLElement;
|
||||
scrollbarHorizontal: {
|
||||
scrollbar: HTMLElement;
|
||||
track: HTMLElement;
|
||||
handle: HTMLElement;
|
||||
};
|
||||
scrollbarVertical: {
|
||||
scrollbar: HTMLElement;
|
||||
track: HTMLElement;
|
||||
handle: HTMLElement;
|
||||
};
|
||||
scrollbarCorner: HTMLElement;
|
||||
}
|
||||
|
||||
export interface State {
|
||||
destroyed: boolean;
|
||||
sleeping: boolean;
|
||||
autoUpdate: boolean;
|
||||
widthAuto: boolean;
|
||||
heightAuto: boolean;
|
||||
documentMixed: boolean;
|
||||
padding: {
|
||||
t: number;
|
||||
r: number;
|
||||
b: number;
|
||||
l: number;
|
||||
};
|
||||
overflowAmount: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
hideOverflow: {
|
||||
x: boolean;
|
||||
y: boolean;
|
||||
xs: boolean;
|
||||
ys: boolean;
|
||||
};
|
||||
hasOverflow: {
|
||||
x: boolean;
|
||||
y: boolean;
|
||||
};
|
||||
contentScrollSize: {
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
viewportSize: {
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
hostSize: {
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface Extension {
|
||||
contract(global: any): boolean;
|
||||
|
||||
added(options?: {}): void;
|
||||
|
||||
removed(): void;
|
||||
|
||||
on(
|
||||
callbackName: string,
|
||||
callbackArgs?: UIEvent | OverflowChangedArgs | OverflowAmountChangedArgs | DirectionChangedArgs | SizeChangedArgs | UpdatedArgs,
|
||||
): void;
|
||||
}
|
||||
|
||||
export interface ExtensionInfo {
|
||||
name: string;
|
||||
extensionFactory: (this: OverlayScrollbars, defaultOptions: {}, compatibility: Compatibility, framework: any) => Extension;
|
||||
defaultOptions?: {};
|
||||
}
|
||||
|
||||
export interface Globals {
|
||||
defaultOptions: {};
|
||||
autoUpdateLoop: boolean;
|
||||
autoUpdateRecommended: boolean;
|
||||
supportMutationObserver: boolean;
|
||||
supportResizeObserver: boolean;
|
||||
supportPassiveEvents: boolean;
|
||||
supportTransform: boolean;
|
||||
supportTransition: boolean;
|
||||
restrictedMeasuring: boolean;
|
||||
nativeScrollbarStyling: boolean;
|
||||
cssCalc: string | null;
|
||||
nativeScrollbarSize: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
nativeScrollbarIsOverlaid: {
|
||||
x: boolean;
|
||||
y: boolean;
|
||||
};
|
||||
overlayScrollbarDummySize: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
rtlScrollBehavior: {
|
||||
i: boolean;
|
||||
n: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export interface Compatibility {
|
||||
wW(): number;
|
||||
wH(): number;
|
||||
mO(): any;
|
||||
rO(): any;
|
||||
rAF(): (callback: (...args: any[]) => any) => number;
|
||||
cAF(): (requestID: number) => void;
|
||||
now(): number;
|
||||
stpP(event: Event): void;
|
||||
prvD(event: Event): void;
|
||||
page(event: MouseEvent): { x: number; y: number };
|
||||
mBtn(event: MouseEvent): number;
|
||||
inA<T>(item: T, array: T[]): number;
|
||||
isA(obj: any): boolean;
|
||||
type(obj: any): string;
|
||||
bind(func: (...args: any[]) => any, thisObj: any, ...args: any[]): any;
|
||||
}
|
||||
}
|
||||
|
||||
interface OverlayScrollbars {
|
||||
options(): OverlayScrollbars.Options;
|
||||
options(options: OverlayScrollbars.Options): void;
|
||||
options(optionName: string): any;
|
||||
options(optionName: string, optionValue: {} | null): void;
|
||||
options(): OverlayScrollbars.Options;
|
||||
options(options: OverlayScrollbars.Options): void;
|
||||
options(optionName: string): any;
|
||||
options(optionName: string, optionValue: {} | null): void;
|
||||
|
||||
update(force?: boolean): void;
|
||||
update(force?: boolean): void;
|
||||
|
||||
sleep(): void;
|
||||
sleep(): void;
|
||||
|
||||
scroll(): OverlayScrollbars.ScrollInfo;
|
||||
scroll(
|
||||
coordinates: OverlayScrollbars.Coordinates,
|
||||
duration?: number,
|
||||
easing?: OverlayScrollbars.Easing | { x?: OverlayScrollbars.Easing; y?: OverlayScrollbars.Easing } | [OverlayScrollbars.Easing, OverlayScrollbars.Easing],
|
||||
complete?: (...args: any[]) => any
|
||||
): void;
|
||||
scroll(coordinates: OverlayScrollbars.Coordinates, options: {}): void;
|
||||
scroll(): OverlayScrollbars.ScrollInfo;
|
||||
scroll(
|
||||
coordinates: OverlayScrollbars.Coordinates,
|
||||
duration?: number,
|
||||
easing?:
|
||||
| OverlayScrollbars.Easing
|
||||
| { x?: OverlayScrollbars.Easing; y?: OverlayScrollbars.Easing }
|
||||
| [OverlayScrollbars.Easing, OverlayScrollbars.Easing],
|
||||
complete?: (...args: any[]) => any,
|
||||
): void;
|
||||
scroll(coordinates: OverlayScrollbars.Coordinates, options: {}): void;
|
||||
|
||||
scrollStop(): OverlayScrollbars;
|
||||
scrollStop(): OverlayScrollbars;
|
||||
|
||||
getElements(): OverlayScrollbars.Elements;
|
||||
getElements(elementName: string): any;
|
||||
getElements(): OverlayScrollbars.Elements;
|
||||
getElements(elementName: string): any;
|
||||
|
||||
getState(): OverlayScrollbars.State;
|
||||
getState(stateProperty: string): any;
|
||||
getState(): OverlayScrollbars.State;
|
||||
getState(stateProperty: string): any;
|
||||
|
||||
destroy(): void;
|
||||
destroy(): void;
|
||||
|
||||
ext(): {};
|
||||
ext(extensionName: string): OverlayScrollbars.Extension;
|
||||
ext(): {};
|
||||
ext(extensionName: string): OverlayScrollbars.Extension;
|
||||
|
||||
addExt(extensionName: string, options: {}): OverlayScrollbars.Extension;
|
||||
addExt(extensionName: string, options: {}): OverlayScrollbars.Extension;
|
||||
|
||||
removeExt(extensionName: string): boolean;
|
||||
removeExt(extensionName: string): boolean;
|
||||
}
|
||||
|
||||
interface OverlayScrollbarsStatic {
|
||||
(
|
||||
element: HTMLElement | Element,
|
||||
options: OverlayScrollbars.Options,
|
||||
extensions?: OverlayScrollbars.Extensions
|
||||
): OverlayScrollbars;
|
||||
(
|
||||
element: HTMLElement | Element | null
|
||||
): OverlayScrollbars | undefined;
|
||||
(element: HTMLElement | Element, options: OverlayScrollbars.Options, extensions?: OverlayScrollbars.Extensions): OverlayScrollbars;
|
||||
(element: HTMLElement | Element | null): OverlayScrollbars | undefined;
|
||||
|
||||
(
|
||||
elements: NodeListOf<Element> | ReadonlyArray<Element>,
|
||||
options: OverlayScrollbars.Options,
|
||||
extensions?: OverlayScrollbars.Extensions
|
||||
): OverlayScrollbars | OverlayScrollbars[] | undefined;
|
||||
(
|
||||
elements: NodeListOf<Element> | ReadonlyArray<Element>,
|
||||
filter?: string | ((element: Element, instance: OverlayScrollbars) => boolean)
|
||||
): OverlayScrollbars | OverlayScrollbars[] | undefined;
|
||||
(elements: NodeListOf<Element> | ReadonlyArray<Element>, options: OverlayScrollbars.Options, extensions?: OverlayScrollbars.Extensions):
|
||||
| OverlayScrollbars
|
||||
| OverlayScrollbars[]
|
||||
| undefined;
|
||||
(elements: NodeListOf<Element> | ReadonlyArray<Element>, filter?: string | ((element: Element, instance: OverlayScrollbars) => boolean)):
|
||||
| OverlayScrollbars
|
||||
| OverlayScrollbars[]
|
||||
| undefined;
|
||||
|
||||
globals(): OverlayScrollbars.Globals;
|
||||
globals(): OverlayScrollbars.Globals;
|
||||
|
||||
defaultOptions(): OverlayScrollbars.Options;
|
||||
defaultOptions(newDefaultOptions: OverlayScrollbars.Options): void;
|
||||
defaultOptions(): OverlayScrollbars.Options;
|
||||
defaultOptions(newDefaultOptions: OverlayScrollbars.Options): void;
|
||||
|
||||
extension(): { [index: number]: OverlayScrollbars.ExtensionInfo; length: number };
|
||||
extension(extensionName: string): OverlayScrollbars.ExtensionInfo;
|
||||
extension(
|
||||
extensionName: string,
|
||||
extensionFactory: (this: OverlayScrollbars, defaultOptions: {},
|
||||
compatibility: OverlayScrollbars.Compatibility, framework: any) => OverlayScrollbars.Extension,
|
||||
defaultOptions?: {}
|
||||
): void;
|
||||
extension(extensionName: string, extensionFactory: null | undefined): void;
|
||||
extension(): {
|
||||
[index: number]: OverlayScrollbars.ExtensionInfo;
|
||||
length: number;
|
||||
};
|
||||
extension(extensionName: string): OverlayScrollbars.ExtensionInfo;
|
||||
extension(
|
||||
extensionName: string,
|
||||
extensionFactory: (
|
||||
this: OverlayScrollbars,
|
||||
defaultOptions: {},
|
||||
compatibility: OverlayScrollbars.Compatibility,
|
||||
framework: any,
|
||||
) => OverlayScrollbars.Extension,
|
||||
defaultOptions?: {},
|
||||
): void;
|
||||
extension(extensionName: string, extensionFactory: null | undefined): void;
|
||||
|
||||
valid(osInstance: any): boolean;
|
||||
}
|
||||
valid(osInstance: any): boolean;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
@@ -1,87 +1,87 @@
|
||||
import { jsAPI, cssProperty, cssPropertyValue } from 'core/compatibility/vendors';
|
||||
|
||||
describe('vendors', () => {
|
||||
describe('jsAPI', () => {
|
||||
test('gets MutationObserver', () => {
|
||||
const mutationObserver = jsAPI('MutationObserver');
|
||||
expect(mutationObserver).toBe(MutationObserver);
|
||||
});
|
||||
|
||||
test('gets requestAnimationFrame', () => {
|
||||
const rAF = jsAPI('requestAnimationFrame');
|
||||
expect(rAF).toBe(requestAnimationFrame);
|
||||
});
|
||||
|
||||
test('gets undefined', () => {
|
||||
const apiWhichDontExist = jsAPI('apiWhichDontExist');
|
||||
expect(apiWhichDontExist).toBeUndefined();
|
||||
});
|
||||
|
||||
test('cache is used', () => {
|
||||
const name = 'CacheTestJsAPIWhichDontExists';
|
||||
const fn = () => { };
|
||||
window[name] = fn;
|
||||
|
||||
expect(jsAPI(name)).toBe(fn);
|
||||
|
||||
delete window[name];
|
||||
|
||||
expect(jsAPI(name)).toBe(fn);
|
||||
});
|
||||
describe('jsAPI', () => {
|
||||
test('gets MutationObserver', () => {
|
||||
const mutationObserver = jsAPI('MutationObserver');
|
||||
expect(mutationObserver).toBe(MutationObserver);
|
||||
});
|
||||
|
||||
describe('cssProperty', () => {
|
||||
test('gets transform', () => {
|
||||
const transform = cssProperty('transform');
|
||||
expect(transform).not.toBeUndefined();
|
||||
});
|
||||
|
||||
test('gets undefined', () => {
|
||||
const propWhichDontExist = cssProperty('propWhichDontExist');
|
||||
expect(propWhichDontExist).toBeUndefined();
|
||||
});
|
||||
|
||||
test('cache is used', () => {
|
||||
const spy = jest.spyOn(Document.prototype, 'createElement');
|
||||
|
||||
cssProperty('cachePropWhichDontExist');
|
||||
expect(spy).toBeCalledTimes(1);
|
||||
cssProperty('cachePropWhichDontExist');
|
||||
expect(spy).toBeCalledTimes(1);
|
||||
});
|
||||
test('gets requestAnimationFrame', () => {
|
||||
const rAF = jsAPI('requestAnimationFrame');
|
||||
expect(rAF).toBe(requestAnimationFrame);
|
||||
});
|
||||
|
||||
describe('cssPropertyValue', () => {
|
||||
test('gets calc', () => {
|
||||
const calc = cssPropertyValue('width', 'calc', '(1px)');
|
||||
expect(calc).not.toBeUndefined();
|
||||
});
|
||||
|
||||
test('gets calc as second value', () => {
|
||||
const calc = cssPropertyValue('width', 'nonexistend-calc calc', '(1px)');
|
||||
expect(calc).not.toBeUndefined();
|
||||
});
|
||||
|
||||
test('gets undefined', () => {
|
||||
const nonexistend = cssPropertyValue('width', 'nonexistend');
|
||||
expect(nonexistend).toBeUndefined();
|
||||
});
|
||||
|
||||
test('cache is used', () => {
|
||||
let expectedCalledTimes = 0;
|
||||
const spy = jest.spyOn(Document.prototype, 'createElement');
|
||||
const run = (propName: string, propValue: string) => {
|
||||
expectedCalledTimes++;
|
||||
cssPropertyValue(propName, propValue);
|
||||
expect(spy).toBeCalledTimes(expectedCalledTimes);
|
||||
cssPropertyValue(propName, propValue);
|
||||
expect(spy).toBeCalledTimes(expectedCalledTimes);
|
||||
}
|
||||
|
||||
run('width', 'cacheNonexistendValue');
|
||||
run('height', 'cacheNonexistendValue');
|
||||
run('width', 'cacheNonexistendValue cacheNonexistendValue2');
|
||||
run('height', 'cacheNonexistendValue cacheNonexistendValue2');
|
||||
});
|
||||
test('gets undefined', () => {
|
||||
const apiWhichDontExist = jsAPI('apiWhichDontExist');
|
||||
expect(apiWhichDontExist).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
test('cache is used', () => {
|
||||
const name = 'CacheTestJsAPIWhichDontExists';
|
||||
const fn = () => {};
|
||||
window[name] = fn;
|
||||
|
||||
expect(jsAPI(name)).toBe(fn);
|
||||
|
||||
delete window[name];
|
||||
|
||||
expect(jsAPI(name)).toBe(fn);
|
||||
});
|
||||
});
|
||||
|
||||
describe('cssProperty', () => {
|
||||
test('gets transform', () => {
|
||||
const transform = cssProperty('transform');
|
||||
expect(transform).not.toBeUndefined();
|
||||
});
|
||||
|
||||
test('gets undefined', () => {
|
||||
const propWhichDontExist = cssProperty('propWhichDontExist');
|
||||
expect(propWhichDontExist).toBeUndefined();
|
||||
});
|
||||
|
||||
test('cache is used', () => {
|
||||
const spy = jest.spyOn(Document.prototype, 'createElement');
|
||||
|
||||
cssProperty('cachePropWhichDontExist');
|
||||
expect(spy).toBeCalledTimes(1);
|
||||
cssProperty('cachePropWhichDontExist');
|
||||
expect(spy).toBeCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('cssPropertyValue', () => {
|
||||
test('gets calc', () => {
|
||||
const calc = cssPropertyValue('width', 'calc', '(1px)');
|
||||
expect(calc).not.toBeUndefined();
|
||||
});
|
||||
|
||||
test('gets calc as second value', () => {
|
||||
const calc = cssPropertyValue('width', 'nonexistend-calc calc', '(1px)');
|
||||
expect(calc).not.toBeUndefined();
|
||||
});
|
||||
|
||||
test('gets undefined', () => {
|
||||
const nonexistend = cssPropertyValue('width', 'nonexistend');
|
||||
expect(nonexistend).toBeUndefined();
|
||||
});
|
||||
|
||||
test('cache is used', () => {
|
||||
let expectedCalledTimes = 0;
|
||||
const spy = jest.spyOn(Document.prototype, 'createElement');
|
||||
const run = (propName: string, propValue: string) => {
|
||||
expectedCalledTimes++;
|
||||
cssPropertyValue(propName, propValue);
|
||||
expect(spy).toBeCalledTimes(expectedCalledTimes);
|
||||
cssPropertyValue(propName, propValue);
|
||||
expect(spy).toBeCalledTimes(expectedCalledTimes);
|
||||
};
|
||||
|
||||
run('width', 'cacheNonexistendValue');
|
||||
run('height', 'cacheNonexistendValue');
|
||||
run('width', 'cacheNonexistendValue cacheNonexistendValue2');
|
||||
run('height', 'cacheNonexistendValue cacheNonexistendValue2');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,97 +1,97 @@
|
||||
import { attr, removeAttr, val, scrollLeft, scrollTop } from 'core/dom/attributes';
|
||||
import { attr, removeAttr, val, scrollLeft, scrollTop } from 'core/dom/attribute';
|
||||
|
||||
const testElm = document.body;
|
||||
const setAttribute = (name: string, value: string) => {
|
||||
testElm.setAttribute(name, value);
|
||||
testElm.setAttribute(name, value);
|
||||
};
|
||||
const setScrollLeft = (value: number) => {
|
||||
testElm.scrollLeft = value;
|
||||
testElm.scrollLeft = value;
|
||||
};
|
||||
const setScrollTop = (value: number) => {
|
||||
testElm.scrollTop = value;
|
||||
testElm.scrollTop = value;
|
||||
};
|
||||
const removeAttribute = (name: string) => {
|
||||
testElm.removeAttribute(name);
|
||||
testElm.removeAttribute(name);
|
||||
};
|
||||
|
||||
describe('dom attributes', () => {
|
||||
describe('attr', () => {
|
||||
test('get', () => {
|
||||
const attrName = 'data-test-get';
|
||||
describe('attr', () => {
|
||||
test('get', () => {
|
||||
const attrName = 'data-test-get';
|
||||
|
||||
setAttribute(attrName, '123');
|
||||
expect(attr(testElm, attrName)).toBe('123');
|
||||
setAttribute(attrName, '123');
|
||||
expect(attr(testElm, attrName)).toBe('123');
|
||||
|
||||
setAttribute(attrName, 'abc');
|
||||
expect(attr(testElm, attrName)).toBe('abc');
|
||||
setAttribute(attrName, 'abc');
|
||||
expect(attr(testElm, attrName)).toBe('abc');
|
||||
|
||||
removeAttribute(attrName);
|
||||
});
|
||||
|
||||
test('set', () => {
|
||||
const attrName = 'data-test-set';
|
||||
|
||||
attr(testElm, attrName, '123');
|
||||
expect(attr(testElm, attrName)).toBe('123');
|
||||
|
||||
attr(testElm, attrName, 'abc');
|
||||
expect(attr(testElm, attrName)).toBe('abc');
|
||||
|
||||
removeAttribute(attrName);
|
||||
});
|
||||
removeAttribute(attrName);
|
||||
});
|
||||
|
||||
describe('scrollLeft', () => {
|
||||
test('get', () => {
|
||||
setScrollLeft(100);
|
||||
expect(scrollLeft(testElm)).toBe(100);
|
||||
setScrollLeft(0);
|
||||
});
|
||||
test('set', () => {
|
||||
const attrName = 'data-test-set';
|
||||
|
||||
test('set', () => {
|
||||
scrollLeft(testElm, 100);
|
||||
expect(scrollLeft(testElm)).toBe(100);
|
||||
setScrollLeft(0);
|
||||
});
|
||||
attr(testElm, attrName, '123');
|
||||
expect(attr(testElm, attrName)).toBe('123');
|
||||
|
||||
attr(testElm, attrName, 'abc');
|
||||
expect(attr(testElm, attrName)).toBe('abc');
|
||||
|
||||
removeAttribute(attrName);
|
||||
});
|
||||
});
|
||||
|
||||
describe('scrollLeft', () => {
|
||||
test('get', () => {
|
||||
setScrollLeft(100);
|
||||
expect(scrollLeft(testElm)).toBe(100);
|
||||
setScrollLeft(0);
|
||||
});
|
||||
|
||||
describe('scrollTop', () => {
|
||||
test('get', () => {
|
||||
setScrollTop(100);
|
||||
expect(scrollTop(testElm)).toBe(100);
|
||||
setScrollTop(0);
|
||||
});
|
||||
test('set', () => {
|
||||
scrollLeft(testElm, 100);
|
||||
expect(scrollLeft(testElm)).toBe(100);
|
||||
setScrollLeft(0);
|
||||
});
|
||||
});
|
||||
|
||||
test('set', () => {
|
||||
scrollTop(testElm, 100);
|
||||
expect(scrollTop(testElm)).toBe(100);
|
||||
setScrollTop(0);
|
||||
});
|
||||
describe('scrollTop', () => {
|
||||
test('get', () => {
|
||||
setScrollTop(100);
|
||||
expect(scrollTop(testElm)).toBe(100);
|
||||
setScrollTop(0);
|
||||
});
|
||||
|
||||
describe('val', () => {
|
||||
const input = document.createElement('input');
|
||||
test('set', () => {
|
||||
scrollTop(testElm, 100);
|
||||
expect(scrollTop(testElm)).toBe(100);
|
||||
setScrollTop(0);
|
||||
});
|
||||
});
|
||||
|
||||
test('get', () => {
|
||||
input.value = 'hi';
|
||||
expect(val(input)).toBe('hi');
|
||||
input.value = '';
|
||||
});
|
||||
describe('val', () => {
|
||||
const input = document.createElement('input');
|
||||
|
||||
test('set', () => {
|
||||
val(input, 'hi2');
|
||||
expect(val(input)).toBe('hi2');
|
||||
val(input, '');
|
||||
expect(val(input)).toBe('');
|
||||
});
|
||||
test('get', () => {
|
||||
input.value = 'hi';
|
||||
expect(val(input)).toBe('hi');
|
||||
input.value = '';
|
||||
});
|
||||
|
||||
test('remove attribute', () => {
|
||||
const attrName = 'data-test-remove';
|
||||
|
||||
setAttribute(attrName, '123');
|
||||
removeAttr(testElm, attrName);
|
||||
|
||||
expect(attr(testElm, attrName)).toBeNull();
|
||||
test('set', () => {
|
||||
val(input, 'hi2');
|
||||
expect(val(input)).toBe('hi2');
|
||||
val(input, '');
|
||||
expect(val(input)).toBe('');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('remove attribute', () => {
|
||||
const attrName = 'data-test-remove';
|
||||
|
||||
setAttribute(attrName, '123');
|
||||
removeAttr(testElm, attrName);
|
||||
|
||||
expect(attr(testElm, attrName)).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,85 +1,83 @@
|
||||
import { addClass, removeClass, hasClass, conditionalClass } from 'core/dom/classes';
|
||||
import { addClass, removeClass, hasClass, conditionalClass } from 'core/dom/class';
|
||||
|
||||
const testElm = document.body;
|
||||
const removeAllClassNames = () => {
|
||||
while (testElm.classList.length > 0) {
|
||||
const classToRemove = testElm.classList.item(0);
|
||||
if (classToRemove) {
|
||||
testElm.classList.remove(classToRemove);
|
||||
}
|
||||
while (testElm.classList.length > 0) {
|
||||
const classToRemove = testElm.classList.item(0);
|
||||
if (classToRemove) {
|
||||
testElm.classList.remove(classToRemove);
|
||||
}
|
||||
}
|
||||
};
|
||||
const hasClassName = (className: string) => {
|
||||
return testElm.classList.contains(className);
|
||||
};
|
||||
const hasClassName = (className: string) => testElm.classList.contains(className);
|
||||
|
||||
describe('dom class names', () => {
|
||||
afterEach(() => {
|
||||
removeAllClassNames();
|
||||
});
|
||||
afterEach(() => {
|
||||
removeAllClassNames();
|
||||
});
|
||||
|
||||
test('add none', () => {
|
||||
addClass(testElm, '');
|
||||
// @ts-ignore
|
||||
addClass(testElm, null);
|
||||
// @ts-ignore
|
||||
addClass(testElm, 2);
|
||||
expect(testElm.classList.length).toBe(0);
|
||||
});
|
||||
test('add none', () => {
|
||||
addClass(testElm, '');
|
||||
// @ts-ignore
|
||||
addClass(testElm, null);
|
||||
// @ts-ignore
|
||||
addClass(testElm, 2);
|
||||
expect(testElm.classList.length).toBe(0);
|
||||
});
|
||||
|
||||
test('add single', () => {
|
||||
addClass(testElm, 'test-class');
|
||||
expect(hasClassName('test-class')).toBe(true);
|
||||
});
|
||||
test('add single', () => {
|
||||
addClass(testElm, 'test-class');
|
||||
expect(hasClassName('test-class')).toBe(true);
|
||||
});
|
||||
|
||||
test('add multiple', () => {
|
||||
addClass(testElm, 'test-class test-class2');
|
||||
expect(hasClassName('test-class')).toBe(true);
|
||||
expect(hasClassName('test-class2')).toBe(true);
|
||||
});
|
||||
test('add multiple', () => {
|
||||
addClass(testElm, 'test-class test-class2');
|
||||
expect(hasClassName('test-class')).toBe(true);
|
||||
expect(hasClassName('test-class2')).toBe(true);
|
||||
});
|
||||
|
||||
test('remove none', () => {
|
||||
addClass(testElm, 'test-class');
|
||||
removeClass(testElm, '');
|
||||
// @ts-ignore
|
||||
removeClass(testElm, null);
|
||||
// @ts-ignore
|
||||
removeClass(testElm, 2);
|
||||
expect(testElm.classList.length).toBe(1);
|
||||
});
|
||||
test('remove none', () => {
|
||||
addClass(testElm, 'test-class');
|
||||
removeClass(testElm, '');
|
||||
// @ts-ignore
|
||||
removeClass(testElm, null);
|
||||
// @ts-ignore
|
||||
removeClass(testElm, 2);
|
||||
expect(testElm.classList.length).toBe(1);
|
||||
});
|
||||
|
||||
test('remove single', () => {
|
||||
addClass(testElm, 'test-class');
|
||||
expect(hasClassName('test-class')).toBe(true);
|
||||
removeClass(testElm, 'test-class');
|
||||
expect(hasClassName('test-class')).toBe(false);
|
||||
});
|
||||
test('remove single', () => {
|
||||
addClass(testElm, 'test-class');
|
||||
expect(hasClassName('test-class')).toBe(true);
|
||||
removeClass(testElm, 'test-class');
|
||||
expect(hasClassName('test-class')).toBe(false);
|
||||
});
|
||||
|
||||
test('remove multiple', () => {
|
||||
addClass(testElm, 'test-class test-class2');
|
||||
removeClass(testElm, 'test-class test-class2');
|
||||
expect(hasClassName('test-class')).toBe(false);
|
||||
expect(hasClassName('test-class2')).toBe(false);
|
||||
});
|
||||
test('remove multiple', () => {
|
||||
addClass(testElm, 'test-class test-class2');
|
||||
removeClass(testElm, 'test-class test-class2');
|
||||
expect(hasClassName('test-class')).toBe(false);
|
||||
expect(hasClassName('test-class2')).toBe(false);
|
||||
});
|
||||
|
||||
test('has', () => {
|
||||
addClass(testElm, 'test-class');
|
||||
expect(hasClass(testElm, 'test-class')).toBe(true);
|
||||
});
|
||||
test('has', () => {
|
||||
addClass(testElm, 'test-class');
|
||||
expect(hasClass(testElm, 'test-class')).toBe(true);
|
||||
});
|
||||
|
||||
test('conditional single', () => {
|
||||
conditionalClass(testElm, 'test-class', true)
|
||||
expect(hasClass(testElm, 'test-class')).toBe(true);
|
||||
conditionalClass(testElm, 'test-class', false)
|
||||
expect(hasClass(testElm, 'test-class')).toBe(false);
|
||||
});
|
||||
test('conditional single', () => {
|
||||
conditionalClass(testElm, 'test-class', true);
|
||||
expect(hasClass(testElm, 'test-class')).toBe(true);
|
||||
conditionalClass(testElm, 'test-class', false);
|
||||
expect(hasClass(testElm, 'test-class')).toBe(false);
|
||||
});
|
||||
|
||||
test('conditional multiple', () => {
|
||||
conditionalClass(testElm, 'test-class test-class2', true)
|
||||
expect(hasClass(testElm, 'test-class')).toBe(true);
|
||||
expect(hasClass(testElm, 'test-class2')).toBe(true);
|
||||
conditionalClass(testElm, 'test-class test-class2', false)
|
||||
expect(hasClass(testElm, 'test-class')).toBe(false);
|
||||
expect(hasClass(testElm, 'test-class2')).toBe(false);
|
||||
});
|
||||
});
|
||||
test('conditional multiple', () => {
|
||||
conditionalClass(testElm, 'test-class test-class2', true);
|
||||
expect(hasClass(testElm, 'test-class')).toBe(true);
|
||||
expect(hasClass(testElm, 'test-class2')).toBe(true);
|
||||
conditionalClass(testElm, 'test-class test-class2', false);
|
||||
expect(hasClass(testElm, 'test-class')).toBe(false);
|
||||
expect(hasClass(testElm, 'test-class2')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,73 +2,74 @@ import { each } from 'core/utils';
|
||||
import { createDiv, createDOM } from 'core/dom/create';
|
||||
|
||||
const slotElm = document.body;
|
||||
const testHTML = '<div id="parent" class="parent-class"><div id="child" class="child-class"></div></div><p>2</p><input type="text" value="3"></input>';
|
||||
const testHTML =
|
||||
'<div id="parent" class="parent-class"><div id="child" class="child-class"></div></div><p>2</p><input type="text" value="3"></input>';
|
||||
|
||||
describe('dom create', () => {
|
||||
afterEach(() => {
|
||||
slotElm.innerHTML = '';
|
||||
afterEach(() => {
|
||||
slotElm.innerHTML = '';
|
||||
});
|
||||
|
||||
describe('createDiv', () => {
|
||||
test('correct element tag', () => {
|
||||
const createdDiv = createDiv();
|
||||
expect(createdDiv.tagName.toLowerCase()).toBe('div');
|
||||
});
|
||||
|
||||
describe('createDiv', () => {
|
||||
test('correct element tag', () => {
|
||||
const createdDiv = createDiv();
|
||||
expect(createdDiv.tagName.toLowerCase()).toBe('div');
|
||||
});
|
||||
|
||||
test('no class names', () => {
|
||||
const createdDiv = createDiv();
|
||||
expect(createdDiv.classList.length).toBe(0);
|
||||
});
|
||||
|
||||
test('no style', () => {
|
||||
const createdDiv = createDiv();
|
||||
expect(createdDiv.style.length).toBe(0);
|
||||
});
|
||||
|
||||
test('not in document', () => {
|
||||
const createdDiv = createDiv();
|
||||
expect(createdDiv.parentElement).toBe(null);
|
||||
});
|
||||
test('no class names', () => {
|
||||
const createdDiv = createDiv();
|
||||
expect(createdDiv.classList.length).toBe(0);
|
||||
});
|
||||
|
||||
describe('createDOM', () => {
|
||||
test('correct elements length', () => {
|
||||
const dom = createDOM(testHTML);
|
||||
expect(dom.length).toBe(3);
|
||||
});
|
||||
|
||||
test('elements arent child of any element', () => {
|
||||
const dom = createDOM(testHTML);
|
||||
each(dom, (elm) => {
|
||||
expect(elm.parentElement).toBe(null);
|
||||
});
|
||||
});
|
||||
|
||||
test('elements are created correctly', () => {
|
||||
const dom = createDOM(testHTML);
|
||||
each(dom, (elm) => {
|
||||
slotElm.append(elm);
|
||||
});
|
||||
const parentElm = slotElm.querySelector('#parent');
|
||||
const childElm = slotElm.querySelector('#child');
|
||||
const pElm = slotElm.querySelector('p');
|
||||
const inputElm = slotElm.querySelector('input');
|
||||
|
||||
expect(parentElm).toBeDefined();
|
||||
expect(childElm).toBeDefined();
|
||||
expect(pElm).toBeDefined();
|
||||
expect(inputElm).toBeDefined();
|
||||
|
||||
expect(parentElm?.parentElement).toBe(slotElm);
|
||||
expect(pElm?.parentElement).toBe(slotElm);
|
||||
expect(inputElm?.parentElement).toBe(slotElm);
|
||||
expect(childElm?.parentElement).toBe(parentElm);
|
||||
|
||||
expect(parentElm?.classList.contains('parent-class')).toBeTruthy();
|
||||
expect(childElm?.classList.contains('child-class')).toBeTruthy();
|
||||
expect(pElm?.textContent).toBe('2');
|
||||
expect(inputElm?.value).toBe('3');
|
||||
expect(inputElm?.getAttribute('type')).toBe('text');
|
||||
});
|
||||
test('no style', () => {
|
||||
const createdDiv = createDiv();
|
||||
expect(createdDiv.style.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
test('not in document', () => {
|
||||
const createdDiv = createDiv();
|
||||
expect(createdDiv.parentElement).toBe(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe('createDOM', () => {
|
||||
test('correct elements length', () => {
|
||||
const dom = createDOM(testHTML);
|
||||
expect(dom.length).toBe(3);
|
||||
});
|
||||
|
||||
test('elements arent child of any element', () => {
|
||||
const dom = createDOM(testHTML);
|
||||
each(dom, (elm) => {
|
||||
expect(elm.parentElement).toBe(null);
|
||||
});
|
||||
});
|
||||
|
||||
test('elements are created correctly', () => {
|
||||
const dom = createDOM(testHTML);
|
||||
each(dom, (elm) => {
|
||||
slotElm.append(elm);
|
||||
});
|
||||
const parentElm = slotElm.querySelector('#parent');
|
||||
const childElm = slotElm.querySelector('#child');
|
||||
const pElm = slotElm.querySelector('p');
|
||||
const inputElm = slotElm.querySelector('input');
|
||||
|
||||
expect(parentElm).toBeDefined();
|
||||
expect(childElm).toBeDefined();
|
||||
expect(pElm).toBeDefined();
|
||||
expect(inputElm).toBeDefined();
|
||||
|
||||
expect(parentElm?.parentElement).toBe(slotElm);
|
||||
expect(pElm?.parentElement).toBe(slotElm);
|
||||
expect(inputElm?.parentElement).toBe(slotElm);
|
||||
expect(childElm?.parentElement).toBe(parentElm);
|
||||
|
||||
expect(parentElm?.classList.contains('parent-class')).toBeTruthy();
|
||||
expect(childElm?.classList.contains('child-class')).toBeTruthy();
|
||||
expect(pElm?.textContent).toBe('2');
|
||||
expect(inputElm?.value).toBe('3');
|
||||
expect(inputElm?.getAttribute('type')).toBe('text');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,347 +3,352 @@ import { each, isArray, isHTMLElement } from 'core/utils';
|
||||
|
||||
const slotElm = document.body;
|
||||
const fillSlotElm = () => {
|
||||
const content = [createDiv(), createDiv(), createDiv(), createDiv(), createDiv()];
|
||||
content.forEach((elm, i) => {
|
||||
elm.setAttribute('id', i.toString());
|
||||
slotElm.append(elm);
|
||||
});
|
||||
const content = [createDiv(), createDiv(), createDiv(), createDiv(), createDiv()];
|
||||
content.forEach((elm, i) => {
|
||||
elm.setAttribute('id', i.toString());
|
||||
slotElm.append(elm);
|
||||
});
|
||||
};
|
||||
const clearSlotElm = () => {
|
||||
contents(slotElm).forEach(elm => {
|
||||
elm.remove();
|
||||
});
|
||||
contents(slotElm).forEach((elm) => {
|
||||
elm.remove();
|
||||
});
|
||||
};
|
||||
const compareToNative = (target: Node, method: string, snapshot: Array<Node>, elms: Element | Node | Array<Element> | Array<Node>, compareIds: boolean = false) => {
|
||||
if (!compareIds) {
|
||||
if (!isArray(elms)) {
|
||||
elms = [elms];
|
||||
}
|
||||
elms.forEach(e => {
|
||||
if (isHTMLElement(e))
|
||||
e.remove();
|
||||
});
|
||||
target[method](...elms);
|
||||
expect(Array.from(slotElm.childNodes)).toEqual(snapshot);
|
||||
const compareToNative = (
|
||||
target: Node,
|
||||
method: string,
|
||||
snapshot: Array<Node>,
|
||||
elms: Element | Node | Array<Element> | Array<Node>,
|
||||
compareIds = false,
|
||||
) => {
|
||||
if (!compareIds) {
|
||||
if (!isArray(elms)) {
|
||||
elms = [elms];
|
||||
}
|
||||
else {
|
||||
clearSlotElm();
|
||||
fillSlotElm();
|
||||
elms.forEach((e) => {
|
||||
if (isHTMLElement(e)) {
|
||||
e.remove();
|
||||
}
|
||||
});
|
||||
target[method](...elms);
|
||||
expect(Array.from(slotElm.childNodes)).toEqual(snapshot);
|
||||
} else {
|
||||
clearSlotElm();
|
||||
fillSlotElm();
|
||||
|
||||
|
||||
if (!isArray(elms)) {
|
||||
elms = [elms];
|
||||
}
|
||||
|
||||
const realElms: Array<Element> = [];
|
||||
elms.forEach((elm) => {
|
||||
slotElm.childNodes.forEach((child) => {
|
||||
if (isHTMLElement(child)) {
|
||||
if (isHTMLElement(elm) && child.getAttribute('id') === elm.getAttribute('id')) {
|
||||
realElms.push(child);
|
||||
}
|
||||
if (compareIds && target !== slotElm && isHTMLElement(target) && child.getAttribute('id') === target.getAttribute('id')) {
|
||||
target = child;
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
target[method](...realElms);
|
||||
|
||||
const mapIds = (elm: Node) => isHTMLElement(elm) ? elm.getAttribute('id') || '' : '';
|
||||
const snapshotIdArr: Array<string> = snapshot.map(mapIds);
|
||||
const elmsIdArr: Array<string> = Array.from(slotElm.childNodes).map(mapIds);
|
||||
|
||||
expect(JSON.stringify(elmsIdArr)).toEqual(JSON.stringify(snapshotIdArr));
|
||||
if (!isArray(elms)) {
|
||||
elms = [elms];
|
||||
}
|
||||
|
||||
const realElms: Array<Element> = [];
|
||||
elms.forEach((elm) => {
|
||||
slotElm.childNodes.forEach((child) => {
|
||||
if (isHTMLElement(child)) {
|
||||
if (isHTMLElement(elm) && child.getAttribute('id') === elm.getAttribute('id')) {
|
||||
realElms.push(child);
|
||||
}
|
||||
if (compareIds && target !== slotElm && isHTMLElement(target) && child.getAttribute('id') === target.getAttribute('id')) {
|
||||
target = child;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
target[method](...realElms);
|
||||
|
||||
const mapIds = (elm: Node) => (isHTMLElement(elm) ? elm.getAttribute('id') || '' : '');
|
||||
const snapshotIdArr: Array<string> = snapshot.map(mapIds);
|
||||
const elmsIdArr: Array<string> = Array.from(slotElm.childNodes).map(mapIds);
|
||||
|
||||
expect(JSON.stringify(elmsIdArr)).toEqual(JSON.stringify(snapshotIdArr));
|
||||
}
|
||||
};
|
||||
|
||||
describe('dom manipulation', () => {
|
||||
beforeEach(() => fillSlotElm());
|
||||
afterEach(() => clearSlotElm());
|
||||
beforeEach(() => fillSlotElm());
|
||||
afterEach(() => clearSlotElm());
|
||||
|
||||
describe('appendChildren', () => {
|
||||
test('single created', () => {
|
||||
const createdDiv = createDiv();
|
||||
const childNodes = slotElm.childNodes;
|
||||
const length = childNodes.length;
|
||||
describe('appendChildren', () => {
|
||||
test('single created', () => {
|
||||
const createdDiv = createDiv();
|
||||
const { childNodes } = slotElm;
|
||||
const { length } = childNodes;
|
||||
|
||||
appendChildren(slotElm, createdDiv);
|
||||
expect(createdDiv).toBe(childNodes[childNodes.length - 1]);
|
||||
expect(childNodes.length).toBe(length + 1);
|
||||
appendChildren(slotElm, createdDiv);
|
||||
expect(createdDiv).toBe(childNodes[childNodes.length - 1]);
|
||||
expect(childNodes.length).toBe(length + 1);
|
||||
|
||||
compareToNative(slotElm, 'append', Array.from(childNodes), createdDiv);
|
||||
});
|
||||
|
||||
test('multiple created', () => {
|
||||
const createdDivs = [createDiv(), createDiv(), createDiv()];
|
||||
const childNodes = slotElm.childNodes;
|
||||
const length = childNodes.length;
|
||||
|
||||
appendChildren(slotElm, createdDivs);
|
||||
expect(createdDivs[0]).toBe(childNodes[childNodes.length - 3]);
|
||||
expect(createdDivs[1]).toBe(childNodes[childNodes.length - 2]);
|
||||
expect(createdDivs[2]).toBe(childNodes[childNodes.length - 1]);
|
||||
expect(childNodes.length).toBe(length + createdDivs.length);
|
||||
|
||||
compareToNative(slotElm, 'append', Array.from(childNodes), createdDivs);
|
||||
});
|
||||
|
||||
test('single existing', () => {
|
||||
const childNodes = slotElm.childNodes;
|
||||
const elm = childNodes[1];
|
||||
|
||||
appendChildren(slotElm, elm);
|
||||
expect(elm).toBe(childNodes[childNodes.length - 1]);
|
||||
|
||||
compareToNative(slotElm, 'append', Array.from(childNodes), elm, true);
|
||||
});
|
||||
|
||||
test('multiple existing', () => {
|
||||
const childNodes = slotElm.childNodes;
|
||||
const elms = [childNodes[1], childNodes[0], childNodes[2]];
|
||||
|
||||
appendChildren(slotElm, elms);
|
||||
expect(elms[0]).toBe(childNodes[childNodes.length - 3]);
|
||||
expect(elms[1]).toBe(childNodes[childNodes.length - 2]);
|
||||
expect(elms[2]).toBe(childNodes[childNodes.length - 1]);
|
||||
|
||||
compareToNative(slotElm, 'append', Array.from(childNodes), elms, true);
|
||||
});
|
||||
|
||||
test('none', () => {
|
||||
const childNodes = slotElm.childNodes;
|
||||
const length = childNodes.length;
|
||||
|
||||
appendChildren(slotElm, null);
|
||||
appendChildren(null, childNodes);
|
||||
|
||||
expect(childNodes.length).toBe(length);
|
||||
});
|
||||
compareToNative(slotElm, 'append', Array.from(childNodes), createdDiv);
|
||||
});
|
||||
|
||||
describe('prependChildren', () => {
|
||||
test('single created', () => {
|
||||
const createdDiv = createDiv();
|
||||
const childNodes = slotElm.childNodes;
|
||||
const length = childNodes.length;
|
||||
test('multiple created', () => {
|
||||
const createdDivs = [createDiv(), createDiv(), createDiv()];
|
||||
const { childNodes } = slotElm;
|
||||
const { length } = childNodes;
|
||||
|
||||
prependChildren(slotElm, createdDiv);
|
||||
expect(createdDiv).toBe(childNodes[0]);
|
||||
expect(childNodes.length).toBe(length + 1);
|
||||
appendChildren(slotElm, createdDivs);
|
||||
expect(createdDivs[0]).toBe(childNodes[childNodes.length - 3]);
|
||||
expect(createdDivs[1]).toBe(childNodes[childNodes.length - 2]);
|
||||
expect(createdDivs[2]).toBe(childNodes[childNodes.length - 1]);
|
||||
expect(childNodes.length).toBe(length + createdDivs.length);
|
||||
|
||||
compareToNative(slotElm, 'prepend', Array.from(childNodes), createdDiv);
|
||||
});
|
||||
|
||||
test('multiple created', () => {
|
||||
const createdDivs = [createDiv(), createDiv(), createDiv()];
|
||||
const childNodes = slotElm.childNodes;
|
||||
const length = childNodes.length;
|
||||
|
||||
prependChildren(slotElm, createdDivs);
|
||||
expect(createdDivs[0]).toBe(childNodes[0]);
|
||||
expect(createdDivs[1]).toBe(childNodes[1]);
|
||||
expect(createdDivs[2]).toBe(childNodes[2]);
|
||||
expect(childNodes.length).toBe(length + createdDivs.length);
|
||||
|
||||
compareToNative(slotElm, 'prepend', Array.from(childNodes), createdDivs);
|
||||
});
|
||||
|
||||
test('single existing', () => {
|
||||
const childNodes = slotElm.childNodes;
|
||||
const elm = childNodes[1];
|
||||
|
||||
prependChildren(slotElm, elm);
|
||||
expect(elm).toBe(childNodes[0]);
|
||||
|
||||
compareToNative(slotElm, 'prepend', Array.from(childNodes), elm, true);
|
||||
});
|
||||
|
||||
test('multiple existing', () => {
|
||||
const childNodes = slotElm.childNodes;
|
||||
const elms = [childNodes[1], childNodes[0], childNodes[2]];
|
||||
|
||||
prependChildren(slotElm, elms);
|
||||
expect(elms[0]).toBe(childNodes[0]);
|
||||
expect(elms[1]).toBe(childNodes[1]);
|
||||
expect(elms[2]).toBe(childNodes[2]);
|
||||
|
||||
compareToNative(slotElm, 'prepend', Array.from(childNodes), elms, true);
|
||||
});
|
||||
|
||||
test('none', () => {
|
||||
const childNodes = slotElm.childNodes;
|
||||
const length = childNodes.length;
|
||||
|
||||
prependChildren(slotElm, null);
|
||||
prependChildren(null, childNodes);
|
||||
|
||||
expect(childNodes.length).toBe(length);
|
||||
});
|
||||
compareToNative(slotElm, 'append', Array.from(childNodes), createdDivs);
|
||||
});
|
||||
|
||||
describe('insertBefore', () => {
|
||||
test('single created', () => {
|
||||
const createdDiv = createDiv();
|
||||
const childNodes = slotElm.childNodes;
|
||||
const length = childNodes.length;
|
||||
const target = childNodes[1];
|
||||
test('single existing', () => {
|
||||
const { childNodes } = slotElm;
|
||||
const elm = childNodes[1];
|
||||
|
||||
insertBefore(target, createdDiv);
|
||||
expect(createdDiv).toBe(childNodes[1]);
|
||||
expect(childNodes.length).toBe(length + 1);
|
||||
appendChildren(slotElm, elm);
|
||||
expect(elm).toBe(childNodes[childNodes.length - 1]);
|
||||
|
||||
compareToNative(target, 'before', Array.from(childNodes), createdDiv);
|
||||
});
|
||||
|
||||
test('multiple created', () => {
|
||||
const createdDivs = [createDiv(), createDiv(), createDiv()];
|
||||
const childNodes = slotElm.childNodes;
|
||||
const length = childNodes.length;
|
||||
const target = childNodes[1];
|
||||
|
||||
insertBefore(target, createdDivs);
|
||||
expect(createdDivs[0]).toBe(childNodes[1]);
|
||||
expect(createdDivs[1]).toBe(childNodes[2]);
|
||||
expect(createdDivs[2]).toBe(childNodes[3]);
|
||||
expect(childNodes.length).toBe(length + createdDivs.length);
|
||||
|
||||
compareToNative(target, 'before', Array.from(childNodes), createdDivs);
|
||||
});
|
||||
|
||||
test('single existing', () => {
|
||||
const childNodes = slotElm.childNodes;
|
||||
const target = childNodes[1];
|
||||
const elm = childNodes[2];
|
||||
|
||||
insertBefore(target, elm);
|
||||
expect(elm).toBe(childNodes[1]);
|
||||
|
||||
compareToNative(target, 'before', Array.from(childNodes), elm, true);
|
||||
});
|
||||
|
||||
test('multiple existing', () => {
|
||||
const childNodes = slotElm.childNodes;
|
||||
const target = childNodes[1];
|
||||
const elms = [childNodes[4], childNodes[1], childNodes[2]];
|
||||
|
||||
insertBefore(target, elms);
|
||||
expect(elms[0]).toBe(childNodes[1]);
|
||||
expect(elms[1]).toBe(childNodes[2]);
|
||||
expect(elms[2]).toBe(childNodes[3]);
|
||||
|
||||
compareToNative(target, 'before', Array.from(childNodes), elms, true);
|
||||
});
|
||||
|
||||
test('none', () => {
|
||||
const childNodes = slotElm.childNodes;
|
||||
const length = childNodes.length;
|
||||
|
||||
insertBefore(slotElm, null);
|
||||
insertBefore(null, childNodes);
|
||||
|
||||
expect(childNodes.length).toBe(length);
|
||||
});
|
||||
compareToNative(slotElm, 'append', Array.from(childNodes), elm, true);
|
||||
});
|
||||
|
||||
describe('insertAfter', () => {
|
||||
test('single created', () => {
|
||||
const createdDiv = createDiv();
|
||||
const childNodes = slotElm.childNodes;
|
||||
const length = childNodes.length;
|
||||
const target = childNodes[1];
|
||||
test('multiple existing', () => {
|
||||
const { childNodes } = slotElm;
|
||||
const elms = [childNodes[1], childNodes[0], childNodes[2]];
|
||||
|
||||
insertAfter(target, createdDiv);
|
||||
expect(createdDiv).toBe(childNodes[2]);
|
||||
expect(childNodes.length).toBe(length + 1);
|
||||
appendChildren(slotElm, elms);
|
||||
expect(elms[0]).toBe(childNodes[childNodes.length - 3]);
|
||||
expect(elms[1]).toBe(childNodes[childNodes.length - 2]);
|
||||
expect(elms[2]).toBe(childNodes[childNodes.length - 1]);
|
||||
|
||||
compareToNative(target, 'after', Array.from(childNodes), createdDiv);
|
||||
});
|
||||
|
||||
test('multiple created', () => {
|
||||
const createdDivs = [createDiv(), createDiv(), createDiv()];
|
||||
const childNodes = slotElm.childNodes;
|
||||
const length = childNodes.length;
|
||||
const target = childNodes[1];
|
||||
|
||||
insertAfter(target, createdDivs);
|
||||
expect(createdDivs[0]).toBe(childNodes[2]);
|
||||
expect(createdDivs[1]).toBe(childNodes[3]);
|
||||
expect(createdDivs[2]).toBe(childNodes[4]);
|
||||
expect(childNodes.length).toBe(length + createdDivs.length);
|
||||
|
||||
compareToNative(target, 'after', Array.from(childNodes), createdDivs);
|
||||
});
|
||||
|
||||
test('single existing', () => {
|
||||
const childNodes = slotElm.childNodes;
|
||||
const target = childNodes[1];
|
||||
const elm = childNodes[0];
|
||||
|
||||
insertAfter(target, elm);
|
||||
expect(elm).toBe(childNodes[1]);
|
||||
|
||||
compareToNative(target, 'after', Array.from(childNodes), elm, true);
|
||||
});
|
||||
|
||||
test('multiple existing', () => {
|
||||
const childNodes = slotElm.childNodes;
|
||||
const target = childNodes[1];
|
||||
const elms = [childNodes[4], childNodes[1], childNodes[2]];
|
||||
|
||||
insertAfter(target, elms);
|
||||
expect(elms[0]).toBe(childNodes[1]);
|
||||
expect(elms[1]).toBe(childNodes[2]);
|
||||
expect(elms[2]).toBe(childNodes[3]);
|
||||
|
||||
compareToNative(target, 'after', Array.from(childNodes), elms, true);
|
||||
});
|
||||
|
||||
test('none', () => {
|
||||
const childNodes = slotElm.childNodes;
|
||||
const length = childNodes.length;
|
||||
|
||||
insertAfter(slotElm, null);
|
||||
insertAfter(null, childNodes);
|
||||
|
||||
expect(childNodes.length).toBe(length);
|
||||
});
|
||||
compareToNative(slotElm, 'append', Array.from(childNodes), elms, true);
|
||||
});
|
||||
|
||||
describe('removeElm', () => {
|
||||
test('single created', () => {
|
||||
const createdDiv = createDiv();
|
||||
expect(createdDiv.parentElement).toBeNull();
|
||||
removeElements(createdDiv);
|
||||
});
|
||||
test('none', () => {
|
||||
const { childNodes } = slotElm;
|
||||
const { length } = childNodes;
|
||||
|
||||
test('multiple created', () => {
|
||||
const createdDivs: Array<HTMLElement> = [createDiv(), createDiv(), createDiv(), createDiv()];
|
||||
each(createdDivs, (createdDiv: HTMLElement) => {
|
||||
expect(createdDiv.parentElement).toBeNull();
|
||||
});
|
||||
removeElements(createdDivs);
|
||||
});
|
||||
appendChildren(slotElm, null);
|
||||
appendChildren(null, childNodes);
|
||||
|
||||
test('single existing', () => {
|
||||
const childNodes = slotElm.childNodes;
|
||||
const length = childNodes.length;
|
||||
expect(length).not.toBe(0);
|
||||
removeElements(childNodes[0]);
|
||||
expect(childNodes.length).toBe(length - 1);
|
||||
});
|
||||
|
||||
test('multiple existing', () => {
|
||||
const childNodes = slotElm.childNodes;
|
||||
expect(childNodes.length).not.toBe(0)
|
||||
removeElements(childNodes);
|
||||
expect(childNodes.length).toBe(0);
|
||||
});
|
||||
|
||||
test('none', () => {
|
||||
// @ts-ignore
|
||||
removeElements(null);
|
||||
});
|
||||
expect(childNodes.length).toBe(length);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('prependChildren', () => {
|
||||
test('single created', () => {
|
||||
const createdDiv = createDiv();
|
||||
const { childNodes } = slotElm;
|
||||
const { length } = childNodes;
|
||||
|
||||
prependChildren(slotElm, createdDiv);
|
||||
expect(createdDiv).toBe(childNodes[0]);
|
||||
expect(childNodes.length).toBe(length + 1);
|
||||
|
||||
compareToNative(slotElm, 'prepend', Array.from(childNodes), createdDiv);
|
||||
});
|
||||
|
||||
test('multiple created', () => {
|
||||
const createdDivs = [createDiv(), createDiv(), createDiv()];
|
||||
const { childNodes } = slotElm;
|
||||
const { length } = childNodes;
|
||||
|
||||
prependChildren(slotElm, createdDivs);
|
||||
expect(createdDivs[0]).toBe(childNodes[0]);
|
||||
expect(createdDivs[1]).toBe(childNodes[1]);
|
||||
expect(createdDivs[2]).toBe(childNodes[2]);
|
||||
expect(childNodes.length).toBe(length + createdDivs.length);
|
||||
|
||||
compareToNative(slotElm, 'prepend', Array.from(childNodes), createdDivs);
|
||||
});
|
||||
|
||||
test('single existing', () => {
|
||||
const { childNodes } = slotElm;
|
||||
const elm = childNodes[1];
|
||||
|
||||
prependChildren(slotElm, elm);
|
||||
expect(elm).toBe(childNodes[0]);
|
||||
|
||||
compareToNative(slotElm, 'prepend', Array.from(childNodes), elm, true);
|
||||
});
|
||||
|
||||
test('multiple existing', () => {
|
||||
const { childNodes } = slotElm;
|
||||
const elms = [childNodes[1], childNodes[0], childNodes[2]];
|
||||
|
||||
prependChildren(slotElm, elms);
|
||||
expect(elms[0]).toBe(childNodes[0]);
|
||||
expect(elms[1]).toBe(childNodes[1]);
|
||||
expect(elms[2]).toBe(childNodes[2]);
|
||||
|
||||
compareToNative(slotElm, 'prepend', Array.from(childNodes), elms, true);
|
||||
});
|
||||
|
||||
test('none', () => {
|
||||
const { childNodes } = slotElm;
|
||||
const { length } = childNodes;
|
||||
|
||||
prependChildren(slotElm, null);
|
||||
prependChildren(null, childNodes);
|
||||
|
||||
expect(childNodes.length).toBe(length);
|
||||
});
|
||||
});
|
||||
|
||||
describe('insertBefore', () => {
|
||||
test('single created', () => {
|
||||
const createdDiv = createDiv();
|
||||
const { childNodes } = slotElm;
|
||||
const { length } = childNodes;
|
||||
const target = childNodes[1];
|
||||
|
||||
insertBefore(target, createdDiv);
|
||||
expect(createdDiv).toBe(childNodes[1]);
|
||||
expect(childNodes.length).toBe(length + 1);
|
||||
|
||||
compareToNative(target, 'before', Array.from(childNodes), createdDiv);
|
||||
});
|
||||
|
||||
test('multiple created', () => {
|
||||
const createdDivs = [createDiv(), createDiv(), createDiv()];
|
||||
const { childNodes } = slotElm;
|
||||
const { length } = childNodes;
|
||||
const target = childNodes[1];
|
||||
|
||||
insertBefore(target, createdDivs);
|
||||
expect(createdDivs[0]).toBe(childNodes[1]);
|
||||
expect(createdDivs[1]).toBe(childNodes[2]);
|
||||
expect(createdDivs[2]).toBe(childNodes[3]);
|
||||
expect(childNodes.length).toBe(length + createdDivs.length);
|
||||
|
||||
compareToNative(target, 'before', Array.from(childNodes), createdDivs);
|
||||
});
|
||||
|
||||
test('single existing', () => {
|
||||
const { childNodes } = slotElm;
|
||||
const target = childNodes[1];
|
||||
const elm = childNodes[2];
|
||||
|
||||
insertBefore(target, elm);
|
||||
expect(elm).toBe(childNodes[1]);
|
||||
|
||||
compareToNative(target, 'before', Array.from(childNodes), elm, true);
|
||||
});
|
||||
|
||||
test('multiple existing', () => {
|
||||
const { childNodes } = slotElm;
|
||||
const target = childNodes[1];
|
||||
const elms = [childNodes[4], childNodes[1], childNodes[2]];
|
||||
|
||||
insertBefore(target, elms);
|
||||
expect(elms[0]).toBe(childNodes[1]);
|
||||
expect(elms[1]).toBe(childNodes[2]);
|
||||
expect(elms[2]).toBe(childNodes[3]);
|
||||
|
||||
compareToNative(target, 'before', Array.from(childNodes), elms, true);
|
||||
});
|
||||
|
||||
test('none', () => {
|
||||
const { childNodes } = slotElm;
|
||||
const { length } = childNodes;
|
||||
|
||||
insertBefore(slotElm, null);
|
||||
insertBefore(null, childNodes);
|
||||
|
||||
expect(childNodes.length).toBe(length);
|
||||
});
|
||||
});
|
||||
|
||||
describe('insertAfter', () => {
|
||||
test('single created', () => {
|
||||
const createdDiv = createDiv();
|
||||
const { childNodes } = slotElm;
|
||||
const { length } = childNodes;
|
||||
const target = childNodes[1];
|
||||
|
||||
insertAfter(target, createdDiv);
|
||||
expect(createdDiv).toBe(childNodes[2]);
|
||||
expect(childNodes.length).toBe(length + 1);
|
||||
|
||||
compareToNative(target, 'after', Array.from(childNodes), createdDiv);
|
||||
});
|
||||
|
||||
test('multiple created', () => {
|
||||
const createdDivs = [createDiv(), createDiv(), createDiv()];
|
||||
const { childNodes } = slotElm;
|
||||
const { length } = childNodes;
|
||||
const target = childNodes[1];
|
||||
|
||||
insertAfter(target, createdDivs);
|
||||
expect(createdDivs[0]).toBe(childNodes[2]);
|
||||
expect(createdDivs[1]).toBe(childNodes[3]);
|
||||
expect(createdDivs[2]).toBe(childNodes[4]);
|
||||
expect(childNodes.length).toBe(length + createdDivs.length);
|
||||
|
||||
compareToNative(target, 'after', Array.from(childNodes), createdDivs);
|
||||
});
|
||||
|
||||
test('single existing', () => {
|
||||
const { childNodes } = slotElm;
|
||||
const target = childNodes[1];
|
||||
const elm = childNodes[0];
|
||||
|
||||
insertAfter(target, elm);
|
||||
expect(elm).toBe(childNodes[1]);
|
||||
|
||||
compareToNative(target, 'after', Array.from(childNodes), elm, true);
|
||||
});
|
||||
|
||||
test('multiple existing', () => {
|
||||
const { childNodes } = slotElm;
|
||||
const target = childNodes[1];
|
||||
const elms = [childNodes[4], childNodes[1], childNodes[2]];
|
||||
|
||||
insertAfter(target, elms);
|
||||
expect(elms[0]).toBe(childNodes[1]);
|
||||
expect(elms[1]).toBe(childNodes[2]);
|
||||
expect(elms[2]).toBe(childNodes[3]);
|
||||
|
||||
compareToNative(target, 'after', Array.from(childNodes), elms, true);
|
||||
});
|
||||
|
||||
test('none', () => {
|
||||
const { childNodes } = slotElm;
|
||||
const { length } = childNodes;
|
||||
|
||||
insertAfter(slotElm, null);
|
||||
insertAfter(null, childNodes);
|
||||
|
||||
expect(childNodes.length).toBe(length);
|
||||
});
|
||||
});
|
||||
|
||||
describe('removeElm', () => {
|
||||
test('single created', () => {
|
||||
const createdDiv = createDiv();
|
||||
expect(createdDiv.parentElement).toBeNull();
|
||||
removeElements(createdDiv);
|
||||
});
|
||||
|
||||
test('multiple created', () => {
|
||||
const createdDivs: Array<HTMLElement> = [createDiv(), createDiv(), createDiv(), createDiv()];
|
||||
each(createdDivs, (createdDiv: HTMLElement) => {
|
||||
expect(createdDiv.parentElement).toBeNull();
|
||||
});
|
||||
removeElements(createdDivs);
|
||||
});
|
||||
|
||||
test('single existing', () => {
|
||||
const { childNodes } = slotElm;
|
||||
const { length } = childNodes;
|
||||
expect(length).not.toBe(0);
|
||||
removeElements(childNodes[0]);
|
||||
expect(childNodes.length).toBe(length - 1);
|
||||
});
|
||||
|
||||
test('multiple existing', () => {
|
||||
const { childNodes } = slotElm;
|
||||
expect(childNodes.length).not.toBe(0);
|
||||
removeElements(childNodes);
|
||||
expect(childNodes.length).toBe(0);
|
||||
});
|
||||
|
||||
test('none', () => {
|
||||
// @ts-ignore
|
||||
removeElements(null);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,210 +4,210 @@ const slotElm = document.body;
|
||||
const testHTML = '<div id="parent" class="div-class"><div id="child" class="div-class"></div></div><p>2</p><input type="text" value="3"></input>abc';
|
||||
|
||||
describe('dom traversal', () => {
|
||||
beforeEach(() => {
|
||||
slotElm.innerHTML = testHTML;
|
||||
});
|
||||
afterEach(() => {
|
||||
slotElm.innerHTML = '';
|
||||
beforeEach(() => {
|
||||
slotElm.innerHTML = testHTML;
|
||||
});
|
||||
afterEach(() => {
|
||||
slotElm.innerHTML = '';
|
||||
});
|
||||
|
||||
describe('find', () => {
|
||||
test('by class', () => {
|
||||
const divClass = find('.div-class');
|
||||
|
||||
expect(divClass.length).toBe(2);
|
||||
expect(divClass[1].parentElement).toBe(divClass[0]);
|
||||
});
|
||||
|
||||
describe('find', () => {
|
||||
test('by class', () => {
|
||||
const divClass = find('.div-class');
|
||||
test('by id', () => {
|
||||
const parentId = find('#parent');
|
||||
|
||||
expect(divClass.length).toBe(2);
|
||||
expect(divClass[1].parentElement).toBe(divClass[0]);
|
||||
});
|
||||
|
||||
test('by id', () => {
|
||||
const parentId = find('#parent');
|
||||
|
||||
expect(parentId.length).toBe(1);
|
||||
expect(parentId[0]).toBe(document.querySelector('#parent'));
|
||||
});
|
||||
|
||||
test('all', () => {
|
||||
const all = find('*');
|
||||
const allNative = document.querySelectorAll('*');
|
||||
|
||||
expect(all.length).toBe(allNative.length);
|
||||
expect(Array.from(all)).toEqual(Array.from(allNative));
|
||||
});
|
||||
|
||||
test('all with defined parent', () => {
|
||||
const all = find('*', document.querySelector('#parent'));
|
||||
const allNative = document.querySelector('#parent')?.querySelectorAll('*');
|
||||
|
||||
expect(all.length).toBe(allNative?.length);
|
||||
expect(Array.from(all)).toEqual(Array.from(allNative!));
|
||||
});
|
||||
|
||||
test('all with null parent', () => {
|
||||
const all = find('*', null);
|
||||
const allNative = document.querySelectorAll('*');
|
||||
|
||||
expect(all.length).toBe(allNative.length);
|
||||
expect(Array.from(all)).toEqual(Array.from(allNative!));
|
||||
});
|
||||
|
||||
test('non-existent', () => {
|
||||
const nonExistent = find('#non-existent');
|
||||
|
||||
expect(nonExistent.length).toBe(0);
|
||||
});
|
||||
expect(parentId.length).toBe(1);
|
||||
expect(parentId[0]).toBe(document.querySelector('#parent'));
|
||||
});
|
||||
|
||||
describe('findFirst', () => {
|
||||
test('by class', () => {
|
||||
const divClass = findFirst('.div-class');
|
||||
test('all', () => {
|
||||
const all = find('*');
|
||||
const allNative = document.querySelectorAll('*');
|
||||
|
||||
expect(divClass).toBe(document.querySelector('.div-class'));
|
||||
});
|
||||
|
||||
test('by id', () => {
|
||||
const parentId = findFirst('#parent');
|
||||
|
||||
expect(parentId).toBe(document.querySelector('#parent'));
|
||||
});
|
||||
|
||||
test('all', () => {
|
||||
const all = findFirst('*');
|
||||
const allNative = document.querySelector('*');
|
||||
|
||||
expect(all).toBe(allNative);
|
||||
});
|
||||
|
||||
test('all with defined parent', () => {
|
||||
const all = findFirst('*', document.querySelector('#parent'));
|
||||
const allNative = document.querySelector('#parent')?.querySelector('*');
|
||||
|
||||
expect(all).toBe(allNative);
|
||||
});
|
||||
|
||||
test('all with null parent', () => {
|
||||
const all = findFirst('*', null);
|
||||
const allNative = document.querySelector('*');
|
||||
|
||||
expect(all).toBe(allNative);
|
||||
});
|
||||
|
||||
test('non-existent', () => {
|
||||
const nonExistent = findFirst('#non-existent');
|
||||
|
||||
expect(nonExistent).toBe(null);
|
||||
});
|
||||
expect(all.length).toBe(allNative.length);
|
||||
expect(Array.from(all)).toEqual(Array.from(allNative));
|
||||
});
|
||||
|
||||
describe('is', () => {
|
||||
test('tag', () => {
|
||||
expect(is(findFirst('input'), 'input')).toBe(true);
|
||||
expect(is(findFirst('body'), 'body')).toBe(true);
|
||||
expect(is(findFirst('div'), 'div')).toBe(true);
|
||||
test('all with defined parent', () => {
|
||||
const all = find('*', document.querySelector('#parent'));
|
||||
const allNative = document.querySelector('#parent')?.querySelectorAll('*');
|
||||
|
||||
expect(is(findFirst('input'), 'body')).toBe(false);
|
||||
expect(is(findFirst('body'), 'input')).toBe(false);
|
||||
expect(is(findFirst('div'), 'head')).toBe(false);
|
||||
});
|
||||
|
||||
test('id', () => {
|
||||
expect(is(findFirst('#parent'), '#parent')).toBe(true);
|
||||
expect(is(findFirst('#child'), '#parent')).toBe(false);
|
||||
});
|
||||
|
||||
test('class', () => {
|
||||
expect(is(findFirst('.div-class'), '.div-class')).toBe(true);
|
||||
expect(is(findFirst('.div-class'), '.other-class')).toBe(false);
|
||||
});
|
||||
|
||||
test('visibility', () => {
|
||||
expect(is(findFirst('.div-class'), ':visible')).toBe(false);
|
||||
expect(is(findFirst('.div-class'), ':hidden')).toBe(true);
|
||||
});
|
||||
|
||||
test('created', () => {
|
||||
const div = createDiv();
|
||||
expect(div.parentNode).toBeNull();
|
||||
|
||||
expect(is(div, 'div')).toBe(true);
|
||||
|
||||
expect(is(div, 'body')).toBe(false);
|
||||
expect(is(div, 'input')).toBe(false);
|
||||
expect(is(div, 'head')).toBe(false);
|
||||
|
||||
expect(is(div, '#parent')).toBe(false);
|
||||
expect(is(div, '#parent')).toBe(false);
|
||||
|
||||
expect(is(div, '.div-class')).toBe(false);
|
||||
expect(is(div, '.other-class')).toBe(false);
|
||||
|
||||
expect(is(div, ':visible')).toBe(false);
|
||||
expect(is(div, ':hidden')).toBe(true);
|
||||
});
|
||||
|
||||
test('none', () => {
|
||||
expect(is(null, 'body')).toBe(false);
|
||||
expect(is(null, 'input')).toBe(false);
|
||||
expect(is(null, 'head')).toBe(false);
|
||||
|
||||
expect(is(null, '#parent')).toBe(false);
|
||||
expect(is(null, '#parent')).toBe(false);
|
||||
|
||||
expect(is(null, '.div-class')).toBe(false);
|
||||
expect(is(null, '.other-class')).toBe(false);
|
||||
|
||||
expect(is(null, ':visible')).toBe(false);
|
||||
expect(is(null, ':hidden')).toBe(false);
|
||||
});
|
||||
expect(all.length).toBe(allNative?.length);
|
||||
expect(Array.from(all)).toEqual(Array.from(allNative));
|
||||
});
|
||||
|
||||
describe('children', () => {
|
||||
test('available element', () => {
|
||||
const childs = children(document.body);
|
||||
test('all with null parent', () => {
|
||||
const all = find('*', null);
|
||||
const allNative = document.querySelectorAll('*');
|
||||
|
||||
expect(childs.length).toBe(document.body.children.length);
|
||||
expect(childs).toEqual(Array.from(document.body.children));
|
||||
});
|
||||
|
||||
test('unavailable element', () => {
|
||||
const childs = children(null);
|
||||
|
||||
expect(childs.length).toEqual(0);
|
||||
});
|
||||
|
||||
test('with selector', () => {
|
||||
const childs = children(document.body, 'input');
|
||||
|
||||
expect(childs.length).toBe(1);
|
||||
expect(childs[0]).toBe(findFirst('input'));
|
||||
});
|
||||
expect(all.length).toBe(allNative.length);
|
||||
expect(Array.from(all)).toEqual(Array.from(allNative));
|
||||
});
|
||||
|
||||
describe('contents', () => {
|
||||
test('available element', () => {
|
||||
const childs = contents(document.body);
|
||||
test('non-existent', () => {
|
||||
const nonExistent = find('#non-existent');
|
||||
|
||||
expect(childs.length).toBe(document.body.childNodes.length);
|
||||
expect(childs).toEqual(Array.from(document.body.childNodes));
|
||||
});
|
||||
expect(nonExistent.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
test('unavailable element', () => {
|
||||
const childs = contents(null);
|
||||
describe('findFirst', () => {
|
||||
test('by class', () => {
|
||||
const divClass = findFirst('.div-class');
|
||||
|
||||
expect(childs.length).toEqual(0);
|
||||
});
|
||||
expect(divClass).toBe(document.querySelector('.div-class'));
|
||||
});
|
||||
|
||||
describe('parent', () => {
|
||||
test('available element', () => {
|
||||
const p = parent(document.body);
|
||||
test('by id', () => {
|
||||
const parentId = findFirst('#parent');
|
||||
|
||||
expect(p).toBe(document.body.parentElement);
|
||||
});
|
||||
|
||||
test('unavailable element', () => {
|
||||
const p = parent(null);
|
||||
|
||||
expect(p).toBeNull();
|
||||
});
|
||||
expect(parentId).toBe(document.querySelector('#parent'));
|
||||
});
|
||||
});
|
||||
|
||||
test('all', () => {
|
||||
const all = findFirst('*');
|
||||
const allNative = document.querySelector('*');
|
||||
|
||||
expect(all).toBe(allNative);
|
||||
});
|
||||
|
||||
test('all with defined parent', () => {
|
||||
const all = findFirst('*', document.querySelector('#parent'));
|
||||
const allNative = document.querySelector('#parent')?.querySelector('*');
|
||||
|
||||
expect(all).toBe(allNative);
|
||||
});
|
||||
|
||||
test('all with null parent', () => {
|
||||
const all = findFirst('*', null);
|
||||
const allNative = document.querySelector('*');
|
||||
|
||||
expect(all).toBe(allNative);
|
||||
});
|
||||
|
||||
test('non-existent', () => {
|
||||
const nonExistent = findFirst('#non-existent');
|
||||
|
||||
expect(nonExistent).toBe(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe('is', () => {
|
||||
test('tag', () => {
|
||||
expect(is(findFirst('input'), 'input')).toBe(true);
|
||||
expect(is(findFirst('body'), 'body')).toBe(true);
|
||||
expect(is(findFirst('div'), 'div')).toBe(true);
|
||||
|
||||
expect(is(findFirst('input'), 'body')).toBe(false);
|
||||
expect(is(findFirst('body'), 'input')).toBe(false);
|
||||
expect(is(findFirst('div'), 'head')).toBe(false);
|
||||
});
|
||||
|
||||
test('id', () => {
|
||||
expect(is(findFirst('#parent'), '#parent')).toBe(true);
|
||||
expect(is(findFirst('#child'), '#parent')).toBe(false);
|
||||
});
|
||||
|
||||
test('class', () => {
|
||||
expect(is(findFirst('.div-class'), '.div-class')).toBe(true);
|
||||
expect(is(findFirst('.div-class'), '.other-class')).toBe(false);
|
||||
});
|
||||
|
||||
test('visibility', () => {
|
||||
expect(is(findFirst('.div-class'), ':visible')).toBe(false);
|
||||
expect(is(findFirst('.div-class'), ':hidden')).toBe(true);
|
||||
});
|
||||
|
||||
test('created', () => {
|
||||
const div = createDiv();
|
||||
expect(div.parentNode).toBeNull();
|
||||
|
||||
expect(is(div, 'div')).toBe(true);
|
||||
|
||||
expect(is(div, 'body')).toBe(false);
|
||||
expect(is(div, 'input')).toBe(false);
|
||||
expect(is(div, 'head')).toBe(false);
|
||||
|
||||
expect(is(div, '#parent')).toBe(false);
|
||||
expect(is(div, '#parent')).toBe(false);
|
||||
|
||||
expect(is(div, '.div-class')).toBe(false);
|
||||
expect(is(div, '.other-class')).toBe(false);
|
||||
|
||||
expect(is(div, ':visible')).toBe(false);
|
||||
expect(is(div, ':hidden')).toBe(true);
|
||||
});
|
||||
|
||||
test('none', () => {
|
||||
expect(is(null, 'body')).toBe(false);
|
||||
expect(is(null, 'input')).toBe(false);
|
||||
expect(is(null, 'head')).toBe(false);
|
||||
|
||||
expect(is(null, '#parent')).toBe(false);
|
||||
expect(is(null, '#parent')).toBe(false);
|
||||
|
||||
expect(is(null, '.div-class')).toBe(false);
|
||||
expect(is(null, '.other-class')).toBe(false);
|
||||
|
||||
expect(is(null, ':visible')).toBe(false);
|
||||
expect(is(null, ':hidden')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('children', () => {
|
||||
test('available element', () => {
|
||||
const childs = children(document.body);
|
||||
|
||||
expect(childs.length).toBe(document.body.children.length);
|
||||
expect(childs).toEqual(Array.from(document.body.children));
|
||||
});
|
||||
|
||||
test('unavailable element', () => {
|
||||
const childs = children(null);
|
||||
|
||||
expect(childs.length).toEqual(0);
|
||||
});
|
||||
|
||||
test('with selector', () => {
|
||||
const childs = children(document.body, 'input');
|
||||
|
||||
expect(childs.length).toBe(1);
|
||||
expect(childs[0]).toBe(findFirst('input'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('contents', () => {
|
||||
test('available element', () => {
|
||||
const childs = contents(document.body);
|
||||
|
||||
expect(childs.length).toBe(document.body.childNodes.length);
|
||||
expect(childs).toEqual(Array.from(document.body.childNodes));
|
||||
});
|
||||
|
||||
test('unavailable element', () => {
|
||||
const childs = contents(null);
|
||||
|
||||
expect(childs.length).toEqual(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('parent', () => {
|
||||
test('available element', () => {
|
||||
const p = parent(document.body);
|
||||
|
||||
expect(p).toBe(document.body.parentElement);
|
||||
});
|
||||
|
||||
test('unavailable element', () => {
|
||||
const p = parent(null);
|
||||
|
||||
expect(p).toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,77 +1,77 @@
|
||||
import { OptionsTemplate, OptionsAndOptionsTemplate, PlainObject } from "core/typings";
|
||||
import { optionsTemplateTypes as oTypes, transform } from "core/options";
|
||||
import { OptionsTemplate, OptionsAndOptionsTemplate, PlainObject } from 'core/typings';
|
||||
import { optionsTemplateTypes as oTypes, transform } from 'core/options';
|
||||
|
||||
type TestOptionsObj = { propA: 'propA', null: null };
|
||||
type TestOptionsObj = { propA: 'propA'; null: null };
|
||||
type TestOptionsEnum = 'A' | 'B' | 'C';
|
||||
type TestOptions = {
|
||||
str?: string;
|
||||
strArrNull?: string | Array<string> | null;
|
||||
nullbool?: boolean | null;
|
||||
nested?: {
|
||||
num?: number;
|
||||
switch?: boolean;
|
||||
abc?: TestOptionsEnum;
|
||||
};
|
||||
obj?: TestOptionsObj | null;
|
||||
str?: string;
|
||||
strArrNull?: string | Array<string> | null;
|
||||
nullbool?: boolean | null;
|
||||
nested?: {
|
||||
num?: number;
|
||||
switch?: boolean;
|
||||
abc?: TestOptionsEnum;
|
||||
arr?: Array<any>;
|
||||
func?: () => void;
|
||||
}
|
||||
};
|
||||
obj?: TestOptionsObj | null;
|
||||
abc?: TestOptionsEnum;
|
||||
arr?: Array<any>;
|
||||
func?: () => void;
|
||||
};
|
||||
type DeepRequired<T> = {
|
||||
[P in keyof T]-?: PlainObject extends T[P] ? DeepRequired<T[P]> : T[P];
|
||||
[P in keyof T]-?: PlainObject extends T[P] ? DeepRequired<T[P]> : T[P];
|
||||
};
|
||||
|
||||
const options: DeepRequired<TestOptions> = {
|
||||
str: 'hi',
|
||||
strArrNull: null,
|
||||
nullbool: true,
|
||||
nested: {
|
||||
num: 1,
|
||||
switch: false,
|
||||
abc: 'B',
|
||||
},
|
||||
obj: { propA: 'propA', null: null },
|
||||
abc: 'A',
|
||||
arr: [1, 2, 3],
|
||||
func: () => { }
|
||||
}
|
||||
str: 'hi',
|
||||
strArrNull: null,
|
||||
nullbool: true,
|
||||
nested: {
|
||||
num: 1,
|
||||
switch: false,
|
||||
abc: 'B',
|
||||
},
|
||||
obj: { propA: 'propA', null: null },
|
||||
abc: 'A',
|
||||
arr: [1, 2, 3],
|
||||
func: () => {},
|
||||
};
|
||||
|
||||
const optionsTemplate: OptionsTemplate<Required<TestOptions>> = {
|
||||
str: oTypes.string,
|
||||
strArrNull: [oTypes.string, oTypes.array, oTypes.null],
|
||||
nullbool: [oTypes.boolean, oTypes.null],
|
||||
nested: {
|
||||
num: oTypes.number,
|
||||
switch: oTypes.boolean,
|
||||
abc: 'A B C',
|
||||
},
|
||||
obj: [oTypes.object, oTypes.null],
|
||||
str: oTypes.string,
|
||||
strArrNull: [oTypes.string, oTypes.array, oTypes.null],
|
||||
nullbool: [oTypes.boolean, oTypes.null],
|
||||
nested: {
|
||||
num: oTypes.number,
|
||||
switch: oTypes.boolean,
|
||||
abc: 'A B C',
|
||||
arr: oTypes.array,
|
||||
func: oTypes.function,
|
||||
}
|
||||
},
|
||||
obj: [oTypes.object, oTypes.null],
|
||||
abc: 'A B C',
|
||||
arr: oTypes.array,
|
||||
func: oTypes.function,
|
||||
};
|
||||
|
||||
const optionsAndOptionsTemplate: OptionsAndOptionsTemplate<Required<TestOptions>> = {
|
||||
str: [options.str, optionsTemplate.str],
|
||||
strArrNull: [options.strArrNull, optionsTemplate.strArrNull],
|
||||
nullbool: [options.nullbool, optionsTemplate.nullbool],
|
||||
nested: {
|
||||
num: [options.nested.num, optionsTemplate.nested.num],
|
||||
switch: [options.nested.switch, optionsTemplate.nested.switch],
|
||||
abc: [options.nested.abc, optionsTemplate.nested.abc],
|
||||
},
|
||||
obj: [options.obj, optionsTemplate.obj],
|
||||
abc: [options.abc, optionsTemplate.abc],
|
||||
arr: [options.arr, optionsTemplate.arr],
|
||||
func: [options.func, optionsTemplate.func]
|
||||
str: [options.str, optionsTemplate.str],
|
||||
strArrNull: [options.strArrNull, optionsTemplate.strArrNull],
|
||||
nullbool: [options.nullbool, optionsTemplate.nullbool],
|
||||
nested: {
|
||||
num: [options.nested.num, optionsTemplate.nested.num],
|
||||
switch: [options.nested.switch, optionsTemplate.nested.switch],
|
||||
abc: [options.nested.abc, optionsTemplate.nested.abc],
|
||||
},
|
||||
obj: [options.obj, optionsTemplate.obj],
|
||||
abc: [options.abc, optionsTemplate.abc],
|
||||
arr: [options.arr, optionsTemplate.arr],
|
||||
func: [options.func, optionsTemplate.func],
|
||||
};
|
||||
|
||||
describe('options and options template object transformation', () => {
|
||||
test('transforms correctly into options object', () => {
|
||||
expect(transform(optionsAndOptionsTemplate)).toEqual(options);
|
||||
});
|
||||
test('transforms correctly into options object', () => {
|
||||
expect(transform(optionsAndOptionsTemplate)).toEqual(options);
|
||||
});
|
||||
|
||||
test('transforms correctly into template object', () => {
|
||||
expect(transform(optionsAndOptionsTemplate, true)).toEqual(optionsTemplate);
|
||||
});
|
||||
});
|
||||
test('transforms correctly into template object', () => {
|
||||
expect(transform(optionsAndOptionsTemplate, true)).toEqual(optionsTemplate);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,369 +2,438 @@ import { validate, optionsTemplateTypes as oTypes } from 'core/options';
|
||||
import { extend, isEmptyObject } from 'core/utils';
|
||||
import { OptionsTemplate } from 'core/typings';
|
||||
|
||||
type TestOptionsObj = { propA: 'propA', null: null };
|
||||
type TestOptionsObj = { propA: 'propA'; null: null };
|
||||
type TestOptionsEnum = 'A' | 'B' | 'C';
|
||||
type TestOptions = {
|
||||
str?: string;
|
||||
strArrNull?: string | Array<string> | null;
|
||||
nullbool?: boolean | null;
|
||||
nested?: {
|
||||
num?: number;
|
||||
switch?: boolean;
|
||||
abc?: TestOptionsEnum;
|
||||
};
|
||||
obj?: TestOptionsObj | null;
|
||||
str?: string;
|
||||
strArrNull?: string | Array<string> | null;
|
||||
nullbool?: boolean | null;
|
||||
nested?: {
|
||||
num?: number;
|
||||
switch?: boolean;
|
||||
abc?: TestOptionsEnum;
|
||||
arr?: Array<any>;
|
||||
func?: () => void;
|
||||
}
|
||||
};
|
||||
obj?: TestOptionsObj | null;
|
||||
abc?: TestOptionsEnum;
|
||||
arr?: Array<any>;
|
||||
func?: () => void;
|
||||
};
|
||||
|
||||
const options: TestOptions = {
|
||||
str: 'hi',
|
||||
strArrNull: null,
|
||||
nullbool: true,
|
||||
nested: {
|
||||
num: 1,
|
||||
switch: false,
|
||||
abc: 'B',
|
||||
},
|
||||
obj: { propA: 'propA', null: null },
|
||||
abc: 'A',
|
||||
arr: [1, 2, 3],
|
||||
func: () => { }
|
||||
}
|
||||
str: 'hi',
|
||||
strArrNull: null,
|
||||
nullbool: true,
|
||||
nested: {
|
||||
num: 1,
|
||||
switch: false,
|
||||
abc: 'B',
|
||||
},
|
||||
obj: { propA: 'propA', null: null },
|
||||
abc: 'A',
|
||||
arr: [1, 2, 3],
|
||||
func: () => {},
|
||||
};
|
||||
|
||||
const template: OptionsTemplate<Required<TestOptions>> = {
|
||||
str: oTypes.string,
|
||||
strArrNull: [oTypes.string, oTypes.array, oTypes.null],
|
||||
nullbool: [oTypes.boolean, oTypes.null],
|
||||
nested: {
|
||||
num: oTypes.number,
|
||||
switch: oTypes.boolean,
|
||||
abc: 'A B C',
|
||||
},
|
||||
obj: [oTypes.object, oTypes.null],
|
||||
str: oTypes.string,
|
||||
strArrNull: [oTypes.string, oTypes.array, oTypes.null],
|
||||
nullbool: [oTypes.boolean, oTypes.null],
|
||||
nested: {
|
||||
num: oTypes.number,
|
||||
switch: oTypes.boolean,
|
||||
abc: 'A B C',
|
||||
arr: oTypes.array,
|
||||
func: oTypes.function,
|
||||
}
|
||||
},
|
||||
obj: [oTypes.object, oTypes.null],
|
||||
abc: 'A B C',
|
||||
arr: oTypes.array,
|
||||
func: oTypes.function,
|
||||
};
|
||||
|
||||
describe('options validation', () => {
|
||||
describe('object return & mutation', () => {
|
||||
test('foreign properties wont affect validated object', () => {
|
||||
const foreignObj = { foreignProp: 'foreign', foreignDeep: { a: 'A', b: 'B' } };
|
||||
const modifiedOptions = extend({}, options, { nested: foreignObj }, foreignObj);
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { validated } = result;
|
||||
describe('object return & mutation', () => {
|
||||
test('foreign properties wont affect validated object', () => {
|
||||
const foreignObj = {
|
||||
foreignProp: 'foreign',
|
||||
foreignDeep: { a: 'A', b: 'B' },
|
||||
};
|
||||
const modifiedOptions = extend({}, options, { nested: foreignObj }, foreignObj);
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { validated } = result;
|
||||
|
||||
expect(validated).toEqual(options);
|
||||
});
|
||||
|
||||
test('passed objects arent mutated', () => {
|
||||
const clonedOptions = extend({}, options);
|
||||
validate(clonedOptions, template, clonedOptions);
|
||||
|
||||
expect(clonedOptions).toEqual(options);
|
||||
});
|
||||
|
||||
test('passed object isnt returned object', () => {
|
||||
const clonedOptions = extend({}, options);
|
||||
const result = validate(clonedOptions, template);
|
||||
|
||||
expect(result.validated).not.toBe(clonedOptions);
|
||||
});
|
||||
expect(validated).toEqual(options);
|
||||
});
|
||||
|
||||
describe('foreign property return', () => {
|
||||
test('return no foreign property', () => {
|
||||
const result = validate(options, template);
|
||||
test('passed objects arent mutated', () => {
|
||||
const clonedOptions = extend({}, options);
|
||||
validate(clonedOptions, template, clonedOptions);
|
||||
|
||||
expect(isEmptyObject(result.foreign)).toBe(true);
|
||||
});
|
||||
|
||||
test('return signle non-object foreign property', () => {
|
||||
const foreignObj = { foreignProp: 'foreign' };
|
||||
const modifiedOptions = extend({}, options, foreignObj);
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { foreign } = result;
|
||||
|
||||
expect(foreign).toEqual(foreignObj);
|
||||
});
|
||||
|
||||
test('return complex foreign properties', () => {
|
||||
const foreignObj = { foreignProp: 'foreign', foreignDeep: { a: 'A', b: 'B' } };
|
||||
const modifiedOptions = extend({}, options, foreignObj);
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { foreign } = result;
|
||||
|
||||
expect(foreign).toEqual(foreignObj);
|
||||
});
|
||||
|
||||
test('return nested complex foreign properties', () => {
|
||||
const foreignObj = { foreignProp: 'foreign', foreignDeep: { a: 'A', b: 'B' } };
|
||||
const modifiedOptions = extend({}, options, { nested: foreignObj }, foreignObj);
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { foreign } = result;
|
||||
|
||||
expect(foreign.nested).toEqual(foreignObj);
|
||||
delete foreign.nested;
|
||||
expect(foreign).toEqual(foreignObj);
|
||||
});
|
||||
expect(clonedOptions).toEqual(options);
|
||||
});
|
||||
|
||||
describe('diff property return', () => {
|
||||
test('one value changed', () => {
|
||||
const modifiedOptions = extend({}, options, { str: 'newvaluetest' });
|
||||
const result = validate(modifiedOptions, template, options);
|
||||
const { validated } = result;
|
||||
test('passed object isnt returned object', () => {
|
||||
const clonedOptions = extend({}, options);
|
||||
const result = validate(clonedOptions, template);
|
||||
|
||||
expect(validated.str).toBe('newvaluetest');
|
||||
delete validated.str;
|
||||
expect(isEmptyObject(validated)).toBe(true);
|
||||
});
|
||||
expect(result.validated).not.toBe(clonedOptions);
|
||||
});
|
||||
});
|
||||
|
||||
test('multiple values changed', () => {
|
||||
const modifiedOptions = extend({}, options, { str: 'newvaluetest', nullbool: null });
|
||||
const result = validate(modifiedOptions, template, options);
|
||||
const { validated } = result;
|
||||
describe('foreign property return', () => {
|
||||
test('return no foreign property', () => {
|
||||
const result = validate(options, template);
|
||||
|
||||
expect(validated.str).toBe('newvaluetest');
|
||||
expect(validated.nullbool).toBe(null);
|
||||
delete validated.str;
|
||||
delete validated.nullbool;
|
||||
expect(isEmptyObject(validated)).toBe(true);
|
||||
});
|
||||
|
||||
test('one nested value changed', () => {
|
||||
const modifiedOptions = extend({}, options, { nested: { num: -1293 } });
|
||||
const result = validate(modifiedOptions, template, options);
|
||||
const { validated } = result;
|
||||
|
||||
expect(validated.nested?.num).toBe(-1293);
|
||||
delete validated.nested?.num;
|
||||
expect(isEmptyObject(validated.nested)).toBe(true);
|
||||
delete validated.nested;
|
||||
expect(isEmptyObject(validated)).toBe(true);
|
||||
});
|
||||
|
||||
test('multiple nested values changed', () => {
|
||||
const modifiedOptions = extend({}, options, { nested: { num: -1293, abc: 'C' } });
|
||||
const result = validate(modifiedOptions, template, options);
|
||||
const { validated } = result;
|
||||
|
||||
expect(validated.nested?.num).toBe(-1293);
|
||||
expect(validated.nested?.abc).toBe('C');
|
||||
delete validated.nested?.num;
|
||||
delete validated.nested?.abc;
|
||||
expect(isEmptyObject(validated.nested)).toBe(true);
|
||||
delete validated.nested;
|
||||
expect(isEmptyObject(validated)).toBe(true);
|
||||
});
|
||||
|
||||
test('various values changed', () => {
|
||||
const newFunc = () => { };
|
||||
const modifiedOptions = extend({}, options, { str: 'newstrvalue', func: newFunc, abc: 'C', nested: { num: -1293, abc: 'C' } });
|
||||
const result = validate(modifiedOptions, template, options);
|
||||
const { validated } = result;
|
||||
|
||||
expect(validated.str).toBe('newstrvalue');
|
||||
expect(validated.func).toBe(newFunc);
|
||||
expect(validated.abc).toBe('C');
|
||||
delete validated.str;
|
||||
delete validated.func;
|
||||
delete validated.abc;
|
||||
expect(validated.nested?.num).toBe(-1293);
|
||||
expect(validated.nested?.abc).toBe('C');
|
||||
delete validated.nested?.num;
|
||||
delete validated.nested?.abc;
|
||||
expect(isEmptyObject(validated.nested)).toBe(true);
|
||||
delete validated.nested;
|
||||
expect(isEmptyObject(validated)).toBe(true);
|
||||
});
|
||||
|
||||
test('various values changed with foreign properties', () => {
|
||||
const foreignObj = { foreignProp: 'foreign', foreignDeep: { a: 'A', b: 'B' } };
|
||||
const newFunc = () => { };
|
||||
const modifiedOptions = extend({}, options, { str: 'newstrvalue', func: newFunc, abc: 'C', nested: { num: -1293, abc: 'C' } }, foreignObj, { nested: foreignObj });
|
||||
const result = validate(modifiedOptions, template, options);
|
||||
const { validated } = result;
|
||||
|
||||
expect(validated.str).toBe('newstrvalue');
|
||||
expect(validated.func).toBe(newFunc);
|
||||
expect(validated.abc).toBe('C');
|
||||
delete validated.str;
|
||||
delete validated.func;
|
||||
delete validated.abc;
|
||||
expect(validated.nested?.num).toBe(-1293);
|
||||
expect(validated.nested?.abc).toBe('C');
|
||||
delete validated.nested?.num;
|
||||
delete validated.nested?.abc;
|
||||
expect(isEmptyObject(validated.nested)).toBe(true);
|
||||
delete validated.nested;
|
||||
expect(isEmptyObject(validated)).toBe(true);
|
||||
});
|
||||
expect(isEmptyObject(result.foreign)).toBe(true);
|
||||
});
|
||||
|
||||
describe('value validity', () => {
|
||||
test('single value doesnt match template', () => {
|
||||
const modifiedOptions = extend({}, options, { str: 1 });
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { validated } = result;
|
||||
test('return signle non-object foreign property', () => {
|
||||
const foreignObj = { foreignProp: 'foreign' };
|
||||
const modifiedOptions = extend({}, options, foreignObj);
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { foreign } = result;
|
||||
|
||||
expect(validated).not.toHaveProperty('str');
|
||||
});
|
||||
|
||||
test('single enum value doesnt match template', () => {
|
||||
const modifiedOptions = extend({}, options, { abc: 'testval' });
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { validated } = result;
|
||||
|
||||
expect(validated).not.toHaveProperty('abc');
|
||||
});
|
||||
|
||||
test('multiple values dont match template', () => {
|
||||
const modifiedOptions = extend({}, options, { str: 1, abc: 'testval', nullbool: 'string' });
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { validated } = result;
|
||||
|
||||
expect(validated).not.toHaveProperty('str');
|
||||
expect(validated).not.toHaveProperty('abc');
|
||||
expect(validated).not.toHaveProperty('nullbool');
|
||||
});
|
||||
|
||||
test('single nested value dont match template', () => {
|
||||
const modifiedOptions = extend({}, options, { nested: { num: 'hi' } });
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { validated } = result;
|
||||
|
||||
expect(validated.nested).not.toHaveProperty('num');
|
||||
});
|
||||
|
||||
test('single nested enum value dont match template', () => {
|
||||
const modifiedOptions = extend({}, options, { nested: { abc: 'testabc' } });
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { validated } = result;
|
||||
|
||||
expect(validated.nested).not.toHaveProperty('abc');
|
||||
});
|
||||
|
||||
test('multiple nested values dont match template', () => {
|
||||
const modifiedOptions = extend({}, options, { nested: { num: 'hi', abc: 'testabc' } });
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { validated } = result;
|
||||
|
||||
expect(validated.nested).not.toHaveProperty('num');
|
||||
expect(validated.nested).not.toHaveProperty('abc');
|
||||
});
|
||||
|
||||
test('all nested values dont match template', () => {
|
||||
const modifiedOptions = extend({}, options, { nested: { num: 'hi', abc: 'testabc', switch: 1 } });
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { validated } = result;
|
||||
|
||||
expect(validated).not.toHaveProperty('nested');
|
||||
});
|
||||
|
||||
test('all nested values dont match template with foreign property', () => {
|
||||
const modifiedOptions = extend({}, options, { nested: { foreign: 'foreign', num: 'hi', abc: 'testabc', switch: 1 } });
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { validated } = result;
|
||||
|
||||
expect(validated).not.toHaveProperty('nested');
|
||||
});
|
||||
|
||||
test('various values dont match template', () => {
|
||||
const modifiedOptions = extend({}, options, { nested: { switch: null }, obj: 1, abc: 'testest', func: {} });
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { validated } = result;
|
||||
|
||||
expect(validated.nested).not.toHaveProperty('switch');
|
||||
expect(validated).not.toHaveProperty('obj');
|
||||
expect(validated).not.toHaveProperty('abc');
|
||||
expect(validated).not.toHaveProperty('func');
|
||||
});
|
||||
|
||||
test('various values dont match template with foreign properties', () => {
|
||||
const foreignObj = { foreignProp: 'foreign', foreignDeep: { a: 'A', b: 'B' } };
|
||||
const modifiedOptions = extend({}, options, { nested: { switch: null }, obj: 1, abc: 'testest', func: {} }, foreignObj, { nested: foreignObj });
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { validated, foreign } = result;
|
||||
|
||||
expect(foreign.nested).toEqual(foreignObj);
|
||||
delete foreign.nested;
|
||||
expect(foreign).toEqual(foreignObj);
|
||||
|
||||
expect(validated.nested).not.toHaveProperty('switch');
|
||||
expect(validated).not.toHaveProperty('obj');
|
||||
expect(validated).not.toHaveProperty('abc');
|
||||
expect(validated).not.toHaveProperty('func');
|
||||
});
|
||||
|
||||
test('nested object is string', () => {
|
||||
const modifiedOptions = extend({}, options, { nested: 'string' });
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { validated } = result;
|
||||
|
||||
expect(validated).not.toHaveProperty('nested');
|
||||
});
|
||||
|
||||
test('nested object is null', () => {
|
||||
const modifiedOptions = extend({}, options, { nested: null });
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { validated } = result;
|
||||
|
||||
expect(validated).not.toHaveProperty('nested');
|
||||
});
|
||||
|
||||
test('nested object is undefined', () => {
|
||||
const modifiedOptions = extend({}, options);
|
||||
modifiedOptions.nested = undefined;
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { validated } = result;
|
||||
|
||||
expect(validated).not.toHaveProperty('nested');
|
||||
});
|
||||
expect(foreign).toEqual(foreignObj);
|
||||
});
|
||||
|
||||
describe('error logging', () => {
|
||||
test('dont log error if nothing is wrong', () => {
|
||||
const warn = console.warn;
|
||||
console.warn = jest.fn();
|
||||
test('return complex foreign properties', () => {
|
||||
const foreignObj = {
|
||||
foreignProp: 'foreign',
|
||||
foreignDeep: { a: 'A', b: 'B' },
|
||||
};
|
||||
const modifiedOptions = extend({}, options, foreignObj);
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { foreign } = result;
|
||||
|
||||
validate(options, template, {}, true);
|
||||
expect(console.warn).not.toBeCalled();
|
||||
|
||||
console.warn = warn;
|
||||
});
|
||||
|
||||
test('dont log error if something is wrong and flag is false', () => {
|
||||
const warn = console.warn;
|
||||
console.warn = jest.fn();
|
||||
|
||||
const modifiedOptions = extend({}, options, { str: 1 });
|
||||
validate(modifiedOptions, template, {}, false);
|
||||
expect(console.warn).not.toBeCalled();
|
||||
|
||||
console.warn = warn;
|
||||
});
|
||||
|
||||
test('log error if something is wrong and flag is true', () => {
|
||||
const warn = console.warn;
|
||||
console.warn = jest.fn();
|
||||
|
||||
// str must be string
|
||||
validate(extend({}, options, { str: 1 }), template, {}, true);
|
||||
expect(console.warn).toBeCalledTimes(1);
|
||||
|
||||
// abc must be A | B | C
|
||||
validate(extend({}, options, { abc: 'some string' }), template, {}, true);
|
||||
expect(console.warn).toBeCalledTimes(2);
|
||||
|
||||
// everthing OK
|
||||
validate(extend({}, options, { abc: 'C' }), template, {}, true);
|
||||
expect(console.warn).toBeCalledTimes(2);
|
||||
|
||||
console.warn = warn;
|
||||
});
|
||||
expect(foreign).toEqual(foreignObj);
|
||||
});
|
||||
});
|
||||
|
||||
test('return nested complex foreign properties', () => {
|
||||
const foreignObj = {
|
||||
foreignProp: 'foreign',
|
||||
foreignDeep: { a: 'A', b: 'B' },
|
||||
};
|
||||
const modifiedOptions = extend({}, options, { nested: foreignObj }, foreignObj);
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { foreign } = result;
|
||||
|
||||
expect(foreign.nested).toEqual(foreignObj);
|
||||
delete foreign.nested;
|
||||
expect(foreign).toEqual(foreignObj);
|
||||
});
|
||||
});
|
||||
|
||||
describe('diff property return', () => {
|
||||
test('one value changed', () => {
|
||||
const modifiedOptions = extend({}, options, { str: 'newvaluetest' });
|
||||
const result = validate(modifiedOptions, template, options);
|
||||
const { validated } = result;
|
||||
|
||||
expect(validated.str).toBe('newvaluetest');
|
||||
delete validated.str;
|
||||
expect(isEmptyObject(validated)).toBe(true);
|
||||
});
|
||||
|
||||
test('multiple values changed', () => {
|
||||
const modifiedOptions = extend({}, options, {
|
||||
str: 'newvaluetest',
|
||||
nullbool: null,
|
||||
});
|
||||
const result = validate(modifiedOptions, template, options);
|
||||
const { validated } = result;
|
||||
|
||||
expect(validated.str).toBe('newvaluetest');
|
||||
expect(validated.nullbool).toBe(null);
|
||||
delete validated.str;
|
||||
delete validated.nullbool;
|
||||
expect(isEmptyObject(validated)).toBe(true);
|
||||
});
|
||||
|
||||
test('one nested value changed', () => {
|
||||
const modifiedOptions = extend({}, options, { nested: { num: -1293 } });
|
||||
const result = validate(modifiedOptions, template, options);
|
||||
const { validated } = result;
|
||||
|
||||
expect(validated.nested?.num).toBe(-1293);
|
||||
delete validated.nested?.num;
|
||||
expect(isEmptyObject(validated.nested)).toBe(true);
|
||||
delete validated.nested;
|
||||
expect(isEmptyObject(validated)).toBe(true);
|
||||
});
|
||||
|
||||
test('multiple nested values changed', () => {
|
||||
const modifiedOptions = extend({}, options, {
|
||||
nested: { num: -1293, abc: 'C' },
|
||||
});
|
||||
const result = validate(modifiedOptions, template, options);
|
||||
const { validated } = result;
|
||||
|
||||
expect(validated.nested?.num).toBe(-1293);
|
||||
expect(validated.nested?.abc).toBe('C');
|
||||
delete validated.nested?.num;
|
||||
delete validated.nested?.abc;
|
||||
expect(isEmptyObject(validated.nested)).toBe(true);
|
||||
delete validated.nested;
|
||||
expect(isEmptyObject(validated)).toBe(true);
|
||||
});
|
||||
|
||||
test('various values changed', () => {
|
||||
const newFunc = () => {};
|
||||
const modifiedOptions = extend({}, options, {
|
||||
str: 'newstrvalue',
|
||||
func: newFunc,
|
||||
abc: 'C',
|
||||
nested: { num: -1293, abc: 'C' },
|
||||
});
|
||||
const result = validate(modifiedOptions, template, options);
|
||||
const { validated } = result;
|
||||
|
||||
expect(validated.str).toBe('newstrvalue');
|
||||
expect(validated.func).toBe(newFunc);
|
||||
expect(validated.abc).toBe('C');
|
||||
delete validated.str;
|
||||
delete validated.func;
|
||||
delete validated.abc;
|
||||
expect(validated.nested?.num).toBe(-1293);
|
||||
expect(validated.nested?.abc).toBe('C');
|
||||
delete validated.nested?.num;
|
||||
delete validated.nested?.abc;
|
||||
expect(isEmptyObject(validated.nested)).toBe(true);
|
||||
delete validated.nested;
|
||||
expect(isEmptyObject(validated)).toBe(true);
|
||||
});
|
||||
|
||||
test('various values changed with foreign properties', () => {
|
||||
const foreignObj = {
|
||||
foreignProp: 'foreign',
|
||||
foreignDeep: { a: 'A', b: 'B' },
|
||||
};
|
||||
const newFunc = () => {};
|
||||
const modifiedOptions = extend(
|
||||
{},
|
||||
options,
|
||||
{
|
||||
str: 'newstrvalue',
|
||||
func: newFunc,
|
||||
abc: 'C',
|
||||
nested: { num: -1293, abc: 'C' },
|
||||
},
|
||||
foreignObj,
|
||||
{ nested: foreignObj },
|
||||
);
|
||||
const result = validate(modifiedOptions, template, options);
|
||||
const { validated } = result;
|
||||
|
||||
expect(validated.str).toBe('newstrvalue');
|
||||
expect(validated.func).toBe(newFunc);
|
||||
expect(validated.abc).toBe('C');
|
||||
delete validated.str;
|
||||
delete validated.func;
|
||||
delete validated.abc;
|
||||
expect(validated.nested?.num).toBe(-1293);
|
||||
expect(validated.nested?.abc).toBe('C');
|
||||
delete validated.nested?.num;
|
||||
delete validated.nested?.abc;
|
||||
expect(isEmptyObject(validated.nested)).toBe(true);
|
||||
delete validated.nested;
|
||||
expect(isEmptyObject(validated)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('value validity', () => {
|
||||
test('single value doesnt match template', () => {
|
||||
const modifiedOptions = extend({}, options, { str: 1 });
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { validated } = result;
|
||||
|
||||
expect(validated).not.toHaveProperty('str');
|
||||
});
|
||||
|
||||
test('single enum value doesnt match template', () => {
|
||||
const modifiedOptions = extend({}, options, { abc: 'testval' });
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { validated } = result;
|
||||
|
||||
expect(validated).not.toHaveProperty('abc');
|
||||
});
|
||||
|
||||
test('multiple values dont match template', () => {
|
||||
const modifiedOptions = extend({}, options, {
|
||||
str: 1,
|
||||
abc: 'testval',
|
||||
nullbool: 'string',
|
||||
});
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { validated } = result;
|
||||
|
||||
expect(validated).not.toHaveProperty('str');
|
||||
expect(validated).not.toHaveProperty('abc');
|
||||
expect(validated).not.toHaveProperty('nullbool');
|
||||
});
|
||||
|
||||
test('single nested value dont match template', () => {
|
||||
const modifiedOptions = extend({}, options, { nested: { num: 'hi' } });
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { validated } = result;
|
||||
|
||||
expect(validated.nested).not.toHaveProperty('num');
|
||||
});
|
||||
|
||||
test('single nested enum value dont match template', () => {
|
||||
const modifiedOptions = extend({}, options, {
|
||||
nested: { abc: 'testabc' },
|
||||
});
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { validated } = result;
|
||||
|
||||
expect(validated.nested).not.toHaveProperty('abc');
|
||||
});
|
||||
|
||||
test('multiple nested values dont match template', () => {
|
||||
const modifiedOptions = extend({}, options, {
|
||||
nested: { num: 'hi', abc: 'testabc' },
|
||||
});
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { validated } = result;
|
||||
|
||||
expect(validated.nested).not.toHaveProperty('num');
|
||||
expect(validated.nested).not.toHaveProperty('abc');
|
||||
});
|
||||
|
||||
test('all nested values dont match template', () => {
|
||||
const modifiedOptions = extend({}, options, {
|
||||
nested: { num: 'hi', abc: 'testabc', switch: 1 },
|
||||
});
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { validated } = result;
|
||||
|
||||
expect(validated).not.toHaveProperty('nested');
|
||||
});
|
||||
|
||||
test('all nested values dont match template with foreign property', () => {
|
||||
const modifiedOptions = extend({}, options, {
|
||||
nested: {
|
||||
foreign: 'foreign',
|
||||
num: 'hi',
|
||||
abc: 'testabc',
|
||||
switch: 1,
|
||||
},
|
||||
});
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { validated } = result;
|
||||
|
||||
expect(validated).not.toHaveProperty('nested');
|
||||
});
|
||||
|
||||
test('various values dont match template', () => {
|
||||
const modifiedOptions = extend({}, options, {
|
||||
nested: { switch: null },
|
||||
obj: 1,
|
||||
abc: 'testest',
|
||||
func: {},
|
||||
});
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { validated } = result;
|
||||
|
||||
expect(validated.nested).not.toHaveProperty('switch');
|
||||
expect(validated).not.toHaveProperty('obj');
|
||||
expect(validated).not.toHaveProperty('abc');
|
||||
expect(validated).not.toHaveProperty('func');
|
||||
});
|
||||
|
||||
test('various values dont match template with foreign properties', () => {
|
||||
const foreignObj = {
|
||||
foreignProp: 'foreign',
|
||||
foreignDeep: { a: 'A', b: 'B' },
|
||||
};
|
||||
const modifiedOptions = extend(
|
||||
{},
|
||||
options,
|
||||
{
|
||||
nested: { switch: null },
|
||||
obj: 1,
|
||||
abc: 'testest',
|
||||
func: {},
|
||||
},
|
||||
foreignObj,
|
||||
{ nested: foreignObj },
|
||||
);
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { validated, foreign } = result;
|
||||
|
||||
expect(foreign.nested).toEqual(foreignObj);
|
||||
delete foreign.nested;
|
||||
expect(foreign).toEqual(foreignObj);
|
||||
|
||||
expect(validated.nested).not.toHaveProperty('switch');
|
||||
expect(validated).not.toHaveProperty('obj');
|
||||
expect(validated).not.toHaveProperty('abc');
|
||||
expect(validated).not.toHaveProperty('func');
|
||||
});
|
||||
|
||||
test('nested object is string', () => {
|
||||
const modifiedOptions = extend({}, options, { nested: 'string' });
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { validated } = result;
|
||||
|
||||
expect(validated).not.toHaveProperty('nested');
|
||||
});
|
||||
|
||||
test('nested object is null', () => {
|
||||
const modifiedOptions = extend({}, options, { nested: null });
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { validated } = result;
|
||||
|
||||
expect(validated).not.toHaveProperty('nested');
|
||||
});
|
||||
|
||||
test('nested object is undefined', () => {
|
||||
const modifiedOptions = extend({}, options);
|
||||
modifiedOptions.nested = undefined;
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { validated } = result;
|
||||
|
||||
expect(validated).not.toHaveProperty('nested');
|
||||
});
|
||||
});
|
||||
|
||||
describe('error logging', () => {
|
||||
test('dont log error if nothing is wrong', () => {
|
||||
const { warn } = console;
|
||||
console.warn = jest.fn();
|
||||
|
||||
validate(options, template, {}, true);
|
||||
expect(console.warn).not.toBeCalled();
|
||||
|
||||
console.warn = warn;
|
||||
});
|
||||
|
||||
test('dont log error if something is wrong and flag is false', () => {
|
||||
const { warn } = console;
|
||||
console.warn = jest.fn();
|
||||
|
||||
const modifiedOptions = extend({}, options, { str: 1 });
|
||||
validate(modifiedOptions, template, {}, false);
|
||||
expect(console.warn).not.toBeCalled();
|
||||
|
||||
console.warn = warn;
|
||||
});
|
||||
|
||||
test('log error if something is wrong and flag is true', () => {
|
||||
const { warn } = console;
|
||||
console.warn = jest.fn();
|
||||
|
||||
// str must be string
|
||||
validate(extend({}, options, { str: 1 }), template, {}, true);
|
||||
expect(console.warn).toBeCalledTimes(1);
|
||||
|
||||
// abc must be A | B | C
|
||||
validate(extend({}, options, { abc: 'some string' }), template, {}, true);
|
||||
expect(console.warn).toBeCalledTimes(2);
|
||||
|
||||
// everthing OK
|
||||
validate(extend({}, options, { abc: 'C' }), template, {}, true);
|
||||
expect(console.warn).toBeCalledTimes(2);
|
||||
|
||||
console.warn = warn;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,176 +1,179 @@
|
||||
import { each, indexOf } from 'core/utils/arrays';
|
||||
import { each, indexOf } from 'core/utils/array';
|
||||
|
||||
describe('array utilities', () => {
|
||||
describe('each', () => {
|
||||
describe('each through Array', () => {
|
||||
test('returns input', () => {
|
||||
const arr = [1, 2, 3];
|
||||
expect(each(arr, () => { })).toBe(arr);
|
||||
});
|
||||
describe('each', () => {
|
||||
describe('each through Array', () => {
|
||||
test('returns input', () => {
|
||||
const arr = [1, 2, 3];
|
||||
expect(each(arr, () => {})).toBe(arr);
|
||||
});
|
||||
|
||||
test('correct times', () => {
|
||||
const arr = [1, 2, 3];
|
||||
const eachCallback = jest.fn();
|
||||
test('correct times', () => {
|
||||
const arr = [1, 2, 3];
|
||||
const eachCallback = jest.fn();
|
||||
|
||||
each(arr, eachCallback);
|
||||
expect(eachCallback).toBeCalledTimes(arr.length);
|
||||
});
|
||||
each(arr, eachCallback);
|
||||
expect(eachCallback).toBeCalledTimes(arr.length);
|
||||
});
|
||||
|
||||
test('correct callback values', () => {
|
||||
const arr = [1, 2, 3];
|
||||
each(arr, (value, index, src) => {
|
||||
expect(value).toBe(arr[index]);
|
||||
expect(arr).toBe(src);
|
||||
});
|
||||
});
|
||||
test('correct callback values', () => {
|
||||
const arr = [1, 2, 3];
|
||||
each(arr, (value, index, src) => {
|
||||
expect(value).toBe(arr[index]);
|
||||
expect(arr).toBe(src);
|
||||
});
|
||||
});
|
||||
|
||||
test('return false equals break', () => {
|
||||
const arr = [1, 2, 3];
|
||||
const testFunc = jest.fn();
|
||||
test('return false equals break', () => {
|
||||
const arr = [1, 2, 3];
|
||||
const testFunc = jest.fn();
|
||||
|
||||
each(arr, () => {
|
||||
testFunc();
|
||||
return false;
|
||||
});
|
||||
|
||||
expect(testFunc).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
test('return true equals continue', () => {
|
||||
const arr = [1, 2, 3];
|
||||
const testFunc = jest.fn();
|
||||
|
||||
each(arr, (value, index) => {
|
||||
if (index === 0)
|
||||
return true;
|
||||
testFunc();
|
||||
});
|
||||
|
||||
expect(testFunc).toBeCalledTimes(arr.length - 1);
|
||||
});
|
||||
each(arr, () => {
|
||||
testFunc();
|
||||
return false;
|
||||
});
|
||||
|
||||
describe('each through Object', () => {
|
||||
test('returns input', () => {
|
||||
const obj = {
|
||||
a: 1,
|
||||
b: 2,
|
||||
c: 3
|
||||
};
|
||||
expect(each(obj, () => { })).toBe(obj);
|
||||
});
|
||||
expect(testFunc).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
test('correct times', () => {
|
||||
const obj = {
|
||||
a: 1,
|
||||
b: 2,
|
||||
c: 3
|
||||
};
|
||||
const eachCallback = jest.fn();
|
||||
test('return true equals continue', () => {
|
||||
const arr = [1, 2, 3];
|
||||
const testFunc = jest.fn();
|
||||
|
||||
each(obj, eachCallback);
|
||||
expect(eachCallback).toBeCalledTimes(Object.keys(obj).length);
|
||||
});
|
||||
|
||||
test('correct callback values', () => {
|
||||
const obj = {
|
||||
a: 1,
|
||||
b: 2,
|
||||
c: 3
|
||||
};
|
||||
each(obj, (value, key, src) => {
|
||||
expect(value).toBe(obj[key]);
|
||||
expect(obj).toBe(src);
|
||||
});
|
||||
});
|
||||
|
||||
test('return false equals break', () => {
|
||||
const obj = {
|
||||
a: 1,
|
||||
b: 2,
|
||||
c: 3
|
||||
};
|
||||
const testFunc = jest.fn();
|
||||
|
||||
each(obj, () => {
|
||||
testFunc();
|
||||
return false;
|
||||
});
|
||||
|
||||
expect(testFunc).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
test('return true equals continue', () => {
|
||||
const obj = {
|
||||
a: 1,
|
||||
b: 2,
|
||||
c: 3
|
||||
};
|
||||
const testFunc = jest.fn();
|
||||
let index = -1;
|
||||
|
||||
each(obj, (value) => {
|
||||
index++;
|
||||
if (index === 0)
|
||||
return true;
|
||||
testFunc();
|
||||
});
|
||||
|
||||
expect(testFunc).toBeCalledTimes(Object.keys(obj).length - 1);
|
||||
});
|
||||
each(arr, (value, index) => {
|
||||
if (index === 0) {
|
||||
return true;
|
||||
}
|
||||
testFunc();
|
||||
});
|
||||
|
||||
describe('each through ArrayLike Object', () => {
|
||||
test('returns input', () => {
|
||||
const arrLikeObj = document.querySelectorAll('*');
|
||||
expect(each(arrLikeObj, () => { })).toBe(arrLikeObj);
|
||||
});
|
||||
|
||||
test('correct times', () => {
|
||||
const arrLikeObj = document.querySelectorAll('*');
|
||||
const eachCallback = jest.fn();
|
||||
|
||||
each(arrLikeObj, eachCallback);
|
||||
expect(eachCallback).toBeCalledTimes(arrLikeObj.length);
|
||||
});
|
||||
|
||||
test('correct callback values', () => {
|
||||
const arrLikeObj = document.querySelectorAll('*');
|
||||
each(arrLikeObj, (value, index, src) => {
|
||||
expect(value).toBe(arrLikeObj[index]);
|
||||
expect(src).toBe(arrLikeObj);
|
||||
});
|
||||
});
|
||||
|
||||
test('return false equals break', () => {
|
||||
const arrLikeObj = document.querySelectorAll('*');
|
||||
const testFunc = jest.fn();
|
||||
|
||||
each(arrLikeObj, () => {
|
||||
testFunc();
|
||||
return false;
|
||||
});
|
||||
|
||||
expect(testFunc).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
test('return true equals continue', () => {
|
||||
const arrLikeObj = document.querySelectorAll('*');
|
||||
const testFunc = jest.fn();
|
||||
|
||||
each(arrLikeObj, (value, index) => {
|
||||
if (index === 0)
|
||||
return true;
|
||||
testFunc();
|
||||
});
|
||||
|
||||
expect(testFunc).toBeCalledTimes(arrLikeObj.length - 1);
|
||||
});
|
||||
});
|
||||
expect(testFunc).toBeCalledTimes(arr.length - 1);
|
||||
});
|
||||
});
|
||||
|
||||
test('indexOf', () => {
|
||||
const idx = indexOf([1, 2, 3], 2);
|
||||
expect(idx).toBe(1);
|
||||
describe('each through Object', () => {
|
||||
test('returns input', () => {
|
||||
const obj = {
|
||||
a: 1,
|
||||
b: 2,
|
||||
c: 3,
|
||||
};
|
||||
expect(each(obj, () => {})).toBe(obj);
|
||||
});
|
||||
|
||||
test('correct times', () => {
|
||||
const obj = {
|
||||
a: 1,
|
||||
b: 2,
|
||||
c: 3,
|
||||
};
|
||||
const eachCallback = jest.fn();
|
||||
|
||||
each(obj, eachCallback);
|
||||
expect(eachCallback).toBeCalledTimes(Object.keys(obj).length);
|
||||
});
|
||||
|
||||
test('correct callback values', () => {
|
||||
const obj = {
|
||||
a: 1,
|
||||
b: 2,
|
||||
c: 3,
|
||||
};
|
||||
each(obj, (value, key, src) => {
|
||||
expect(value).toBe(obj[key]);
|
||||
expect(obj).toBe(src);
|
||||
});
|
||||
});
|
||||
|
||||
test('return false equals break', () => {
|
||||
const obj = {
|
||||
a: 1,
|
||||
b: 2,
|
||||
c: 3,
|
||||
};
|
||||
const testFunc = jest.fn();
|
||||
|
||||
each(obj, () => {
|
||||
testFunc();
|
||||
return false;
|
||||
});
|
||||
|
||||
expect(testFunc).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
test('return true equals continue', () => {
|
||||
const obj = {
|
||||
a: 1,
|
||||
b: 2,
|
||||
c: 3,
|
||||
};
|
||||
const testFunc = jest.fn();
|
||||
let index = -1;
|
||||
|
||||
each(obj, () => {
|
||||
index++;
|
||||
if (index === 0) {
|
||||
return true;
|
||||
}
|
||||
testFunc();
|
||||
});
|
||||
|
||||
expect(testFunc).toBeCalledTimes(Object.keys(obj).length - 1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('each through ArrayLike Object', () => {
|
||||
test('returns input', () => {
|
||||
const arrLikeObj = document.querySelectorAll('*');
|
||||
expect(each(arrLikeObj, () => {})).toBe(arrLikeObj);
|
||||
});
|
||||
|
||||
test('correct times', () => {
|
||||
const arrLikeObj = document.querySelectorAll('*');
|
||||
const eachCallback = jest.fn();
|
||||
|
||||
each(arrLikeObj, eachCallback);
|
||||
expect(eachCallback).toBeCalledTimes(arrLikeObj.length);
|
||||
});
|
||||
|
||||
test('correct callback values', () => {
|
||||
const arrLikeObj = document.querySelectorAll('*');
|
||||
each(arrLikeObj, (value, index, src) => {
|
||||
expect(value).toBe(arrLikeObj[index]);
|
||||
expect(src).toBe(arrLikeObj);
|
||||
});
|
||||
});
|
||||
|
||||
test('return false equals break', () => {
|
||||
const arrLikeObj = document.querySelectorAll('*');
|
||||
const testFunc = jest.fn();
|
||||
|
||||
each(arrLikeObj, () => {
|
||||
testFunc();
|
||||
return false;
|
||||
});
|
||||
|
||||
expect(testFunc).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
test('return true equals continue', () => {
|
||||
const arrLikeObj = document.querySelectorAll('*');
|
||||
const testFunc = jest.fn();
|
||||
|
||||
each(arrLikeObj, (value, index) => {
|
||||
if (index === 0) {
|
||||
return true;
|
||||
}
|
||||
testFunc();
|
||||
});
|
||||
|
||||
expect(testFunc).toBeCalledTimes(arrLikeObj.length - 1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('indexOf', () => {
|
||||
const idx = indexOf([1, 2, 3], 2);
|
||||
expect(idx).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,148 +1,144 @@
|
||||
import { extend } from 'core/utils/extend';
|
||||
import { isPlainObject } from 'core/utils/types';
|
||||
|
||||
//type DeepPartial<T> = T extends object ? { [K in keyof T]?: DeepPartial<T[K]> } : T
|
||||
// type DeepPartial<T> = T extends object ? { [K in keyof T]?: DeepPartial<T[K]> } : T
|
||||
type Deep = {
|
||||
foo?: {
|
||||
bar?: boolean,
|
||||
baz?: boolean
|
||||
},
|
||||
foo2?: Document
|
||||
foo?: {
|
||||
bar?: boolean;
|
||||
baz?: boolean;
|
||||
};
|
||||
foo2?: Document;
|
||||
};
|
||||
type Settings = {
|
||||
xnumber0?: null,
|
||||
xnumber1?: number | null,
|
||||
xnumber2?: number | null,
|
||||
xstring1?: string,
|
||||
xstring2?: string,
|
||||
xxx?: string
|
||||
xnumber0?: null;
|
||||
xnumber1?: number | null;
|
||||
xnumber2?: number | null;
|
||||
xstring1?: string;
|
||||
xstring2?: string;
|
||||
xxx?: string;
|
||||
};
|
||||
type NestedArray = {
|
||||
arr: Array<any> | object
|
||||
arr: Array<any> | object;
|
||||
};
|
||||
|
||||
//https://github.com/jquery/jquery/blob/master/test/unit/core.js#L965
|
||||
// https://github.com/jquery/jquery/blob/master/test/unit/core.js#L965
|
||||
describe('extend', () => {
|
||||
test('equals object assign', () => {
|
||||
let settings: Settings = { xnumber1: 5, xnumber2: 7, xstring1: "peter", xstring2: "pan" };
|
||||
const options: Settings = { xnumber2: 1, xstring2: "x", xxx: "newstring" };
|
||||
const optionsCopy: Settings = { xnumber2: 1, xstring2: "x", xxx: "newstring" };
|
||||
const merged: Settings = { xnumber1: 5, xnumber2: 1, xstring1: "peter", xstring2: "x", xxx: "newstring" };
|
||||
test('equals object assign', () => {
|
||||
let settings: Settings = { xnumber1: 5, xnumber2: 7, xstring1: 'peter', xstring2: 'pan' };
|
||||
const options: Settings = { xnumber2: 1, xstring2: 'x', xxx: 'newstring' };
|
||||
const optionsCopy: Settings = { xnumber2: 1, xstring2: 'x', xxx: 'newstring' };
|
||||
const merged: Settings = { xnumber1: 5, xnumber2: 1, xstring1: 'peter', xstring2: 'x', xxx: 'newstring' };
|
||||
|
||||
extend(settings, options);
|
||||
expect(settings).toEqual(merged);
|
||||
expect(options).toEqual(optionsCopy);
|
||||
extend(settings, options);
|
||||
expect(settings).toEqual(merged);
|
||||
expect(options).toEqual(optionsCopy);
|
||||
|
||||
extend(settings, null, options);
|
||||
expect(settings).toEqual(merged);
|
||||
expect(options).toEqual(optionsCopy);
|
||||
extend(settings, null, options);
|
||||
expect(settings).toEqual(merged);
|
||||
expect(options).toEqual(optionsCopy);
|
||||
|
||||
const deep1: Deep = { foo: { bar: true } };
|
||||
const deep2: Deep = { foo: { baz: true }, foo2: document };
|
||||
const deep2copy: Deep = { foo: { baz: true }, foo2: document };
|
||||
const deepmerged: Deep = { foo: { bar: true, baz: true }, foo2: document };
|
||||
|
||||
const deep1: Deep = { foo: { bar: true } };
|
||||
const deep2: Deep = { foo: { baz: true }, foo2: document };
|
||||
const deep2copy: Deep = { foo: { baz: true }, foo2: document };
|
||||
const deepmerged: Deep = { foo: { bar: true, baz: true }, foo2: document };
|
||||
extend(deep1, deep2);
|
||||
expect(deep1.foo).toEqual(deepmerged.foo);
|
||||
expect(deep2.foo).toEqual(deep2copy.foo);
|
||||
expect(deep1.foo2).toBe(document);
|
||||
|
||||
extend(deep1, deep2);
|
||||
expect(deep1.foo).toEqual(deepmerged.foo);
|
||||
expect(deep2.foo).toEqual(deep2copy.foo);
|
||||
expect(deep1.foo2).toBe(document);
|
||||
const arr = [1, 2, 3];
|
||||
const nestedArray: NestedArray = { arr };
|
||||
|
||||
expect(extend({}, nestedArray).arr).not.toBe(arr);
|
||||
expect(Array.isArray(extend({ arr: {} }, nestedArray).arr)).toBeTruthy();
|
||||
expect(Array.isArray(extend({ arr: {} }, nestedArray).arr)).toBeTruthy();
|
||||
expect(isPlainObject(extend({ arr }, { arr: {} }).arr)).toBeTruthy();
|
||||
|
||||
const arr = [1, 2, 3];
|
||||
const nestedArray: NestedArray = { arr: arr };
|
||||
let empty: { foo?: any } = {};
|
||||
const optionsWithLength = { foo: { length: -1 } };
|
||||
|
||||
expect(extend({}, nestedArray).arr).not.toBe(arr);
|
||||
expect(Array.isArray(extend({ arr: {} }, nestedArray).arr)).toBeTruthy();
|
||||
expect(Array.isArray(extend({ arr: {} }, nestedArray).arr)).toBeTruthy();
|
||||
expect(isPlainObject(extend({ arr: arr }, { arr: {} }).arr)).toBeTruthy();
|
||||
extend(empty, optionsWithLength);
|
||||
expect(empty.foo).toEqual(optionsWithLength.foo);
|
||||
|
||||
let empty = {};
|
||||
const optionsWithLength = { "foo": { "length": -1 } };
|
||||
empty = {};
|
||||
const optionsWithDate = { foo: { date: new Date() } };
|
||||
|
||||
extend(empty, optionsWithDate);
|
||||
expect(empty.foo).toEqual(optionsWithDate.foo);
|
||||
|
||||
extend(empty, optionsWithLength);
|
||||
expect(empty["foo"]).toEqual(optionsWithLength["foo"]);
|
||||
/** @constructor */
|
||||
const MyKlass = function () {};
|
||||
// @ts-ignore
|
||||
const customObject = new MyKlass();
|
||||
const optionsWithCustomObject = { foo: { date: customObject } };
|
||||
empty = {};
|
||||
|
||||
empty = {};
|
||||
const optionsWithDate = { "foo": { "date": new Date() } };
|
||||
extend(empty, optionsWithCustomObject);
|
||||
expect(empty.foo && empty.foo.date === customObject).toBeTruthy();
|
||||
|
||||
// Makes the class a little more realistic
|
||||
MyKlass.prototype = { someMethod() {} };
|
||||
empty = {};
|
||||
|
||||
extend(empty, optionsWithDate);
|
||||
expect(empty["foo"]).toEqual(optionsWithDate["foo"]);
|
||||
extend(empty, optionsWithCustomObject);
|
||||
expect(empty.foo && empty.foo.date === customObject).toBeTruthy();
|
||||
|
||||
/** @constructor */
|
||||
const myKlass = function () { };
|
||||
// @ts-ignore
|
||||
const customObject = new myKlass();
|
||||
const optionsWithCustomObject = { "foo": { "date": customObject } };
|
||||
empty = {};
|
||||
const MyNumber = Number;
|
||||
|
||||
extend(empty, optionsWithCustomObject);
|
||||
expect(empty["foo"] && empty["foo"]["date"] === customObject).toBeTruthy();
|
||||
let ret: any = extend({ foo: 4 }, { foo: new MyNumber(5) });
|
||||
expect(parseInt(ret.foo?.toString() as string, 10) === 5).toBeTruthy();
|
||||
|
||||
// Makes the class a little more realistic
|
||||
myKlass.prototype = { "someMethod": function () { } };
|
||||
empty = {};
|
||||
let nullUndef = extend({}, options, { xnumber2: null });
|
||||
expect(nullUndef.xnumber2).toBe(null);
|
||||
|
||||
extend(empty, optionsWithCustomObject);
|
||||
expect(empty["foo"] && empty["foo"]["date"] === customObject).toBeTruthy();
|
||||
// @ts-ignore
|
||||
nullUndef = extend({}, options, { xnumber2: undefined });
|
||||
expect(nullUndef.xnumber2).toBe(options.xnumber2);
|
||||
|
||||
const MyNumber = Number;
|
||||
// @ts-ignore
|
||||
nullUndef = extend({}, options, { xnumber0: null });
|
||||
expect(nullUndef.xnumber0).toBe(null);
|
||||
|
||||
var ret: any = extend({ foo: 4 }, { foo: new MyNumber(5) });
|
||||
expect(parseInt(ret.foo?.toString() as string, 10) === 5).toBeTruthy();
|
||||
const target = {};
|
||||
const recursive = { foo: target, bar: 5 };
|
||||
|
||||
let nullUndef = extend({}, options, { xnumber2: null });
|
||||
expect(nullUndef.xnumber2).toBe(null);
|
||||
extend(target, recursive);
|
||||
expect(target).toEqual({ bar: 5 });
|
||||
|
||||
// @ts-ignore
|
||||
nullUndef = extend({}, options, { xnumber2: undefined });
|
||||
expect(nullUndef.xnumber2).toBe(options.xnumber2);
|
||||
ret = extend({ foo: [] }, { foo: [0] });
|
||||
expect(ret.foo?.length).toBe(1);
|
||||
|
||||
// @ts-ignore
|
||||
nullUndef = extend({}, options, { xnumber0: null });
|
||||
expect(nullUndef.xnumber0).toBe(null);
|
||||
ret = extend({ foo: '1,2,3' }, { foo: [1, 2, 3] });
|
||||
expect(typeof ret.foo !== 'string').toBeTruthy();
|
||||
|
||||
const target = {};
|
||||
const recursive = { foo: target, bar: 5 };
|
||||
ret = extend({ foo: 'bar' }, { foo: null });
|
||||
expect(typeof ret.foo !== 'undefined').toBeTruthy();
|
||||
|
||||
extend(target, recursive);
|
||||
expect(target).toEqual({ bar: 5 });
|
||||
const obj = { foo: null };
|
||||
extend(obj, { foo: 'notnull' });
|
||||
expect(obj.foo).toBe('notnull');
|
||||
|
||||
ret = extend({ foo: [] }, { foo: [0] });
|
||||
expect(ret.foo?.length).toBe(1);
|
||||
const func: { (): void; key?: string } = () => {};
|
||||
extend(func, { key: 'value' });
|
||||
expect(func.key).toBe('value');
|
||||
|
||||
ret = extend({ foo: "1,2,3" }, { foo: [1, 2, 3] });
|
||||
expect(typeof ret.foo !== "string").toBeTruthy();
|
||||
const defaults = { xnumber1: 5, xnumber2: 7, xstring1: 'peter', xstring2: 'pan' };
|
||||
const defaultsCopy = { xnumber1: 5, xnumber2: 7, xstring1: 'peter', xstring2: 'pan' };
|
||||
const options1 = { xnumber2: 1, xstring2: 'x' };
|
||||
const options1Copy = { xnumber2: 1, xstring2: 'x' };
|
||||
const options2 = { xstring2: 'xx', xxx: 'newstringx' };
|
||||
const options2Copy = { xstring2: 'xx', xxx: 'newstringx' };
|
||||
const merged2 = { xnumber1: 5, xnumber2: 1, xstring1: 'peter', xstring2: 'xx', xxx: 'newstringx' };
|
||||
|
||||
ret = extend({ foo: "bar" }, { foo: null });
|
||||
expect(typeof ret.foo !== "undefined").toBeTruthy();
|
||||
settings = extend({}, defaults, options1, options2);
|
||||
expect(settings).toEqual(merged2);
|
||||
expect(defaults).toEqual(defaultsCopy);
|
||||
expect(options1).toEqual(options1Copy);
|
||||
expect(options2).toEqual(options2Copy);
|
||||
|
||||
const obj = { foo: null };
|
||||
extend(obj, { foo: "notnull" });
|
||||
expect(obj.foo).toBe("notnull");
|
||||
|
||||
const func: { (): void, key?: string } = () => { };
|
||||
extend(func, { key: "value" });
|
||||
expect(func.key).toBe("value");
|
||||
|
||||
const defaults = { xnumber1: 5, xnumber2: 7, xstring1: "peter", xstring2: "pan" };
|
||||
const defaultsCopy = { xnumber1: 5, xnumber2: 7, xstring1: "peter", xstring2: "pan" };
|
||||
const options1 = { xnumber2: 1, xstring2: "x" };
|
||||
const options1Copy = { xnumber2: 1, xstring2: "x" };
|
||||
const options2 = { xstring2: "xx", xxx: "newstringx" };
|
||||
const options2Copy = { xstring2: "xx", xxx: "newstringx" };
|
||||
const merged2 = { xnumber1: 5, xnumber2: 1, xstring1: "peter", xstring2: "xx", xxx: "newstringx" };
|
||||
|
||||
settings = extend({}, defaults, options1, options2);
|
||||
expect(settings).toEqual(merged2);
|
||||
expect(defaults).toEqual(defaultsCopy);
|
||||
expect(options1).toEqual(options1Copy);
|
||||
expect(options2).toEqual(options2Copy);
|
||||
|
||||
expect(extend('', { foo: 1 })).toEqual({ foo: 1 });
|
||||
expect(extend(null, { foo: null, deep: { foo: null } })).toEqual({ foo: null, deep: { foo: null } });
|
||||
expect(extend(12, { foo: 1, deep: { foo: null, text: '' } })).toEqual({ foo: 1, deep: { foo: null, text: '' } });
|
||||
});
|
||||
});
|
||||
expect(extend('', { foo: 1 })).toEqual({ foo: 1 });
|
||||
expect(extend(null, { foo: null, deep: { foo: null } })).toEqual({ foo: null, deep: { foo: null } });
|
||||
expect(extend(12, { foo: 1, deep: { foo: null, text: '' } })).toEqual({ foo: 1, deep: { foo: null, text: '' } });
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,216 +1,229 @@
|
||||
import { type, isNumber, isString, isBoolean, isFunction, isArray, isObject, isUndefined, isNull, isArrayLike, isPlainObject, isEmptyObject, isHTMLElement } from 'core/utils/types';
|
||||
import {
|
||||
type,
|
||||
isNumber,
|
||||
isString,
|
||||
isBoolean,
|
||||
isFunction,
|
||||
isArray,
|
||||
isObject,
|
||||
isUndefined,
|
||||
isNull,
|
||||
isArrayLike,
|
||||
isPlainObject,
|
||||
isEmptyObject,
|
||||
isHTMLElement,
|
||||
} from 'core/utils/types';
|
||||
|
||||
const testfn = function () { };
|
||||
const testfnAsync = async function () { };
|
||||
const testfn = function () {};
|
||||
const testfnAsync = async function () {};
|
||||
|
||||
const typeNameValueMap = {
|
||||
null: null,
|
||||
undefined: undefined,
|
||||
void0: void 0,
|
||||
infinity: Infinity,
|
||||
number: 0,
|
||||
string: '0',
|
||||
booleanTrue: true,
|
||||
booleanFalse: false,
|
||||
function: testfn,
|
||||
functionAsync: testfnAsync,
|
||||
functionArrow: () => { },
|
||||
functionArrowAsync: async () => { },
|
||||
functionConstructor: new (testfn as any)(),
|
||||
arrayEmpty: [],
|
||||
objectEmpty: {},
|
||||
array: [1, 2, 3],
|
||||
object: { a: 1, b: 2, c: 3 },
|
||||
objectCreate: Object.create(null),
|
||||
arrayLikeObject: { 0: 0, 1: 1, 2: 2, length: 3 },
|
||||
newNumber: new Number(0),
|
||||
newString: new String('0'),
|
||||
newBoolean: new Boolean(false),
|
||||
newFunction: new Function(''),
|
||||
newArray: new Array(),
|
||||
document: document,
|
||||
window: window,
|
||||
body: document.body,
|
||||
querySelectorAll: document.querySelectorAll('*'),
|
||||
null: null,
|
||||
undefined,
|
||||
void0: void 0,
|
||||
infinity: Infinity,
|
||||
number: 0,
|
||||
string: '0',
|
||||
booleanTrue: true,
|
||||
booleanFalse: false,
|
||||
function: testfn,
|
||||
functionAsync: testfnAsync,
|
||||
functionArrow: () => {},
|
||||
functionArrowAsync: async () => {},
|
||||
functionConstructor: new (testfn as any)(),
|
||||
arrayEmpty: [],
|
||||
objectEmpty: {},
|
||||
array: [1, 2, 3],
|
||||
object: { a: 1, b: 2, c: 3 },
|
||||
objectCreate: Object.create(null),
|
||||
arrayLikeObject: { 0: 0, 1: 1, 2: 2, length: 3 },
|
||||
newNumber: new Number(0),
|
||||
newString: new String('0'),
|
||||
newBoolean: new Boolean(false),
|
||||
newFunction: new Function(''),
|
||||
newArray: [],
|
||||
document,
|
||||
window,
|
||||
body: document.body,
|
||||
querySelectorAll: document.querySelectorAll('*'),
|
||||
};
|
||||
|
||||
const testTypeFn = (typeFunc: Function, expectedTypeNameValueResultMap: any) => {
|
||||
Object.keys(typeNameValueMap).forEach(comparisonKey => {
|
||||
const comparisonValue = typeNameValueMap[comparisonKey];
|
||||
const result = typeFunc(comparisonValue);
|
||||
if (expectedTypeNameValueResultMap.hasOwnProperty(comparisonKey)) {
|
||||
const todoComparisonValue = expectedTypeNameValueResultMap[comparisonKey];
|
||||
expect(result + comparisonKey).toBe(todoComparisonValue + comparisonKey);
|
||||
}
|
||||
else {
|
||||
expect(result + comparisonKey).toBe(false + comparisonKey);
|
||||
}
|
||||
});
|
||||
Object.keys(typeNameValueMap).forEach((comparisonKey) => {
|
||||
const comparisonValue = typeNameValueMap[comparisonKey];
|
||||
const result = typeFunc(comparisonValue);
|
||||
if (expectedTypeNameValueResultMap.hasOwnProperty(comparisonKey)) {
|
||||
const todoComparisonValue = expectedTypeNameValueResultMap[comparisonKey];
|
||||
expect(result + comparisonKey).toBe(todoComparisonValue + comparisonKey);
|
||||
} else {
|
||||
expect(result + comparisonKey).toBe(false + comparisonKey);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
describe('types', () => {
|
||||
test('type', () => {
|
||||
expect(type(undefined)).toBe("undefined");
|
||||
expect(type(null)).toBe("null");
|
||||
expect(type(true)).toBe("boolean");
|
||||
expect(type(new Boolean())).toBe("boolean");
|
||||
expect(type(3)).toBe("number");
|
||||
expect(type(new Number(3))).toBe("number");
|
||||
expect(type("test")).toBe("string");
|
||||
expect(type(new String("test"))).toBe("string");
|
||||
expect(type(function () { })).toBe("function");
|
||||
expect(type([])).toBe("array");
|
||||
expect(type(new Array())).toBe("array");
|
||||
expect(type(new Date())).toBe("date");
|
||||
expect(type(new Error())).toBe("error");
|
||||
expect(type(Symbol())).toBe("symbol");
|
||||
expect(type(Object(Symbol()))).toBe("symbol");
|
||||
expect(type(/test/)).toBe("regexp");
|
||||
test('type', () => {
|
||||
expect(type(undefined)).toBe('undefined');
|
||||
expect(type(null)).toBe('null');
|
||||
expect(type(true)).toBe('boolean');
|
||||
expect(type(new Boolean())).toBe('boolean');
|
||||
expect(type(3)).toBe('number');
|
||||
expect(type(new Number(3))).toBe('number');
|
||||
expect(type('test')).toBe('string');
|
||||
expect(type(new String('test'))).toBe('string');
|
||||
expect(type(function () {})).toBe('function');
|
||||
expect(type([])).toBe('array');
|
||||
expect(type([])).toBe('array');
|
||||
expect(type(new Date())).toBe('date');
|
||||
expect(type(new Error())).toBe('error');
|
||||
expect(type(Symbol())).toBe('symbol');
|
||||
expect(type(Object(Symbol()))).toBe('symbol');
|
||||
expect(type(/test/)).toBe('regexp');
|
||||
});
|
||||
|
||||
test('isNumber', () => {
|
||||
testTypeFn(isNumber, {
|
||||
number: true,
|
||||
infinity: true,
|
||||
newNumber: false, // new Number() not a number is ok
|
||||
});
|
||||
});
|
||||
|
||||
test('isString', () => {
|
||||
testTypeFn(isString, {
|
||||
string: true,
|
||||
newString: false, // new String() not a string is ok
|
||||
});
|
||||
});
|
||||
|
||||
test('isBoolean', () => {
|
||||
testTypeFn(isBoolean, {
|
||||
booleanTrue: true,
|
||||
booleanFalse: true,
|
||||
newBoolean: false, // new Boolean() not a boolean is ok
|
||||
});
|
||||
});
|
||||
|
||||
test('isFunction', () => {
|
||||
testTypeFn(isFunction, {
|
||||
function: true,
|
||||
functionAsync: true,
|
||||
functionArrow: true,
|
||||
functionArrowAsync: true,
|
||||
newFunction: true,
|
||||
});
|
||||
});
|
||||
|
||||
test('isArray', () => {
|
||||
testTypeFn(isArray, {
|
||||
array: true,
|
||||
arrayEmpty: true,
|
||||
newArray: true,
|
||||
});
|
||||
});
|
||||
|
||||
test('isObject', () => {
|
||||
testTypeFn(isObject, {
|
||||
object: true,
|
||||
objectEmpty: true,
|
||||
objectCreate: true,
|
||||
document: true,
|
||||
window: true,
|
||||
body: true,
|
||||
querySelectorAll: true,
|
||||
functionConstructor: true,
|
||||
arrayLikeObject: true,
|
||||
|
||||
// is ok since nobody does this
|
||||
newNumber: true,
|
||||
newString: true,
|
||||
newBoolean: true,
|
||||
});
|
||||
});
|
||||
|
||||
test('isUndefined', () => {
|
||||
testTypeFn(isUndefined, {
|
||||
undefined: true,
|
||||
void0: true,
|
||||
});
|
||||
});
|
||||
|
||||
test('isNull', () => {
|
||||
testTypeFn(isNull, {
|
||||
null: true,
|
||||
});
|
||||
});
|
||||
|
||||
test('isArrayLike', () => {
|
||||
testTypeFn(isArrayLike, {
|
||||
array: true,
|
||||
arrayEmpty: true,
|
||||
arrayLikeObject: true,
|
||||
querySelectorAll: true,
|
||||
string: true,
|
||||
newString: true,
|
||||
newArray: true,
|
||||
// is ok I guess...
|
||||
window: true,
|
||||
});
|
||||
});
|
||||
|
||||
test('isPlainObject', () => {
|
||||
testTypeFn(isPlainObject, {
|
||||
object: true,
|
||||
objectEmpty: true,
|
||||
objectCreate: true,
|
||||
arrayLikeObject: true,
|
||||
});
|
||||
});
|
||||
|
||||
test('isEmptyObject', () => {
|
||||
testTypeFn(isEmptyObject, {
|
||||
objectEmpty: true,
|
||||
objectCreate: true,
|
||||
arrayEmpty: true,
|
||||
|
||||
newNumber: true,
|
||||
newBoolean: true,
|
||||
newFunction: true,
|
||||
newArray: true,
|
||||
|
||||
null: true,
|
||||
undefined: true,
|
||||
booleanTrue: true,
|
||||
booleanFalse: true,
|
||||
void0: true,
|
||||
number: true,
|
||||
infinity: true,
|
||||
functionConstructor: true,
|
||||
function: true,
|
||||
functionAsync: true,
|
||||
functionArrow: true,
|
||||
functionArrowAsync: true,
|
||||
});
|
||||
});
|
||||
|
||||
test('isHTMLElement', () => {
|
||||
const temp = window.HTMLElement;
|
||||
|
||||
testTypeFn(isHTMLElement, {
|
||||
body: true,
|
||||
});
|
||||
Array.from(document.querySelectorAll('*')).forEach((elm) => {
|
||||
expect(isHTMLElement(elm)).toBeTruthy();
|
||||
});
|
||||
|
||||
test('isNumber', () => {
|
||||
testTypeFn(isNumber, {
|
||||
number: true,
|
||||
infinity: true,
|
||||
newNumber: false // new Number() not a number is ok
|
||||
});
|
||||
delete window.HTMLElement;
|
||||
// @ts-ignore
|
||||
window.HTMLElement = null;
|
||||
|
||||
testTypeFn(isHTMLElement, {
|
||||
body: true,
|
||||
});
|
||||
Array.from(document.querySelectorAll('*')).forEach((elm) => {
|
||||
expect(isHTMLElement(elm)).toBeTruthy();
|
||||
});
|
||||
|
||||
test('isString', () => {
|
||||
testTypeFn(isString, {
|
||||
string: true,
|
||||
newString: false // new String() not a string is ok
|
||||
});
|
||||
});
|
||||
|
||||
test('isBoolean', () => {
|
||||
testTypeFn(isBoolean, {
|
||||
booleanTrue: true,
|
||||
booleanFalse: true,
|
||||
newBoolean: false // new Boolean() not a boolean is ok
|
||||
});
|
||||
});
|
||||
|
||||
test('isFunction', () => {
|
||||
testTypeFn(isFunction, {
|
||||
function: true,
|
||||
functionAsync: true,
|
||||
functionArrow: true,
|
||||
functionArrowAsync: true,
|
||||
newFunction: true
|
||||
});
|
||||
});
|
||||
|
||||
test('isArray', () => {
|
||||
testTypeFn(isArray, {
|
||||
array: true,
|
||||
arrayEmpty: true,
|
||||
newArray: true,
|
||||
});
|
||||
});
|
||||
|
||||
test('isObject', () => {
|
||||
testTypeFn(isObject, {
|
||||
object: true,
|
||||
objectEmpty: true,
|
||||
objectCreate: true,
|
||||
document: true,
|
||||
window: true,
|
||||
body: true,
|
||||
querySelectorAll: true,
|
||||
functionConstructor: true,
|
||||
arrayLikeObject: true,
|
||||
|
||||
// is ok since nobody does this
|
||||
newNumber: true,
|
||||
newString: true,
|
||||
newBoolean: true,
|
||||
});
|
||||
});
|
||||
|
||||
test('isUndefined', () => {
|
||||
testTypeFn(isUndefined, {
|
||||
undefined: true,
|
||||
void0: true,
|
||||
});
|
||||
});
|
||||
|
||||
test('isNull', () => {
|
||||
testTypeFn(isNull, {
|
||||
null: true,
|
||||
});
|
||||
});
|
||||
|
||||
test('isArrayLike', () => {
|
||||
testTypeFn(isArrayLike, {
|
||||
array: true,
|
||||
arrayEmpty: true,
|
||||
arrayLikeObject: true,
|
||||
querySelectorAll: true,
|
||||
string: true,
|
||||
newString: true,
|
||||
newArray: true,
|
||||
// is ok I guess...
|
||||
window: true,
|
||||
});
|
||||
});
|
||||
|
||||
test('isPlainObject', () => {
|
||||
testTypeFn(isPlainObject, {
|
||||
object: true,
|
||||
objectEmpty: true,
|
||||
objectCreate: true,
|
||||
arrayLikeObject: true,
|
||||
});
|
||||
});
|
||||
|
||||
test('isEmptyObject', () => {
|
||||
testTypeFn(isEmptyObject, {
|
||||
objectEmpty: true,
|
||||
objectCreate: true,
|
||||
arrayEmpty: true,
|
||||
|
||||
newNumber: true,
|
||||
newBoolean: true,
|
||||
newFunction: true,
|
||||
newArray: true,
|
||||
|
||||
null: true,
|
||||
undefined: true,
|
||||
booleanTrue: true,
|
||||
booleanFalse: true,
|
||||
void0: true,
|
||||
number: true,
|
||||
infinity: true,
|
||||
functionConstructor: true,
|
||||
function: true,
|
||||
functionAsync: true,
|
||||
functionArrow: true,
|
||||
functionArrowAsync: true,
|
||||
});
|
||||
});
|
||||
|
||||
test('isHTMLElement', () => {
|
||||
const temp = window.HTMLElement;
|
||||
|
||||
testTypeFn(isHTMLElement, {
|
||||
body: true
|
||||
});
|
||||
Array.from(document.querySelectorAll('*')).forEach((elm) => {
|
||||
expect(isHTMLElement(elm)).toBeTruthy();
|
||||
});
|
||||
|
||||
delete window.HTMLElement;
|
||||
// @ts-ignore
|
||||
window.HTMLElement = null;
|
||||
|
||||
testTypeFn(isHTMLElement, {
|
||||
body: true
|
||||
});
|
||||
Array.from(document.querySelectorAll('*')).forEach((elm) => {
|
||||
expect(isHTMLElement(elm)).toBeTruthy();
|
||||
});
|
||||
|
||||
window.HTMLElement = temp;
|
||||
});
|
||||
});
|
||||
window.HTMLElement = temp;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,26 +4,26 @@ const testElm = document.body;
|
||||
const testInstance = { value: 'value' };
|
||||
|
||||
describe('instances', () => {
|
||||
afterEach(() => {
|
||||
removeInstance(testElm);
|
||||
});
|
||||
afterEach(() => {
|
||||
removeInstance(testElm);
|
||||
});
|
||||
|
||||
test('add instance', () => {
|
||||
addInstance(testElm, testInstance);
|
||||
test('add instance', () => {
|
||||
addInstance(testElm, testInstance);
|
||||
|
||||
expect(allInstances().size).toBe(1);
|
||||
});
|
||||
expect(allInstances().size).toBe(1);
|
||||
});
|
||||
|
||||
test('remove instance', () => {
|
||||
addInstance(testElm, testInstance);
|
||||
removeInstance(testElm);
|
||||
test('remove instance', () => {
|
||||
addInstance(testElm, testInstance);
|
||||
removeInstance(testElm);
|
||||
|
||||
expect(allInstances().size).toBe(0);
|
||||
});
|
||||
expect(allInstances().size).toBe(0);
|
||||
});
|
||||
|
||||
test('get instance', () => {
|
||||
addInstance(testElm, testInstance);
|
||||
test('get instance', () => {
|
||||
addInstance(testElm, testInstance);
|
||||
|
||||
expect(getInstance(testElm)).toBe(testInstance);
|
||||
});
|
||||
});
|
||||
expect(getInstance(testElm)).toBe(testInstance);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,8 +2,8 @@ import { validate } from 'core/options';
|
||||
import { defaultOptions, optionsTemplate } from 'options';
|
||||
|
||||
describe('options', () => {
|
||||
test('default options matching the options template', () => {
|
||||
const { validated } = validate(defaultOptions, optionsTemplate);
|
||||
expect(validated).toEqual(defaultOptions);
|
||||
});
|
||||
});
|
||||
test('default options matching the options template', () => {
|
||||
const { validated } = validate(defaultOptions, optionsTemplate);
|
||||
expect(validated).toEqual(defaultOptions);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,28 +1,6 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"allowJs": false,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"esModuleInterop": true,
|
||||
"baseUrl": "./src",
|
||||
"target": "es6",
|
||||
"sourceMap": true,
|
||||
"jsx": "react",
|
||||
"lib": [
|
||||
"es6",
|
||||
"dom",
|
||||
"es2016",
|
||||
"es2017"
|
||||
],
|
||||
"declaration": true,
|
||||
"suppressImplicitAnyIndexErrors": true,
|
||||
"module": "es6",
|
||||
"moduleResolution": "node",
|
||||
"removeComments": true
|
||||
},
|
||||
"exclude": [
|
||||
"./dist",
|
||||
"**/*.test.*",
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./src/"
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
export * from 'core/dom/attributes';
|
||||
export * from 'core/dom/classes';
|
||||
export * from 'core/dom/attribute';
|
||||
export * from 'core/dom/class';
|
||||
export * from 'core/dom/create';
|
||||
export * from 'core/dom/style';
|
||||
export * from 'core/dom/manipulation';
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import { OptionsTemplate, OptionsAndOptionsTemplate } from "core/typings";
|
||||
import { OptionsTemplate, OptionsAndOptionsTemplate } from 'core/typings';
|
||||
export declare function transform<T extends Required<T>>(optionsWithOptionsTemplate: OptionsAndOptionsTemplate<T>): T;
|
||||
export declare function transform<T extends Required<T>>(optionsWithOptionsTemplate: OptionsAndOptionsTemplate<T>, toTemplate: true | void): OptionsTemplate<T>;
|
||||
|
||||
+7
-7
@@ -21,13 +21,13 @@ export declare type OptionsAndOptionsTemplate<T extends Required<T>> = {
|
||||
[P in keyof T]: PlainObject extends T[P] ? OptionsAndOptionsTemplate<Required<T[P]>> : T[P] extends OptionsTemplateNativeTypes ? OptionsAndOptionsTemplateValue<T[P]> : never;
|
||||
};
|
||||
declare type OptionsTemplateTypeMap = {
|
||||
'__TPL_boolean_TYPE__': boolean;
|
||||
'__TPL_number_TYPE__': number;
|
||||
'__TPL_string_TYPE__': string;
|
||||
'__TPL_array_TYPE__': Array<any>;
|
||||
'__TPL_function_TYPE__': Func;
|
||||
'__TPL_null_TYPE__': null;
|
||||
'__TPL_object_TYPE__': object;
|
||||
__TPL_boolean_TYPE__: boolean;
|
||||
__TPL_number_TYPE__: number;
|
||||
__TPL_string_TYPE__: string;
|
||||
__TPL_array_TYPE__: Array<any>;
|
||||
__TPL_function_TYPE__: Func;
|
||||
__TPL_null_TYPE__: null;
|
||||
__TPL_object_TYPE__: object;
|
||||
};
|
||||
declare type ExtractPropsKey<T, TProps extends T[keyof T]> = {
|
||||
[P in keyof T]: TProps extends T[P] ? P : never;
|
||||
|
||||
+2
-1
@@ -1,3 +1,4 @@
|
||||
export * from 'core/utils/arrays';
|
||||
export * from 'core/utils/array';
|
||||
export * from 'core/utils/object';
|
||||
export * from 'core/utils/extend';
|
||||
export * from 'core/utils/types';
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
export declare const hasOwnProperty: (obj: any, prop: string | number | symbol) => boolean;
|
||||
export declare const keys: (obj: any) => Array<string>;
|
||||
+2
-2
@@ -3,11 +3,11 @@ export declare const type: (obj: any) => string;
|
||||
export declare function isNumber(obj: any): obj is number;
|
||||
export declare function isString(obj: any): obj is string;
|
||||
export declare function isBoolean(obj: any): obj is boolean;
|
||||
export declare function isObject(obj: any): boolean;
|
||||
export declare function isFunction(obj: any): obj is Function;
|
||||
export declare function isFunction(obj: any): obj is (...args: Array<unknown>) => unknown;
|
||||
export declare function isUndefined(obj: any): obj is undefined;
|
||||
export declare function isNull(obj: any): obj is null;
|
||||
export declare function isArray(obj: any): obj is Array<any>;
|
||||
export declare function isObject(obj: any): boolean;
|
||||
export declare function isArrayLike<T extends PlainObject = any>(obj: any): obj is ArrayLike<T>;
|
||||
export declare function isPlainObject<T = any>(obj: any): obj is PlainObject<T>;
|
||||
export declare function isHTMLElement(obj: any): obj is HTMLElement;
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
/// <reference types="jquery" />
|
||||
declare const _default: () => (number | readonly Node[] | JQuery<HTMLElement>)[];
|
||||
declare const _default: () => (number | readonly Node[])[];
|
||||
export default _default;
|
||||
export declare const a = 1;
|
||||
|
||||
+4
-4
@@ -1,4 +1,4 @@
|
||||
import { OptionsTemplate } from "core/typings";
|
||||
import { OverlayScrollbars } from "typings";
|
||||
export declare const optionsTemplate: OptionsTemplate<Required<OverlayScrollbars.Options>>;
|
||||
export declare const defaultOptions: OverlayScrollbars.Options;
|
||||
import { OptionsTemplate } from 'core/typings';
|
||||
import { Options } from 'typings';
|
||||
export declare const optionsTemplate: OptionsTemplate<Required<Options>>;
|
||||
export declare const defaultOptions: Options;
|
||||
|
||||
+77
-291
@@ -1,295 +1,81 @@
|
||||
export declare namespace OverlayScrollbars {
|
||||
type ResizeBehavior = "none" | "both" | "horizontal" | "vertical";
|
||||
type OverflowBehavior = "hidden" | "scroll" | "visible-hidden" | "visible-scroll";
|
||||
type VisibilityBehavior = "visible" | "hidden" | "auto";
|
||||
type AutoHideBehavior = "never" | "scroll" | "leave" | "move";
|
||||
type ScrollBehavior = "always" | "ifneeded" | "never";
|
||||
type BlockBehavior = "begin" | "end" | "center" | "nearest";
|
||||
type Easing = string | null | undefined;
|
||||
type Margin = number | boolean;
|
||||
type Position = number | string;
|
||||
type Extensions = string | ReadonlyArray<string> | {
|
||||
[extensionName: string]: {};
|
||||
export declare type ResizeBehavior = 'none' | 'both' | 'horizontal' | 'vertical';
|
||||
export declare type OverflowBehavior = 'hidden' | 'scroll' | 'visible-hidden' | 'visible-scroll';
|
||||
export declare type VisibilityBehavior = 'visible' | 'hidden' | 'auto';
|
||||
export declare type AutoHideBehavior = 'never' | 'scroll' | 'leave' | 'move';
|
||||
export declare type ScrollBehavior = 'always' | 'ifneeded' | 'never';
|
||||
export declare type BasicEventCallback = (this: any) => void;
|
||||
export declare type ScrollEventCallback = (this: any, args?: UIEvent) => void;
|
||||
export declare type OverflowChangedCallback = (this: any, args?: OverflowChangedArgs) => void;
|
||||
export declare type OverflowAmountChangedCallback = (this: any, args?: OverflowAmountChangedArgs) => void;
|
||||
export declare type DirectionChangedCallback = (this: any, args?: DirectionChangedArgs) => void;
|
||||
export declare type SizeChangedCallback = (this: any, args?: SizeChangedArgs) => void;
|
||||
export declare type UpdatedCallback = (this: any, args?: UpdatedArgs) => void;
|
||||
export interface Options {
|
||||
className?: string | null;
|
||||
resize?: ResizeBehavior;
|
||||
sizeAutoCapable?: boolean;
|
||||
clipAlways?: boolean;
|
||||
normalizeRTL?: boolean;
|
||||
paddingAbsolute?: boolean;
|
||||
autoUpdate?: boolean | null;
|
||||
autoUpdateInterval?: number;
|
||||
updateOnLoad?: string | ReadonlyArray<string> | null;
|
||||
nativeScrollbarsOverlaid?: {
|
||||
showNativeScrollbars?: boolean;
|
||||
initialize?: boolean;
|
||||
};
|
||||
type BasicEventCallback = (this: OverlayScrollbars) => void;
|
||||
type ScrollEventCallback = (this: OverlayScrollbars, args?: UIEvent) => void;
|
||||
type OverflowChangedCallback = (this: OverlayScrollbars, args?: OverflowChangedArgs) => void;
|
||||
type OverflowAmountChangedCallback = (this: OverlayScrollbars, args?: OverflowAmountChangedArgs) => void;
|
||||
type DirectionChangedCallback = (this: OverlayScrollbars, args?: DirectionChangedArgs) => void;
|
||||
type SizeChangedCallback = (this: OverlayScrollbars, args?: SizeChangedArgs) => void;
|
||||
type UpdatedCallback = (this: OverlayScrollbars, args?: UpdatedArgs) => void;
|
||||
type Coordinates = {
|
||||
x?: Position;
|
||||
y?: Position;
|
||||
} | {
|
||||
l?: Position;
|
||||
t?: Position;
|
||||
} | {
|
||||
left?: Position;
|
||||
top?: Position;
|
||||
} | [Position, Position] | Position | HTMLElement | {
|
||||
el: HTMLElement;
|
||||
scroll?: ScrollBehavior | {
|
||||
x?: ScrollBehavior;
|
||||
y?: ScrollBehavior;
|
||||
} | [ScrollBehavior, ScrollBehavior];
|
||||
block?: BlockBehavior | {
|
||||
x?: BlockBehavior;
|
||||
y?: BlockBehavior;
|
||||
} | [BlockBehavior, BlockBehavior];
|
||||
margin?: Margin | {
|
||||
top?: Margin;
|
||||
right?: Margin;
|
||||
bottom?: Margin;
|
||||
left?: Margin;
|
||||
} | [Margin, Margin] | [Margin, Margin, Margin, Margin];
|
||||
overflowBehavior?: {
|
||||
x?: OverflowBehavior;
|
||||
y?: OverflowBehavior;
|
||||
};
|
||||
scrollbars?: {
|
||||
visibility?: VisibilityBehavior;
|
||||
autoHide?: AutoHideBehavior;
|
||||
autoHideDelay?: number;
|
||||
dragScrolling?: boolean;
|
||||
clickScrolling?: boolean;
|
||||
touchSupport?: boolean;
|
||||
snapHandle?: boolean;
|
||||
};
|
||||
textarea?: {
|
||||
dynWidth?: boolean;
|
||||
dynHeight?: boolean;
|
||||
inheritedAttrs?: string | ReadonlyArray<string> | null;
|
||||
};
|
||||
callbacks?: {
|
||||
onInitialized?: BasicEventCallback | null;
|
||||
onInitializationWithdrawn?: BasicEventCallback | null;
|
||||
onDestroyed?: BasicEventCallback | null;
|
||||
onScrollStart?: ScrollEventCallback | null;
|
||||
onScroll?: ScrollEventCallback | null;
|
||||
onScrollStop?: ScrollEventCallback | null;
|
||||
onOverflowChanged?: OverflowChangedCallback | null;
|
||||
onOverflowAmountChanged?: OverflowAmountChangedCallback | null;
|
||||
onDirectionChanged?: DirectionChangedCallback | null;
|
||||
onContentSizeChanged?: SizeChangedCallback | null;
|
||||
onHostSizeChanged?: SizeChangedCallback | null;
|
||||
onUpdated?: UpdatedCallback | null;
|
||||
};
|
||||
interface OverflowChangedArgs {
|
||||
x: boolean;
|
||||
y: boolean;
|
||||
xScrollable: boolean;
|
||||
yScrollable: boolean;
|
||||
clipped: boolean;
|
||||
}
|
||||
interface OverflowAmountChangedArgs {
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
interface DirectionChangedArgs {
|
||||
isRTL: number;
|
||||
dir: string;
|
||||
}
|
||||
interface SizeChangedArgs {
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
interface UpdatedArgs {
|
||||
forced: boolean;
|
||||
}
|
||||
interface Options {
|
||||
className?: string | null;
|
||||
resize?: ResizeBehavior;
|
||||
sizeAutoCapable?: boolean;
|
||||
clipAlways?: boolean;
|
||||
normalizeRTL?: boolean;
|
||||
paddingAbsolute?: boolean;
|
||||
autoUpdate?: boolean | null;
|
||||
autoUpdateInterval?: number;
|
||||
updateOnLoad?: string | ReadonlyArray<string> | null;
|
||||
nativeScrollbarsOverlaid?: {
|
||||
showNativeScrollbars?: boolean;
|
||||
initialize?: boolean;
|
||||
};
|
||||
overflowBehavior?: {
|
||||
x?: OverflowBehavior;
|
||||
y?: OverflowBehavior;
|
||||
};
|
||||
scrollbars?: {
|
||||
visibility?: VisibilityBehavior;
|
||||
autoHide?: AutoHideBehavior;
|
||||
autoHideDelay?: number;
|
||||
dragScrolling?: boolean;
|
||||
clickScrolling?: boolean;
|
||||
touchSupport?: boolean;
|
||||
snapHandle?: boolean;
|
||||
};
|
||||
textarea?: {
|
||||
dynWidth?: boolean;
|
||||
dynHeight?: boolean;
|
||||
inheritedAttrs?: string | ReadonlyArray<string> | null;
|
||||
};
|
||||
callbacks?: {
|
||||
onInitialized?: BasicEventCallback | null;
|
||||
onInitializationWithdrawn?: BasicEventCallback | null;
|
||||
onDestroyed?: BasicEventCallback | null;
|
||||
onScrollStart?: ScrollEventCallback | null;
|
||||
onScroll?: ScrollEventCallback | null;
|
||||
onScrollStop?: ScrollEventCallback | null;
|
||||
onOverflowChanged?: OverflowChangedCallback | null;
|
||||
onOverflowAmountChanged?: OverflowAmountChangedCallback | null;
|
||||
onDirectionChanged?: DirectionChangedCallback | null;
|
||||
onContentSizeChanged?: SizeChangedCallback | null;
|
||||
onHostSizeChanged?: SizeChangedCallback | null;
|
||||
onUpdated?: UpdatedCallback | null;
|
||||
};
|
||||
}
|
||||
interface ScrollInfo {
|
||||
position: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
ratio: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
max: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
handleOffset: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
handleLength: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
handleLengthRatio: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
trackLength: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
snappedHandleOffset: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
isRTL: boolean;
|
||||
isRTLNormalized: boolean;
|
||||
}
|
||||
interface Elements {
|
||||
target: HTMLElement;
|
||||
host: HTMLElement;
|
||||
padding: HTMLElement;
|
||||
viewport: HTMLElement;
|
||||
content: HTMLElement;
|
||||
scrollbarHorizontal: {
|
||||
scrollbar: HTMLElement;
|
||||
track: HTMLElement;
|
||||
handle: HTMLElement;
|
||||
};
|
||||
scrollbarVertical: {
|
||||
scrollbar: HTMLElement;
|
||||
track: HTMLElement;
|
||||
handle: HTMLElement;
|
||||
};
|
||||
scrollbarCorner: HTMLElement;
|
||||
}
|
||||
interface State {
|
||||
destroyed: boolean;
|
||||
sleeping: boolean;
|
||||
autoUpdate: boolean;
|
||||
widthAuto: boolean;
|
||||
heightAuto: boolean;
|
||||
documentMixed: boolean;
|
||||
padding: {
|
||||
t: number;
|
||||
r: number;
|
||||
b: number;
|
||||
l: number;
|
||||
};
|
||||
overflowAmount: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
hideOverflow: {
|
||||
x: boolean;
|
||||
y: boolean;
|
||||
xs: boolean;
|
||||
ys: boolean;
|
||||
};
|
||||
hasOverflow: {
|
||||
x: boolean;
|
||||
y: boolean;
|
||||
};
|
||||
contentScrollSize: {
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
viewportSize: {
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
hostSize: {
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
}
|
||||
interface Extension {
|
||||
contract(global: any): boolean;
|
||||
added(options?: {}): void;
|
||||
removed(): void;
|
||||
on(callbackName: string, callbackArgs?: UIEvent | OverflowChangedArgs | OverflowAmountChangedArgs | DirectionChangedArgs | SizeChangedArgs | UpdatedArgs): void;
|
||||
}
|
||||
interface ExtensionInfo {
|
||||
name: string;
|
||||
extensionFactory: (this: OverlayScrollbars, defaultOptions: {}, compatibility: Compatibility, framework: any) => Extension;
|
||||
defaultOptions?: {};
|
||||
}
|
||||
interface Globals {
|
||||
defaultOptions: {};
|
||||
autoUpdateLoop: boolean;
|
||||
autoUpdateRecommended: boolean;
|
||||
supportMutationObserver: boolean;
|
||||
supportResizeObserver: boolean;
|
||||
supportPassiveEvents: boolean;
|
||||
supportTransform: boolean;
|
||||
supportTransition: boolean;
|
||||
restrictedMeasuring: boolean;
|
||||
nativeScrollbarStyling: boolean;
|
||||
cssCalc: string | null;
|
||||
nativeScrollbarSize: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
nativeScrollbarIsOverlaid: {
|
||||
x: boolean;
|
||||
y: boolean;
|
||||
};
|
||||
overlayScrollbarDummySize: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
rtlScrollBehavior: {
|
||||
i: boolean;
|
||||
n: boolean;
|
||||
};
|
||||
}
|
||||
interface Compatibility {
|
||||
wW(): number;
|
||||
wH(): number;
|
||||
mO(): any;
|
||||
rO(): any;
|
||||
rAF(): (callback: (...args: any[]) => any) => number;
|
||||
cAF(): (requestID: number) => void;
|
||||
now(): number;
|
||||
stpP(event: Event): void;
|
||||
prvD(event: Event): void;
|
||||
page(event: MouseEvent): {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
mBtn(event: MouseEvent): number;
|
||||
inA<T>(item: T, array: T[]): number;
|
||||
isA(obj: any): boolean;
|
||||
type(obj: any): string;
|
||||
bind(func: (...args: any[]) => any, thisObj: any, ...args: any[]): any;
|
||||
}
|
||||
}
|
||||
interface OverlayScrollbars {
|
||||
options(): OverlayScrollbars.Options;
|
||||
options(options: OverlayScrollbars.Options): void;
|
||||
options(optionName: string): any;
|
||||
options(optionName: string, optionValue: {} | null): void;
|
||||
update(force?: boolean): void;
|
||||
sleep(): void;
|
||||
scroll(): OverlayScrollbars.ScrollInfo;
|
||||
scroll(coordinates: OverlayScrollbars.Coordinates, duration?: number, easing?: OverlayScrollbars.Easing | {
|
||||
x?: OverlayScrollbars.Easing;
|
||||
y?: OverlayScrollbars.Easing;
|
||||
} | [OverlayScrollbars.Easing, OverlayScrollbars.Easing], complete?: (...args: any[]) => any): void;
|
||||
scroll(coordinates: OverlayScrollbars.Coordinates, options: {}): void;
|
||||
scrollStop(): OverlayScrollbars;
|
||||
getElements(): OverlayScrollbars.Elements;
|
||||
getElements(elementName: string): any;
|
||||
getState(): OverlayScrollbars.State;
|
||||
getState(stateProperty: string): any;
|
||||
destroy(): void;
|
||||
ext(): {};
|
||||
ext(extensionName: string): OverlayScrollbars.Extension;
|
||||
addExt(extensionName: string, options: {}): OverlayScrollbars.Extension;
|
||||
removeExt(extensionName: string): boolean;
|
||||
export interface OverflowChangedArgs {
|
||||
x: boolean;
|
||||
y: boolean;
|
||||
xScrollable: boolean;
|
||||
yScrollable: boolean;
|
||||
clipped: boolean;
|
||||
}
|
||||
export interface OverflowAmountChangedArgs {
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
export interface DirectionChangedArgs {
|
||||
isRTL: number;
|
||||
dir: string;
|
||||
}
|
||||
export interface SizeChangedArgs {
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
export interface UpdatedArgs {
|
||||
forced: boolean;
|
||||
}
|
||||
export {};
|
||||
|
||||
Reference in New Issue
Block a user