Created
October 4, 2017 15:54
-
-
Save rationalthinker1/89c0916fecf535dc680ee48fc15c075c to your computer and use it in GitHub Desktop.
Prototypes for Node and NodeList
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
interface NodeList {first(): Node;} | |
if (!NodeList.prototype.first) { | |
NodeList.prototype.first = function (): Node { | |
if (this.length === 0) { | |
return null; | |
} | |
return this[ 0 ]; | |
}; | |
} | |
interface Node {attr(name: string, value?: string): any | Node;} | |
if (!Node.prototype.attr) { | |
Node.prototype.attr = function (name, value?): string | Node { | |
if (typeof value === 'undefined') { | |
return this.getAttribute(name); | |
} | |
this.setAttribute(name, value); | |
return this; | |
}; | |
} | |
interface NodeList {attr(name: string, value?: string): NodeList;} | |
if (!NodeList.prototype.attr) { | |
NodeList.prototype.attr = function (name, value?): NodeList { | |
this.map(function (element) { | |
element.attr(name, value); | |
}); | |
return this; | |
}; | |
} | |
interface String {humanize(): string;} | |
/* http://stackoverflow.com/questions/196972/convert-string-to-title-case-with-javascript */ | |
if (!String.prototype.humanize) { | |
String.prototype.humanize = function () { | |
return this.toLowerCase().replace(/_/g, ' ') | |
.replace(/(\w+)/g, function (match) { | |
return match.charAt(0).toUpperCase() + match.slice(1); | |
}); | |
}; | |
} | |
interface Node {addClass(className: string): Node;} | |
/* https://gistgithub.com/Maksims/5356227 */ | |
if (!Node.prototype.addClass) { | |
Node.prototype.addClass = function (string: any): Node { | |
if (!(string instanceof Array)) { | |
string = string.split(' '); | |
} | |
for (let i = 0, len = string.length; i < len; ++i) { | |
if (string[ i ] && !new RegExp('(\\s+|^)' + string[ i ] + '(\\s+|$)').test(this.className)) { | |
this.className = this.className.trim() + ' ' + string[ i ]; | |
} | |
} | |
return this; | |
}; | |
} | |
interface Node {removeClass(className: string): Node;} | |
if (!Node.prototype.removeClass) { | |
Node.prototype.removeClass = function (string: any): Node { | |
if (!(string instanceof Array)) { | |
string = string.split(' '); | |
} | |
for (let i = 0, len = string.length; i < len; ++i) { | |
this.className = this.className.replace(new RegExp('(\\s+|^)' + string[ i ] + '(\\s+|$)'), ' ').trim(); | |
} | |
return this; | |
}; | |
} | |
interface Node {toggleClass(string: string): Node;} | |
if (!Node.prototype.toggleClass) { | |
Node.prototype.toggleClass = function (string): Node { | |
if (string) { | |
if (new RegExp('(\\s+|^)' + string + '(\\s+|$)').test(this.className)) { | |
this.className = this.className.replace(new RegExp('(\\s+|^)' + string + '(\\s+|$)'), ' ').trim(); | |
} else { | |
this.className = this.className.trim() + ' ' + string; | |
} | |
} | |
return this; | |
}; | |
} | |
interface Node {hasClass(string: string): boolean;} | |
if (!Node.prototype.hasClass) { | |
Node.prototype.hasClass = function (string) { | |
return string && new RegExp('(\\s+|^)' + string + '(\\s+|$)').test(this.className); | |
}; | |
} | |
interface Node {val(value?: string)} | |
if (!Node.prototype.val) { | |
Node.prototype.val = function (value = null) { | |
if (value === null) { | |
return <string>this.value; | |
} | |
this.value = value; | |
return <Node>this; | |
}; | |
} | |
interface Node {getSelectedOption(key?: string): string;} | |
if (!Node.prototype.getSelectedOption) { | |
Node.prototype.getSelectedOption = function (key = 'text'): string { | |
if (!(this instanceof HTMLSelectElement)) { | |
return null; | |
} | |
if (this.selectedIndex == -1) { | |
return null; | |
} | |
return this.options[ this.selectedIndex ][ key ]; | |
}; | |
} | |
interface Node {setSelectedOption(value: string, key?: string): Node;} | |
if (!Node.prototype.setSelectedOption) { | |
Node.prototype.setSelectedOption = function (value: string, key: 'text' | 'value' = 'text'): Node { | |
if (!(this instanceof HTMLSelectElement)) { | |
return null; | |
} | |
for (let i = 0; i < this.options.length; i++) { | |
if (this.options[ i ][ key ] === value) { | |
this.selectedIndex = i; | |
break; | |
} | |
} | |
return this; | |
}; | |
} | |
interface Node {datum(name: string, value?: string): string | Node;} | |
if (!Node.prototype.datum) { | |
Node.prototype.datum = function (name, value = null): string | Node { | |
if (value === null) { | |
return this.dataset[ name ]; | |
} | |
this.dataset[ name ] = value; | |
return this; | |
}; | |
} | |
interface Node {css(name: string, value?: string): any | Node;} | |
if (!Node.prototype.css) { | |
Node.prototype.css = function <K extends keyof CSSStyleDeclaration>(name: K, value = null): any | Node { | |
if (value === null) { | |
return this.style[ name ]; | |
} | |
this.style[ name ] = value; | |
return this; | |
}; | |
} | |
interface Node {html(string: string): Node;} | |
if (!Node.prototype.html) { | |
Node.prototype.html = function (string: string): Node { | |
this.innerHTML = string; | |
return this; | |
}; | |
} | |
interface Node {remove(): void;} | |
if (!Node.prototype.remove) { | |
Node.prototype.remove = function () { | |
this.parent().removeChild(this); | |
}; | |
} | |
interface Node {prepend(element: Node): Node;} | |
if (!Node.prototype.prepend) { | |
Node.prototype.prepend = function (element: Node): Node { | |
this.insertBefore(element, this.firstChild); | |
return this; | |
}; | |
} | |
interface Node {append(element: Node, ...elements: Node[]): Node;} | |
if (!Node.prototype.append) { | |
Node.prototype.append = function (element: Node, ...elements: Node[]): Node { | |
this.appendChild(element); | |
elements.map((element) => this.appendChild(element)); | |
return this; | |
}; | |
} | |
interface Node {prependChild(child: Node): Node;} | |
if (!Node.prototype.prependChild) { | |
Node.prototype.prependChild = function (child: Node): Node { | |
this.insertBefore(child, this.firstChild); | |
return this; | |
}; | |
} | |
interface Node {prependHtml(elementString: string): Node;} | |
if (!Node.prototype.prependHtml) { | |
Node.prototype.prependHtml = function (elementString: string): Node { | |
const element = document.createElementFromString(elementString); | |
this.insertBefore(element, this.firstChild); | |
return this; | |
}; | |
} | |
interface Node {appendHtml(elementString: string): Node;} | |
if (!Node.prototype.appendHtml) { | |
Node.prototype.appendHtml = function (elementString): Node { | |
const element = document.createElementFromString(elementString); | |
this.appendChild(element); | |
return this; | |
}; | |
} | |
interface Node {map<K extends Node>(elements: string, fn: (element: K) => void): Node;} | |
if (!Node.prototype.map) { | |
Node.prototype.map = function <K extends Node>(elements, fn: (element: K) => void): Node { | |
this.select(elements).map(function (element, index) { | |
fn.call(element, element, index); | |
}); | |
return this; | |
}; | |
} | |
interface NodeList {toArray(): Array<Node>;} | |
if (!NodeList.prototype.toArray) { | |
NodeList.prototype.toArray = function (): Array<Node> { | |
return [ ...this ]; | |
}; | |
} | |
interface Node {select(elements: string): any;} | |
if (!Node.prototype.select) { | |
Node.prototype.select = function (elements): NodeListOf<Element> { | |
return this.querySelectorAll(elements); | |
}; | |
} | |
interface Node {selectOne<K extends keyof HTMLElementTagNameMap>(string: string): Node} | |
if (!Node.prototype.selectOne) { | |
Node.prototype.selectOne = function <K extends keyof HTMLElementTagNameMap>(string): Node { | |
let element; | |
if (string.substr(0, 1) == '#') { | |
element = this.getElementById(string.substring(1)); | |
} else { | |
element = this.querySelector(string); | |
} | |
if (element) { | |
return element; | |
} | |
return document.createElement('div'); | |
}; | |
} | |
interface Node {find(name: string): NodeListOf<Element>} | |
interface Node {findOne<K extends keyof HTMLElementTagNameMap>(elements: string): Node;} | |
if (!Node.prototype.find) { | |
Node.prototype.find = Node.prototype.select; | |
} | |
if (!Node.prototype.findOne) { | |
Node.prototype.findOne = Node.prototype.selectOne; | |
} | |
interface Document {createElementFromString(elementString: string): Node;} | |
if (!Document.prototype.createElementFromString) { | |
Document.prototype.createElementFromString = function (string) { | |
const element = new DOMParser().parseFromString(string, 'text/html'); | |
const child = element.documentElement.querySelector('body').firstChild; | |
return child as Node; | |
}; | |
} | |
/* Function to add/remove required attribute on fields */ | |
interface Node {makeRequired(makeRequired?: boolean): Node;} | |
if (!Node.prototype.makeRequired) { | |
Node.prototype.makeRequired = function (makeItRequired = true): Node { | |
if (makeItRequired) { | |
this.setAttribute('required', 'required'); | |
this.parent().addClass('required'); | |
} else { | |
this.removeAttribute('required'); | |
this.parent().removeClass('required'); | |
} | |
return this; | |
}; | |
} | |
interface NodeList {map(fn: (element: Node, index: number) => void): NodeList;} | |
if (!NodeList.prototype.map) { | |
NodeList.prototype.map = function (fn): NodeList { | |
for (let i = 0; i < this.length; i++) { | |
const element: Node = this.item(i); | |
fn.call(element, element, i); | |
} | |
return this; | |
}; | |
} | |
interface Node {parent(level?: number): Node;} | |
if (!Node.prototype.parent) { | |
Node.prototype.parent = function (level: number = 0): Node { | |
if (!this.parentNode) { | |
return document.createElement('div'); | |
} | |
let elem = this.parentNode; | |
for (let i = 0; i < level; i++) { | |
elem = elem.parentNode; | |
} | |
return elem; | |
}; | |
} | |
interface NodeList {css(key: string, value: string): NodeList;} | |
if (!NodeList.prototype.css) { | |
NodeList.prototype.css = function <K extends keyof CSSStyleDeclaration>(key: K, value): NodeList { | |
this.map((el) => { | |
el.css(key, value); | |
}); | |
return this; | |
}; | |
} | |
interface NodeList {hide(): NodeList;} | |
if (!NodeList.prototype.hide) { | |
NodeList.prototype.hide = function (): NodeList { | |
this.css('display', 'none'); | |
return this; | |
}; | |
} | |
interface NodeList {show(value: string): NodeList;} | |
if (!NodeList.prototype.show) { | |
NodeList.prototype.show = function (value = ''): NodeList { | |
this.css('display', value); | |
return this; | |
}; | |
} | |
interface Node {on(event: string, fn: Function): Node;} | |
if (!Node.prototype.on) { | |
Node.prototype.on = function (event, fn): Node { | |
window.addEventListener ? this.addEventListener(event, fn, false) : this.attachEvent('on' + event, fn); | |
return this; | |
}; | |
} | |
interface Node {trigger(eventName: string, data?: Object): Node;} | |
if (!Node.prototype.trigger) { | |
Node.prototype.trigger = function (eventName, data: Object = {}): Node { | |
let event; | |
if (window.hasOwnProperty('CustomEvent')) { | |
event = new CustomEvent(eventName, { detail: data }); | |
} else { | |
event = document.createEvent('CustomEvent'); | |
event.initCustomEvent(eventName, true, true, data); | |
} | |
this.dispatchEvent(event); | |
return this; | |
}; | |
} | |
interface NodeList {trigger(eventName: string, data?: Object): NodeList;} | |
if (!NodeList.prototype.trigger) { | |
NodeList.prototype.trigger = function (eventName, data: Object = {}): NodeList { | |
this.map(function (element: Node) { | |
element.trigger(eventName, data); | |
}); | |
return this; | |
}; | |
} | |
interface NodeList {on(event: string, fn: Function): NodeList;} | |
if (!NodeList.prototype.on) { | |
NodeList.prototype.on = function (event, fn): NodeList { | |
this.map(function (element: Node) { | |
element.on(event, fn); | |
}); | |
return this; | |
}; | |
} | |
interface Node {setText(string: string): Node;} | |
if (!Node.prototype.setText) { | |
Node.prototype.setText = function (string: string): Node { | |
this.textContent = string; | |
return this; | |
}; | |
} | |
interface Node {clearElements(hide?: boolean): Node;} | |
interface JQuery { | |
doneTyping(callback: (element: Node) => void, timeLimit?: number): JQuery; | |
clearElements(hide?: boolean): JQuery; | |
addSearchableDropdown(opt?: Object): JQuery; | |
addMultipleDropdown(): JQuery; | |
trigger2(eventName): JQuery; | |
makeRequired(makeItRequired?: boolean): JQuery; | |
select2(option?: Object, ...arg: any[]): JQuery | |
} | |
+function ($) { | |
/* Function to make sure to delete all the elements */ | |
if (!Node.prototype.clearElements) { | |
Node.prototype.clearElements = function (hide = true) { | |
this.classList.remove('displayed'); | |
[ | |
...this.querySelectorAll('input:not([type="hidden"])'), | |
...this.querySelectorAll('select') | |
].map(function (element) { | |
element.removeAttribute('disabled'); | |
element.removeAttribute('required'); | |
element.setAttribute('value', ''); | |
element.parent().classList.remove('required'); | |
element.selectedIndex = 0; | |
$(element).trigger('change.select2'); | |
}); | |
if (hide) { | |
$(this).slideUp(); | |
} | |
return this; | |
}; | |
} | |
/* Function to add/remove required attribute on fields */ | |
$.fn.makeRequired = function (makeItRequired = true) { | |
if (makeItRequired) { | |
$(this).attr('required', 'required').parent().addClass('required'); | |
} else { | |
$(this).removeAttr('required').parent().removeClass('required'); | |
} | |
return this; | |
}; | |
$.fn.clearElements = function (hide = true) { | |
const select = this.find('select'); | |
this.removeClass('displayed'); | |
this.find('input').removeAttr('disabled').removeAttr('required').val('').parent().removeClass('required'); | |
select.removeAttr('disabled').removeAttr('required').val('').parent().removeClass('required'); | |
select.val('').trigger('change.select2'); | |
if (hide) { | |
this.slideUp(); | |
} | |
return this; | |
}; | |
/* Function to make the searchable drop-down feature on element of select type */ | |
$.fn.addSearchableDropdown = function (opt = {}) { | |
const defaultOptions = { | |
containerCssClass: 'form-control', | |
formatResultCssClass: function () { | |
return 'tag label label-primary'; | |
}, | |
width: '100%', | |
}; | |
const options = Object.assign({}, defaultOptions, opt); | |
$(this).select2(options); | |
return this; | |
}; | |
/* Function to make the searchable drop-down feature on element of select type */ | |
$.fn.addMultipleDropdown = function () { | |
$(this).attr('multiple', 'multiple'); | |
$(this).find("option[value='']").remove(); | |
$(this).addSearchableDropdown(); | |
return this; | |
}; | |
/* http://stackoverflow.com/questions/21290775/jquery-el-triggerchange-doesnt-fire-native-listeners */ | |
function triggerNativeEvent(el, eventName) { | |
if (el.fireEvent) { // < IE9 | |
(el.fireEvent('on' + eventName)); | |
} else { | |
const evt = document.createEvent('Events'); | |
evt.initEvent(eventName, true, false); | |
el.dispatchEvent(evt); | |
} | |
} | |
/* http://stackoverflow.com/questions/21290775/jquery-el-triggerchange-doesnt-fire-native-listeners */ | |
$.fn.trigger2 = function (eventName) { | |
return this.each(function () { | |
const el = $(this).get(0); | |
triggerNativeEvent(el, eventName); | |
}); | |
}; | |
/** | |
* https://stackoverflow.com/questions/4220126/run-javascript-function-when-user-finishes-typing-instead-of-on-key-up | |
* $('#element').doneTyping(callback[, timeout=1000]) | |
* Fires callback when a user has finished typing. This is determined by the time elapsed | |
* since the last keystroke and timeout parameter or the blur event--whichever comes first. | |
* @callback: function to be called when even triggers | |
* @timeout: (default=1000) timeout, in ms, to to wait before triggering event if not | |
* caused by blur. | |
* Requires jQuery 1.7+ | |
*/ | |
$.fn.doneTyping = function (callback, timeout = 1e3) { | |
let timeoutReference; | |
const doneTyping = function (el) { | |
if (!timeoutReference) { | |
return; | |
} | |
timeoutReference = null; | |
callback.call(el); | |
}; | |
return this.each(function (i, el) { | |
const $el = $(el); | |
// Chrome Fix (Use keyup over keypress to detect backspace) | |
// thank you @palerdot | |
$el.is(':input') && $el.on('keyup keypress paste', function (e) { | |
// This catches the backspace button in chrome, but also prevents | |
// the event from triggering too preemptively. Without this line, | |
// using tab/shift+tab will make the focused element fire the callback. | |
if (e.type == 'keyup' && e.keyCode != 8) { | |
return; | |
} | |
// Check if timeout has been set. If it has, "reset" the clock and | |
// start over again. | |
if (timeoutReference) { | |
clearTimeout(timeoutReference); | |
} | |
timeoutReference = setTimeout(function () { | |
// if we made it here, our timeout has elapsed. Fire the | |
// callback | |
doneTyping(el); | |
}, timeout); | |
}).on('blur', function () { | |
// If we can, fire the event since we're leaving the field | |
doneTyping(el); | |
}); | |
}); | |
}; | |
}(jQuery); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment