123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723 |
- /*!
- Client lib for manipulating on DOM elements.
- Author: CrazyDoctor (Oleg Karataev)
- */
- class CDElement {
- constructor(el) {
- this.element = el;
- el.cdelement = this;
- try {
- this.events = Object.keys(getEventListeners(el));
- } catch(e) {
- this.events = [];
- }
- }
- static get(el) {
- if(el == null)
- return null;
- if(el instanceof CDElement)
- return el;
- if(el.cdelement)
- return el.cdelement;
- if(el instanceof Element || el instanceof Window)
- return el.cdelement = new CDElement(el);
- throw 'CDElement.get() error';
- }
- get() {
- return this.element;
- }
- copy() {
- return new CDElement(this.get().cloneNode(true));
- }
- getFirstChild(selector) {
- const children = Array.from(this.get().children);
- if (children.length == 0)
- return null;
- if (CDUtils.isEmpty(selector))
- return CDElement.get(children[0]);
- const child = this.get().querySelector(selector);
- if(child)
- return CDElement.get(child);
- return null;
- }
- hasChildren() {
- return Array.from(this.get().children).length > 0;
- }
- getChildren(selector) {
- if (CDUtils.isEmpty(selector))
- return Array.from(this.get().children).map((element) => CDElement.get(element));
- return Array.from(this.get().querySelectorAll(selector)).map((element) => CDElement.get(element));
- }
- getChildrenRecursive() {
- let children = this.getChildren();
- for(const child of children) {
- if(this.hasChildren())
- children = children.concat(child.getChildrenRecursive());
- }
- return children;
- }
- getTag() {
- return this.get().tagName.toLowerCase();
- }
- getParent() {
- return CDElement.get(this.get().parentElement);
- }
- getValue() {
- return this.get().value || this.getInnerHTML();
- }
- setValue(value) {
- this.get().value = value;
- return this;
- }
- append(element) {
- this.get().append(element.get());
- }
- prepend(element) {
- this.get().prepend(element.get());
- }
- remove() {
- this.get().remove();
- }
- disable() {
- this.removeCssProperty('display');
- this.addClass('disabled');
- return this;
- }
- enable(display) {
- this.removeClass('disabled');
- this.get().style.display = CDUtils.isEmpty(display) ? 'block' : display;
- return this;
- }
- minimizeHeight() {
- this.get().style.height = '0px';
- return this;
- }
- minimizeWidth() {
- this.get().style.width = '0px';
- return this;
- }
- expandHeight(size) {
- if (CDUtils.isEmpty(size))
- return this;
- this.get().style.height = size + 'px';
- return this;
- }
- expandWidth(size){
- if (CDUtils.isEmpty(size))
- return this;
- this.get().style.width = size + 'px';
- return this;
- }
- isMinimized(el) {
- return CDUtils.isEmpty(this.get().style.height);
- }
- isDisabled(el) {
- return CDUtils.isEmpty(this.get().style.display);
- }
- setId(id) {
- if (CDUtils.isEmpty(id))
- return this;
- this.get().id = id;
- return id;
- }
- previousSibling() {
- return CDElement.get(this.get().previousElementSibling);
- }
- nextSibling() {
- return CDElement.get(this.get().nextElementSibling);
- }
- addClass(cls) {
- if (CDUtils.isEmpty(cls))
- return this;
- cls.split(' ').forEach((c) => {
- if(c.length > 0 && !this.hasClass(c))
- this.get().classList.add(c);
- });
- return this;
- }
- getClass() {
- if (CDUtils.isEmpty(this.get().classList))
- return '';
- let classList = '';
- this.get().classList.forEach((cls) => {
- classList += cls + " ";
- });
- return classList.trim();
- }
- removeClass(cls) {
- if (CDUtils.isEmpty(cls))
- return this;
- this.get().classList.remove(cls);
- return this;
- }
- hasClass(cls) {
- if (CDUtils.isEmpty(this.get().classList))
- return false;
- let has = false;
- this.get().classList.forEach((c) => {
- if (c === cls) has = true;
- });
- return has;
- }
- removeClass(cls) {
- if (CDUtils.isEmpty(cls))
- return this;
- this.get().classList.remove(cls);
- return this;
- }
- switchClass(cls, condition) {
- if(condition != null)
- return condition ? this.addClass(cls) : this.removeClass(cls);
- return this.hasClass(cls) ? this.removeClass(cls) : this.addClass(cls);
- }
- removeCssProperty(prop) {
- if (CDUtils.isEmpty(prop))
- return this;
- this.get().style.setProperty(prop, '');
- return this;
- }
- setAttribute(attr, value) {
- this.get().setAttribute(attr, CDUtils.isEmpty(value) ? '' : value);
- return this;
- }
- getAttribute(attr) {
- return this.get().getAttribute(attr);
- }
- setInnerHTML(value) {
- this.get().innerHTML = CDUtils.isEmpty(value) ? '' : value;
- return this;
- }
- getInnerHTML() {
- return this.get().innerHTML;
- }
- getInnerWidth() {
- return this.get().innerWidth;
- }
- getInnerHeight() {
- return this.get().innerHeight;
- }
- getOffsetTop() {
- return this.get().offsetTop;
- }
- scrollTo(selector) {
- const child = this.getFirstChild(selector);
- if(child)
- this.get().scrollTop = child.getOffsetTop() - this.getOffsetTop();
- }
- scrollIntoView() {
- this.get().scrollIntoView();
- return this;
- }
- style(property, value, priority) {
- this.get().style.setProperty(property, value, priority);
- return this;
- }
- focus() {
- this.get().focus();
- return this;
- }
- blur() {
- this.get().blur();
- return this;
- }
- click() {
- this.get().click();
- return this;
- }
- on(event, callback) {
- if (CDUtils.isEmpty(event) || CDUtils.isEmpty(callback))
- return this;
- this.get().addEventListener(event, callback);
- return this;
- }
- un(event, callback) {
- if (CDUtils.isEmpty(event))
- return this;
- this.get().removeEventListener(event, callback);
- return this;
- }
- }
- class Url {
- constructor(url) {
- this.url = new URL(url || location);
- this.urlSearch = new URLSearchParams(this.url.search);
- }
- static getHash() {
- return new Url().getHash();
- }
- static setHash(hash) {
- return new Url().setHash(hash);
- }
- static setPath(path) {
- return new Url().setPath(path);
- }
- static getOrigin() {
- return new Url().getOrigin();
- }
- static goTo(url, blank) {
- window.open(url, blank ? '_blank' : '_self');
- }
- static reload() {
- location.reload();
- }
- static getPath() {
- return new Url().getPath();
- }
- static getFullPath() {
- const url = new Url().url;
- return `${url.origin}${url.pathname}`;
- }
- setPath(path) {
- this.url.pathname = path;
- return this;
- }
- getHash() {
- const hash = this.url.hash.substring(1);
- return hash.length > 0 ? hash : null;
- }
- setHash(hash) {
- this.url.hash = !hash || hash.length == 0 ? '' : `#${hash}`;
- return this;
- }
- setSearchParams(params) {
- const paramsArr = [];
- for(const key of Object.keys(params)) {
- paramsArr.push(`${key}=${params[key]}`);
- }
- this.url.search = paramsArr.join('&');
- }
- getSearchParams() {
- const params = {};
- Array.from(this.url.searchParams).forEach((pair) => {
- params[pair[0]] = pair[1];
- });
- return params;
- }
- setPath(path) {
- this.url.pathname = path;
- return this;
- }
- getPath() {
- return this.url.pathname;
- }
- getOrigin() {
- return this.url.origin;
- }
- getProtocol() {
- return this.url.protocol;
- }
- setProtocol(protocol) {
- this.url.protocol = protocol;
- return this;
- }
- toString() {
- this.url.search = this.urlSearch.toString();
- return this.url.toString();
- }
- toLocalString() {
- this.url.search = this.urlSearch.toString();
- return this.toString().substring(this.url.origin.length);
- }
- updateLocation() {
- const hashChanged = Url.getHash() !== this.getHash();
-
- history.replaceState(null, null, this.toLocalString());
- hashChanged && window.dispatchEvent(new HashChangeEvent('hashchange'));
- }
- }
- class Style {
- static apply(element, styleStr) {
- element = element instanceof CDElement ? element : CDElement.get(element);
- const propertiesMap = this.getCssPropertiesMap(styleStr);
- for(const prop of Object.keys(propertiesMap))
- element.style(prop, propertiesMap[prop].value, propertiesMap[prop].priority);
- }
- static getCssPropertiesMap(styleStr) {
- const parts = styleStr.split(';');
- const map = {};
- for(let part of parts) {
- part = part.trim();
- if(part.length == 0)
- continue;
- const propVal = part.split(':');
- const property = propVal[0].trim();
- const value = propVal[1].trim().split('!');
- map[property] = { value: value[0], priority: value.length > 1 ? value[1] : '' };
- }
- return map;
- }
- }
- class DOM {
- static Events = {
- Click: 'click',
- Load: 'load',
- KeyDown: 'keydown',
- KeyUp: 'keyup',
- KeyPress: 'keypress',
- Change: 'change',
- Cut: 'cut',
- Drop: 'drop',
- Paste: 'paste',
- Input: 'input',
- HashChange: 'hashchange',
- MouseDown: 'mousedown',
- ContextMenu: 'contextmenu',
- Blur: 'blur'
- };
- static Tags = {
- A: 'a',
- Div: 'div',
- Span: 'span',
- H1: 'h1',
- H2: 'h2',
- H3: 'h3',
- P: 'p',
- Textarea: 'textarea',
- Input: 'input',
- Table: 'table',
- Tr: 'tr',
- Th: 'th',
- Tbody: 'tbody',
- Td: 'td',
- Select: 'select',
- Option: 'option'
- };
- static Keys = {
- Enter: 'Enter',
- Escape: 'Escape',
- Control: 'Control',
- Shift: 'Shift',
- Backspace: 'Backspace',
- Meta: 'Meta'
- };
- static MouseButtons = {
- Left: 1,
- Right: 2,
- Middle: 4
- };
- static get(selector) {
- if (CDUtils.isEmpty(selector))
- throw "DOM.get() invalid selector.";
- const element = document.querySelector(selector);
- if (CDUtils.isEmpty(element))
- return null;
- return CDElement.get(element);
- }
- static getAll(selector) {
- if (CDUtils.isEmpty(selector))
- throw "DOM.getAll() invalid selector.";
- const elements = document.querySelectorAll(selector);
- if(CDUtils.isEmpty(elements))
- return [];
- return Array.from(elements).map((element) => CDElement.get(element));
- }
- static create(config, container, prepend) {
- if (CDUtils.isEmpty(config) || CDUtils.isEmpty(config.tag))
- return;
- const element = CDElement.get(document.createElement(config.tag));
- if (!CDUtils.isEmpty(config.attr)) {
- Object.keys(config.attr).forEach((name) => {
- if(config.attr[name] !== undefined)
- element.setAttribute(name, config.attr[name]);
- });
- }
- if (!CDUtils.isEmpty(config.cls)) element.addClass(config.cls);
- if (!CDUtils.isEmpty(config.id)) element.setId(config.id);
- if (!CDUtils.isEmpty(config.style)) Style.apply(element, config.style);
- if (!CDUtils.isEmpty(config.cn)) {
- config.cn.forEach((el) => {
- if (el instanceof Element) {
- element.append(CDElement.get(el));
- } else if (el instanceof CDElement) {
- element.append(el);
- } else this.create(el, element);
- });
- }
- // innerHTML appends after cn
- if (!CDUtils.isEmpty(config.innerHTML)) element.setInnerHTML(element.getInnerHTML() + config.innerHTML);
- if (!CDUtils.isEmpty(container))
- (prepend === true ? container.prepend(element) : container.append(element));
- return element;
- }
- static append(container, element) {
- if (CDUtils.isEmpty(element) || CDUtils.isEmpty(container) ||
- (!(element instanceof Element) && !(element instanceof CDElement)) ||
- (!(container instanceof Element) && !(container instanceof CDElement)))
- return;
- (container instanceof CDElement ? container.get() : container).append((element instanceof CDElement ? element.get() : element));
- }
- static setTitle(title) {
- document.title = title;
- }
- static setCookie(name, value, hours) {
- document.cookie = name + "=" + JSON.stringify(value) + "; path=/; expires=" + (new Date(Date.now() + hours * 3600000).toGMTString());
- }
- static getCookie(name) {
- const cookies = {};
- document.cookie.split(';').forEach(function(el) {
- const [key, value] = el.split('=');
- cookies[key.trim()] = value;
- });
- const cookieValue = cookies[name];
- if(CDUtils.isEmpty(cookieValue))
- return null;
- if(CDUtils.isJsonString(cookieValue))
- return JSON.parse(cookieValue);
- else
- return cookieValue;
- }
- static getCookieProperty(name, property) {
- const cookie = DOM.getCookie(name);
- if(cookie && !(cookie instanceof Object))
- throw 'DOM.getCookieProperty(): cookie value is not a JSON';
- return cookie ? cookie[property] : null;
- }
- static setCookieProperty(name, property, value, hours) {
- const cookie = DOM.getCookie(name);
- if(cookie) {
- if(!(cookie instanceof Object))
- throw 'DOM.setCookieProperty(): initial cookie value is not a JSON';
- cookie[property] = value;
- DOM.setCookie(name, cookie, hours || 24);
- } else {
- DOM.setCookie(name, { [property]: value }, hours || 24);
- }
- }
- static documentOn(event, callback) {
- if (CDUtils.isEmpty(event) || CDUtils.isEmpty(callback))
- return;
- document.addEventListener(event, callback);
- }
- static copyToClipboard(str) {
- const body = DOM.get('body');
- const input = DOM.create({ tag: DOM.Tags.Input, style: 'display: none;' }, body);
- input.setValue(str);
- input.get().select();
- input.get().setSelectionRange(0, 99999);
- navigator.clipboard.writeText(input.get().value).then(() => {
- input.remove();
- });
- }
- }
- class CDUtils {
- static isEmpty(val) {
- return val === null || val === undefined ||
- val === '' || val.length === 0;
- }
-
- static isJsonString(str) {
- try {
- JSON.parse(str);
- } catch (e) {
- return false;
- }
- return true;
- }
- static nl2br(str) {
- return str.replaceAll(/(?:\r\n|\r|\n)/g, '<br/>');
- }
- static br2nl(str) {
- return str.replaceAll(/<br\/?>/g, '\n');
- }
- static async SHA256(input) {
- return crypto.subtle.digest('SHA-256', new TextEncoder('utf8').encode(input)).then(h => {
- const hexes = [], view = new DataView(h);
- for (let i = 0; i < view.byteLength; i += 4)
- hexes.push(('00000000' + view.getUint32(i).toString(16)).slice(-8));
- return hexes.join('');
- });
- }
- /**
- * Returns string representation of <b>x</b> with leading zeros.<br/>
- * Length of the resulting string will be equal to <b>length</b> or <b>2</b> if <b>length</b> was not specified.<br/>
- * If length of the initial number is greater or equal to <b>length</b> parameter, nothing will be changed.
- * <br/><br/>
- * Examples:<br/>CDUtils.pad(5) -> "05"<br/>CDUtils.pad(21) -> "21"<br/>CDUtils.pad(21, 3) -> "021"
- * @param {number|String} x
- * @param {number} [length]
- * @return string
- */
- static pad(x, length) {
- const count = length != null && length >= 2 ? length : 2;
- const str = x.toString();
- const diff = count - str.length;
- return `${"0".repeat(diff < 0 ? 0 : diff)}${str}`;
- }
- /**
- * Returns formatted date. <br/>
- * H - hours<br/>I - minutes<br/>S - seconds<br/>s - milliseconds<br/>D - day<br/>M - month<br/>Y - year (0000)<br/>y - year (00)
- * @param {number} timestamp
- * @param {string} format
- * @return string
- */
- static dateFormat(timestamp, format) {
- const date = new Date(timestamp);
- const day = date.getDate();
- const month = date.getMonth()+1;
- const year = date.getFullYear();
- const hours = date.getHours();
- const minutes = date.getMinutes();
- const seconds = date.getSeconds();
- const mseconds = date.getMilliseconds();
- return format.replaceAll('H', CDUtils.pad(hours.toString()))
- .replaceAll('I', CDUtils.pad(minutes.toString()))
- .replaceAll('S', CDUtils.pad(seconds.toString()))
- .replaceAll('s', CDUtils.pad(mseconds.toString()))
- .replaceAll('D', CDUtils.pad(day.toString()))
- .replaceAll('M', CDUtils.pad(month.toString()))
- .replaceAll('Y', CDUtils.pad(year.toString(), 4))
- .replaceAll('y', CDUtils.pad((year % 100).toString()));
- }
- static dateFormatUTC(date, timeZoneOffsetHours, format) {
- date = date instanceof Date ? date : new Date(date);
- date.setUTCHours(date.getUTCHours() + timeZoneOffsetHours);
- var year = date.getUTCFullYear();
- var month = date.getUTCMonth() + 1;
- var day = date.getUTCDate();
- var hours = date.getUTCHours();
- var minutes = date.getUTCMinutes();
- var seconds = date.getUTCSeconds();
- return format.replaceAll('H', CDUtils.pad(hours.toString()))
- .replaceAll('I', CDUtils.pad(minutes.toString()))
- .replaceAll('S', CDUtils.pad(seconds.toString()))
- .replaceAll('D', CDUtils.pad(day.toString()))
- .replaceAll('M', CDUtils.pad(month.toString()))
- .replaceAll('Y', CDUtils.pad(year.toString(), 4))
- .replaceAll('y', CDUtils.pad((year % 100).toString())) + ` UTC${timeZoneOffsetHours > 0 ? '+' : '-'}${timeZoneOffsetHours}`;
- }
- static repeat(str, n) {
- let res = '';
- for(let i = 0; i < n; i++)
- res += str;
- return res;
- }
- static randInt(min, max) {
- const minCeiled = Math.ceil(min);
- const maxFloored = Math.floor(max);
- return Math.floor(Math.random() * (maxFloored - minCeiled) + minCeiled);
- }
- static arrayShuffle(unshuffled) {
- return unshuffled
- .map(value => ({ value, sort: Math.random() }))
- .sort((a, b) => a.sort - b.sort)
- .map(({ value }) => value);
- }
- }
- const window_ = CDElement.get(window);
|