Skip to content

Instantly share code, notes, and snippets.

@dentmaged
Last active March 28, 2017 07:11
Show Gist options
  • Select an option

  • Save dentmaged/550c10d1f6b9b983400ed65c16bd65e1 to your computer and use it in GitHub Desktop.

Select an option

Save dentmaged/550c10d1f6b9b983400ed65c16bd65e1 to your computer and use it in GitHub Desktop.
Vertigo - a Javascript library that allows for rapid web development.
jQuery.fn.outerHTML = function(s) {
return s ? this.before(s).remove() : jQuery("<p>").append(this.eq(0).clone()).html();
};
jQuery.fn.extend({
getPath: function () {
var path, node = this;
while (node.length) {
var realNode = node[0], name = realNode.localName;
if (!name) break;
name = name.toLowerCase();
var parent = node.parent();
var sameTagSiblings = parent.children(name);
if (sameTagSiblings.length > 1) {
allSiblings = parent.children();
var index = allSiblings.index(realNode) + 1;
if (index > 1) {
name += ':nth-child(' + index + ')';
}
}
path = name + (path ? '>' + path : '');
node = parent;
}
return path;
}
});
String.prototype.replaceAll = function(search, replacement) {
var target = this;
return target.replace(new RegExp(search, 'g'), replacement);
};
function nano(template, data) {
return template.replace(/\{\{([^\}]*)\}\}/g, function(str, key) {
var keys = key.split('.'), val = data, k;
while (key = keys.shift()) {
key = key.split('[');
val = val[key.shift()];
while (k = key.shift()) {
val = val[k.slice(0, -1)];
}
}
return ("undefined" !== typeof val && val !== null) ? val : "";
});
}
function getFromObject(obj, prop) {
if (typeof obj === 'undefined') {
return false;
}
var _index = prop.indexOf('.');
var _indexBracket = prop.indexOf('[');
if (_indexBracket > -1 && _index == -1) {
return obj[prop.substring(0, _indexBracket)][prop.substring(_indexBracket + 1, prop.length - 1)];
} else if (_indexBracket > -1 && _index > -1) {
return getFromObject(obj[prop.substring(0, _indexBracket)][prop.substring(_indexBracket + 1, _index - 1)], prop.substring(_index + 1));
}
if (_index > -1) {
return getFromObject(obj[prop.substring(0, _index)], prop.substr(_index + 1));
}
return obj[prop];
}
function setFromObject(obj, prop, val) {
if (typeof obj === 'undefined') {
return false;
}
var _index = prop.indexOf('.');
var _indexBracket = prop.indexOf('[');
if (_indexBracket > -1 && _index == -1) {
obj[prop.substring(0, _indexBracket)][prop.substring(_indexBracket + 1, prop.length - 1)] = val;
return;
} else if (_indexBracket > -1 && _index > -1) {
setFromObject(obj[prop.substring(0, _indexBracket)][prop.substring(_indexBracket + 1, _index - 1)], prop.substring(_index + 1), val);
return;
}
if (_index > -1) {
setFromObject(obj[prop.substring(0, _index)], prop.substr(_index + 1), val);
}
obj[prop] = val;
}
function Vertigo(options) {
this.el = $(options.el) || $('#app');
this.originalHtml = "<html>" + $("html").html() + "</html>";
this.$vrbinds = {};
this.$textReplacements = {};
this.$listeners = {};
this.$data = options.data;
this.$methods = options.methods;
var self = this;
this.completeDocument = function() {
self.el.find("*").each(function(index) {
var $this = $(this);
$.each(this.attributes, function() {
if (this.specified) {
var attributeSelf = this;
var directiveName = this.name.toLowerCase().replace('vr-', '');
var this_path = $this.getPath();
if (typeof Vertigo.directives[directiveName] != 'undefined') {
Vertigo.directiveStore[directiveName][this_path] = { html: $this.html(), name: attributeSelf.name, value: attributeSelf.value, elementTag: $this.outerHTML().replace($this.html(), ''), outerHTML: $this.outerHTML(), before: $this.prevAll().length };
Vertigo.directiveStore[directiveName][this_path].action = Vertigo.directives[directiveName](self, $this, this.value, self.$data);
}
if (this.name.toLowerCase().startsWith("vr-bind:")) {
self.$vrbinds[this_path] = { name: attributeSelf.name, value: attributeSelf.value };
$this.attr(this.name.split(":")[1], getFromObject(self.$data, this.value));
$this.removeAttr(this.name);
}
if (this.name.toLowerCase().startsWith("vr-on:")) {
if (typeof self.$listeners[this_path] == 'undefined') {
self.$listeners[this_path] = [];
}
self.$listeners[this_path].push(this.name.split(":")[1]);
var oneself = this;
$this.on(this.name.split(":")[1], function(event) {
with (self.$methods) {
if (!eval(oneself.value)) {
event.preventDefault();
}
}
});
}
}
});
var shouldIgnore = false;
for (var i in Vertigo.ignoreByTextReplacement) {
var ignore = Vertigo.ignoreByTextReplacement[i];
if (typeof $this.attr('vr-' + ignore) != 'undefined' || typeof $this.parent().attr('vr-' + ignore) != 'undefined') {
shouldIgnore = true;
}
}
if (!shouldIgnore) {
var originalPageHtml = $this.html();
$this.html(nano($this.html(), self.$data));
self.$textReplacements[$this.getPath()] = { original: originalPageHtml, now: $this.html() };
}
});
}
this.set = function(prop, value) {
setFromObject(self.$data, prop, value);
self.reset();
}
this.get = function(prop) {
return getFromObject(self.$data, prop);
}
this.reset = function() {
for (var addition in Vertigo.additions) {
var xpath = Vertigo.additions[addition];
if (xpath.endsWith(")")) {
var tmpX = xpath.substring(0, xpath.length - 1).split("(");
xpath = tmpX[0] + "(" + (parseInt(tmpX[1] - 1) - (addition)) + ")";
}
$(xpath).remove();
}
for (var path in self.$listeners) {
for (var listener in self.$listeners[path]) {
$(path).off(self.$listeners[path][listener]);
}
}
for (var directive in Vertigo.directiveStore) {
for (var _path in Vertigo.directiveStore[directive]) {
var path = Vertigo.directiveStore[directive][_path];
if (path.action == 'remove') {
var tmpY = _path.split(">");
tmpY.pop();
$(tmpY.join(">") + ">*:nth-child(" + path.before + ")").after(path.outerHTML);
} else if (path.action.startsWith("listener")) {
var arr = path.action.split(" ");
if (arr.length == 1) {
console.warn(directive + " has an invalid action.");
return;
}
for (var i = 1; i < arr.length; i++) {
$(_path).off(arr[i].replaceAll('_', ' '));
}
} else {
$(_path).outerHTML(path.outerHTML);
}
}
}
for (var _path in self.$vrbinds) {
var path = self.$vrbinds[_path];
var replaced = path.name.split(":")[1];
$(_path).removeAttr(replaced);
$(_path).attr(path.name, path.value);
}
for (var _path in self.$textReplacements) {
var path = self.$textReplacements[_path];
$(_path).html(path.original);
}
Vertigo.additions = [];
self.$vrbinds = {};
self.$textReplacements = {};
self.$listeners = {};
self.completeDocument();
}
this.completeDocument();
}
Vertigo.directives = {};
Vertigo.directiveStore = {};
Vertigo.ignoreByTextReplacement = [];
Vertigo.additions = [];
Vertigo.registerDirective = function(name, callback, ignoreByTextReplacement) {
Vertigo.directives[name.toLowerCase()] = callback;
Vertigo.directiveStore[name] = {};
if (ignoreByTextReplacement) {
Vertigo.ignoreByTextReplacement.push(name);
}
};
Vertigo.registerDirective('if', function(app, element, value, data) {
with (data) {
if (!eval(value)) {
element.remove();
return 'remove';
}
}
return 'keep';
}, false);
Vertigo.registerDirective('for', function(app, element, value, data) {
var name = value.split("in")[0].trim();
var list = value.split("in")[1].trim();
var arr = getFromObject(data, list);
var originalHtml = element.outerHTML(), html;
for (var i = 0; i < arr.length; i++) {
html = originalHtml.replaceAll(name, list + '[' + i + ']');
html = nano(html, data);
var inserted = element.before(html);
Vertigo.additions.push(inserted.getPath());
}
element.remove();
return 'remove';
}, true);
Vertigo.registerDirective('model', function(app, element, value, data) {
if (element.is('input')) {
var contents;
element.val(contents = app.get(value));
element.on('keyup', function(event) {
if (contents != element.val()) {
contents = element.val();
app.set(value, element.val());
}
});
}
return 'listener keyup';
}, false);
function nano(e,t){return e.replace(/\{\{([^\}]*)\}\}/g,function(e,i){for(var r,n=i.split("."),s=t;i=n.shift();)for(i=i.split("["),s=s[i.shift()];r=i.shift();)s=s[r.slice(0,-1)];return"undefined"!=typeof s&&null!==s?s:""})}function getFromObject(e,t){if("undefined"==typeof e)return!1;var i=t.indexOf("."),r=t.indexOf("[");return r>-1&&-1==i?e[t.substring(0,r)][t.substring(r+1,t.length-1)]:r>-1&&i>-1?getFromObject(e[t.substring(0,r)][t.substring(r+1,i-1)],t.substring(i+1)):i>-1?getFromObject(e[t.substring(0,i)],t.substr(i+1)):e[t]}function setFromObject(e,t,i){if("undefined"==typeof e)return!1;var r=t.indexOf("."),n=t.indexOf("[");return n>-1&&-1==r?void(e[t.substring(0,n)][t.substring(n+1,t.length-1)]=i):n>-1&&r>-1?void setFromObject(e[t.substring(0,n)][t.substring(n+1,r-1)],t.substring(r+1),i):(r>-1&&setFromObject(e[t.substring(0,r)],t.substr(r+1),i),void(e[t]=i))}function Vertigo(options){this.el=$(options.el)||$("#app"),this.originalHtml="<html>"+$("html").html()+"</html>",this.$vrbinds={},this.$textReplacements={},this.$listeners={},this.$data=options.data,this.$methods=options.methods;var self=this;this.completeDocument=function(){self.el.find("*").each(function(index){var $this=$(this);$.each(this.attributes,function(){if(this.specified){var attributeSelf=this,directiveName=this.name.toLowerCase().replace("vr-",""),this_path=$this.getPath();if("undefined"!=typeof Vertigo.directives[directiveName]&&(Vertigo.directiveStore[directiveName][this_path]={html:$this.html(),name:attributeSelf.name,value:attributeSelf.value,elementTag:$this.outerHTML().replace($this.html(),""),outerHTML:$this.outerHTML(),before:$this.prevAll().length},Vertigo.directiveStore[directiveName][this_path].action=Vertigo.directives[directiveName](self,$this,this.value,self.$data)),this.name.toLowerCase().startsWith("vr-bind:")&&(self.$vrbinds[this_path]={name:attributeSelf.name,value:attributeSelf.value},$this.attr(this.name.split(":")[1],getFromObject(self.$data,this.value)),$this.removeAttr(this.name)),this.name.toLowerCase().startsWith("vr-on:")){"undefined"==typeof self.$listeners[this_path]&&(self.$listeners[this_path]=[]),self.$listeners[this_path].push(this.name.split(":")[1]);var oneself=this;$this.on(this.name.split(":")[1],function(event){with(self.$methods)eval(oneself.value)||event.preventDefault()})}}});var shouldIgnore=!1;for(var i in Vertigo.ignoreByTextReplacement){var ignore=Vertigo.ignoreByTextReplacement[i];("undefined"!=typeof $this.attr("vr-"+ignore)||"undefined"!=typeof $this.parent().attr("vr-"+ignore))&&(shouldIgnore=!0)}if(!shouldIgnore){var originalPageHtml=$this.html();$this.html(nano($this.html(),self.$data)),self.$textReplacements[$this.getPath()]={original:originalPageHtml,now:$this.html()}}})},this.set=function(e,t){setFromObject(self.$data,e,t),self.reset()},this.get=function(e){return getFromObject(self.$data,e)},this.reset=function(){for(var e in Vertigo.additions){var t=Vertigo.additions[e];if(t.endsWith(")")){var i=t.substring(0,t.length-1).split("(");t=i[0]+"("+(parseInt(i[1]-1)-e)+")"}$(t).remove()}for(var r in self.$listeners)for(var n in self.$listeners[r])$(r).off(self.$listeners[r][n]);for(var s in Vertigo.directiveStore)for(var o in Vertigo.directiveStore[s]){var r=Vertigo.directiveStore[s][o];if("remove"==r.action){var a=o.split(">");a.pop(),$(a.join(">")+">*:nth-child("+r.before+")").after(r.outerHTML)}else if(r.action.startsWith("listener")){var l=r.action.split(" ");if(1==l.length)return void console.warn(s+" has an invalid action.");for(var f=1;f<l.length;f++)$(o).off(l[f].replaceAll("_"," "))}else $(o).outerHTML(r.outerHTML)}for(var o in self.$vrbinds){var r=self.$vrbinds[o],h=r.name.split(":")[1];$(o).removeAttr(h),$(o).attr(r.name,r.value)}for(var o in self.$textReplacements){var r=self.$textReplacements[o];$(o).html(r.original)}Vertigo.additions=[],self.$vrbinds={},self.$textReplacements={},self.$listeners={},self.completeDocument()},this.completeDocument()}jQuery.fn.outerHTML=function(e){return e?this.before(e).remove():jQuery("<p>").append(this.eq(0).clone()).html()},jQuery.fn.extend({getPath:function(){for(var e,t=this;t.length;){var i=t[0],r=i.localName;if(!r)break;r=r.toLowerCase();var n=t.parent(),s=n.children(r);if(s.length>1){allSiblings=n.children();var o=allSiblings.index(i)+1;o>1&&(r+=":nth-child("+o+")")}e=r+(e?">"+e:""),t=n}return e}}),String.prototype.replaceAll=function(e,t){var i=this;return i.replace(new RegExp(e,"g"),t)},Vertigo.directives={},Vertigo.directiveStore={},Vertigo.ignoreByTextReplacement=[],Vertigo.additions=[],Vertigo.registerDirective=function(e,t,i){Vertigo.directives[e.toLowerCase()]=t,Vertigo.directiveStore[e]={},i&&Vertigo.ignoreByTextReplacement.push(e)},Vertigo.registerDirective("if",function(app,element,value,data){with(data)if(!eval(value))return element.remove(),"remove";return"keep"},!1),Vertigo.registerDirective("for",function(e,t,i,r){for(var n,s=i.split("in")[0].trim(),o=i.split("in")[1].trim(),a=getFromObject(r,o),l=t.outerHTML(),f=0;f<a.length;f++){n=l.replaceAll(s,o+"["+f+"]"),n=nano(n,r);var h=t.before(n);Vertigo.additions.push(h.getPath())}return t.remove(),"remove"},!0),Vertigo.registerDirective("model",function(e,t,i,r){if(t.is("input")){var n;t.val(n=e.get(i)),t.on("keyup",function(r){n!=t.val()&&(n=t.val(),e.set(i,t.val()))})}return"listener keyup"},!1);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment