don't extend native objects, #191

This commit is contained in:
Martin Zimmermann 2015-11-08 17:30:00 +01:00
parent 2137441958
commit 2e41c4728a
2 changed files with 127 additions and 89 deletions

View File

@ -2,101 +2,127 @@ define(function() {
"use strict"; "use strict";
window.Element.prototype.replace = function(el) { function Element(node) {
var element = DOM.htmlify(el); this.obj = node;
this.parentNode.replaceChild(element, this);
return element;
};
window.Element.prototype.prepend = function(el) { this.replace = function (el) {
var element = DOM.htmlify(el); var element = DOM.htmlify(el);
this.insertBefore(element, this.firstChild); node.parentNode.replaceChild(element.obj, node);
return element; return element;
}; };
window.Element.prototype.append = function(el) { this.prepend = function (el) {
var element = DOM.htmlify(el); var element = DOM.htmlify(el);
this.appendChild(element); node.insertBefore(element.obj, node.firstChild);
return element; return element;
}; };
window.Element.prototype.insertAfter = function(el) { this.append = function (el) {
var element = DOM.htmlify(el); var element = DOM.htmlify(el);
this.parentNode.insertBefore(element, this.nextSibling); node.appendChild(element.obj);
return element; return element;
}; };
window.Element.prototype.on = function(type, listener, prevent) { this.insertAfter = function(el) {
/* var element = DOM.htmlify(el);
Shortcut for `Element.addEventListener`, prevents default event node.parentNode.insertBefore(element.obj, node.nextSibling);
by default, set :param prevents: to `false` to change that behavior. return element;
};
/**
* Shortcut for `Element.addEventListener`, prevents default event
* by default, set :param prevents: to `false` to change that behavior.
*/ */
this.addEventListener(type, function(event) { this.on = function(type, listener, prevent) {
listener(event); node.addEventListener(type, function(event) {
if (prevent === undefined || prevent) { listener(event);
event.preventDefault(); if (prevent === undefined || prevent) {
event.preventDefault();
}
});
};
/**
* Toggle between two internal states on event :param type: e.g. to
* cycle form visibility. Callback :param a: is called on first event,
* :param b: next time.
*
* You can skip to the next state without executing the callback with
* `toggler.next()`. You can prevent a cycle when you call `toggler.wait()`
* during an event.
*/
this.toggle = function(type, a, b) {
var toggler = new Toggle(a, b);
this.on(type, function() {
toggler.next();
});
};
this.detach = function() {
// Detach an element from the DOM and return it.
node.parentNode.removeChild(this.obj);
return this;
};
this.remove = function() {
// IE quirks
node.parentNode.removeChild(this.obj);
};
this.show = function() {
node.style.display = "block";
};
this.hide = function() {
node.style.display = "none";
};
this.setText = function(text) {
node.textContent = text;
};
this.setHtml = function(html) {
node.innerHTML = html;
};
this.blur = function() { node.blur() };
this.focus = function() { node.focus() };
this.scrollIntoView = function(args) { node.scrollIntoView(args) };
this.setAttribute = function(key, value) { node.setAttribute(key, value) };
this.getAttribute = function(key) { node.getAttribute(key) };
this.classList = node.classList;
Object.defineProperties(this, {
"textContent": {
get: function() { return node.textContent; },
set: function(textContent) { node.textContent = textContent; }
},
"innerHTML": {
get: function() { return node.innerHTML; },
set: function(innerHTML) { node.innerHTML = innerHTML; }
} }
}); });
}; }
window.Element.prototype.toggle = function(type, a, b) { var Toggle = function(a, b) {
/* this.state = false;
Toggle between two internal states on event :param type: e.g. to
cycle form visibility. Callback :param a: is called on first event,
:param b: next time.
You can skip to the next state without executing the callback with this.next = function() {
`toggler.next()`. You can prevent a cycle when you call `toggler.wait()`
during an event.
*/
function Toggle(el, a, b) {
this.state = false;
this.el = el;
this.a = a;
this.b = b;
}
Toggle.prototype.next = function next() {
if (! this.state) { if (! this.state) {
this.state = true; this.state = true;
this.a(this); a(this);
} else { } else {
this.state = false; this.state = false;
this.b(this); b(this);
} }
}; };
Toggle.prototype.wait = function wait() { this.wait = function() {
this.state = ! this.state; this.state = ! this.state;
}; };
var toggler = new Toggle(this, a, b);
this.on(type, function() {
toggler.next();
});
};
window.Element.prototype.detach = function() {
/*
Detach an element from the DOM and return it.
*/
this.parentNode.removeChild(this);
return this;
};
window.Element.prototype.remove = function() {
// Mimimi, I am IE and I am so retarded, mimimi.
this.parentNode.removeChild(this);
};
window.Element.prototype.show = function() {
this.style.display = "block";
};
window.Element.prototype.hide = function() {
this.style.display = "none";
}; };
var DOM = function(query, root, single) { var DOM = function(query, root, single) {
@ -115,31 +141,43 @@ define(function() {
root = window.document; root = window.document;
} }
var elements = root.querySelectorAll(query); if (root instanceof Element) {
root = root.obj;
}
var elements = [].slice.call(root.querySelectorAll(query), 0);
if (elements.length === 0) { if (elements.length === 0) {
return null; return null;
} }
if (elements.length === 1 && single) { if (elements.length === 1 && single) {
return elements[0]; return new Element(elements[0]);
} }
return elements; // convert NodeList to Array
elements = [].slice.call(elements, 0);
return elements.map(function(el) {
return new Element(el);
});
}; };
DOM.htmlify = function(html) { DOM.htmlify = function(el) {
/* /*
Convert :param html: into an Element (if not already). Convert :param html: into an Element (if not already).
*/ */
if (html instanceof window.Element) { if (el instanceof Element) {
return html; return el;
}
if (el instanceof window.Element) {
return new Element(el);
} }
var wrapper = DOM.new("div"); var wrapper = DOM.new("div");
wrapper.innerHTML = html; wrapper.innerHTML = el;
return wrapper.firstChild; return new Element(wrapper.firstChild);
}; };
DOM.new = function(tag, content) { DOM.new = function(tag, content) {
@ -173,4 +211,4 @@ define(function() {
}; };
return DOM; return DOM;
}); });

View File

@ -3,6 +3,7 @@ define(["app/dom", "app/i18n"], function($, i18n) {
"use strict"; "use strict";
return function(el) { return function(el) {
el = $.htmlify(el);
el.setAttribute("contentEditable", true); el.setAttribute("contentEditable", true);
el.on("focus", function() { el.on("focus", function() {
@ -21,5 +22,4 @@ define(["app/dom", "app/i18n"], function($, i18n) {
return el; return el;
}; };
});
});