Skip to content

Instantly share code, notes, and snippets.

@rationalthinker1
Created October 4, 2017 15:54
Show Gist options
  • Save rationalthinker1/89c0916fecf535dc680ee48fc15c075c to your computer and use it in GitHub Desktop.
Save rationalthinker1/89c0916fecf535dc680ee48fc15c075c to your computer and use it in GitHub Desktop.
Prototypes for Node and NodeList
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