Skip to content

Instantly share code, notes, and snippets.

@ggoodman
Created December 15, 2011 22:22
Show Gist options
  • Save ggoodman/1483200 to your computer and use it in GitHub Desktop.
Save ggoodman/1483200 to your computer and use it in GitHub Desktop.
DryKup
/* File: drykup.coffee Author: Mark Hahn DryCup is a CoffeeScript html generator compatible with CoffeeKup but without the magic. DryKup is open-sourced via the MIT license. See https://github.com/mark-hahn/drykup*/
var Drykup, attrAliases, dbg, doctypes, drykup, elements, expandAttrs, expandStyle, extendX, merge_elements, styleAliases, styleValueAliases, util, whiteSpace;
var __slice = Array.prototype.slice,
__hasProp = Object.prototype.hasOwnProperty,
__indexOf = Array.prototype.indexOf ||
function (item) {
for (var i = 0, l = this.length; i < l; i++) {
if (__hasProp.call(this, i) && this[i] === item) return i;
}
return -1;
};
doctypes = {
'default': '<!DOCTYPE html>',
'5': '<!DOCTYPE html>',
'xml': '<?xml version="1.0" encoding="utf-8" ?>',
'transitional': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
'strict': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',
'frameset': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">',
'1.1': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">',
'basic': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">',
'mobile': '<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">',
'ce': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "ce-html-1.0-transitional.dtd">'
};
elements = {
regular: 'a abbr address article aside audio b bdi bdo blockquote body button\ canvas caption cite code colgroup datalist dd del details dfn div dl dt em\ fieldset figcaption figure footer form h1 h2 h3 h4 h5 h6 head header hgroup\ html i iframe ins kbd label legend li map mark menu meter nav noscript object\ ol optgroup option output p pre progress q rp rt ruby s samp script section\ select small span strong sub summary sup table tbody td textarea tfoot\ th thead time title tr u ul video',
"void": 'area base br col command embed hr img input keygen link meta param\ source track wbr',
obsolete: 'applet acronym bgsound dir frameset noframes isindex listing\ nextid noembed plaintext rb strike xmp big blink center font marquee multicol\ nobr spacer tt',
obsolete_void: 'basefont frame'
};
merge_elements = function () {
var a, args, element, result, _i, _j, _len, _len2, _ref;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
result = [];
for (_i = 0, _len = args.length; _i < _len; _i++) {
a = args[_i];
_ref = elements[a].split(' ');
for (_j = 0, _len2 = _ref.length; _j < _len2; _j++) {
element = _ref[_j];
if (__indexOf.call(result, element) < 0) result.push(element);
}
}
return result;
};
attrAliases = {
w: 'width',
h: 'height',
s: 'src',
src: 'src',
hr: 'href',
href: 'href',
c: 'class',
db: 'data-bind',
i: 'id',
n: 'name',
v: 'value',
m: 'method',
t: 'type',
cp: 'cellpadding',
b: 'border',
cs: 'colspan',
rs: 'rowspan',
chk: 'checked',
sel: 'selected'
};
styleValueAliases = {
'm:a': 'margin:auto',
'ml:a': 'margin-left:auto',
'mt:a': 'margin-top:auto',
'mr:a': 'margin-right:auto',
'mb:a': 'margin-bottom:auto',
'c:b': 'clear:both',
'f:l': 'float:left',
'f:r': 'float:right',
'f:n': 'float:none',
'fw:b': 'font-weight:bold',
'fw:n': 'font-weight:normal',
'fs:i': 'font-style:italic',
'fs:n': 'font-style:normal',
'p:a': 'position:absolute',
'p:r': 'position:relative',
'p:f': 'position:fixed',
'd:n': 'display:none',
'd:b': 'display:block',
'd:f': 'display:fixed',
'ta:l': 'text-align:left',
'ta:c': 'text-align:center',
'ta:r': 'text-align:right',
'o:a': 'overflow:auto',
'o:h': 'overflow:hidden',
'c:a': 'cursor:auto',
'c:p': 'cursor:pointer',
'tt:u': 'text-transform:uppercase',
'tt:c': 'text-transform:capitalize',
'tt:l': 'text-transform:lowercase',
'td:n': 'text-decoration:none',
'td:u': 'text-decoration:underline',
'td:lt': 'text-decoration: line-through',
'lh:n': 'line-height:normal',
'b:n': 'border:none',
'b:1pxsb': 'border:1px solid black',
'bl:1pxsb': 'border-left:1px solid black',
'bt:1pxsb': 'border-top:1px solid black',
'br:1pxsb': 'border-right:1px solid black',
'bb:1pxsb': 'border-bottom:1px solid black',
'b:1pxsg': 'border:1px solid gray',
'bl:1pxsg': 'border-left:1px solid gray',
'bt:1pxsg': 'border-top:1px solid gray',
'br:1pxsg': 'border-right:1px solid gray',
'bb:1pxsg': 'border-bottom:1px solid gray',
'zi:a': 'z-index:auto',
'zi:i': 'z-index:inherit',
'v:v': 'visibility:visible',
'v:h': 'visibility:hidden'
};
styleAliases = {
l: 'left',
t: 'top',
r: 'right',
w: 'width',
h: 'height',
c: 'color',
bc: 'background-color',
fs: 'font-size',
lh: 'line-height',
zi: 'z-index',
b: 'border',
bl: 'border-left',
bt: 'border-top',
br: 'border-right',
bb: 'border-bottom',
m: 'margin',
ml: 'margin-left',
mt: 'margin-top',
mr: 'margin-right',
mb: 'margin-bottom',
p: 'padding',
pl: 'padding-left',
pt: 'padding-top',
pr: 'padding-right',
pb: 'padding-bottom',
v: 'visibility',
ff: 'font-family'
};
whiteSpace = function (str) {
return str.replace(/([^~])\+/g, '$1 ').replace(/~\+/g, '+');
};
expandAttrs = function (v, styleOnly) {
var aa, attrs, d, k, name, part, parts, sa, sep, style, styles, sva, thirds, v, value, _i, _len, _ref;
if (v == null) v = '';
if (styleOnly == null) styleOnly = false;
attrs = {};
styles = {};
v = v.replace(/\s+/g, '~`~');
parts = v.split('~`~');
for (_i = 0, _len = parts.length; _i < _len; _i++) {
part = parts[_i];
if (!(thirds = /^([^=:]*)(=|:)(.*)$/.exec(part))) continue;
d = thirds[0], name = thirds[1], sep = thirds[2], value = thirds[3];
if (!styleOnly && sep === '=') {
if (name === 'in') {
attrs.id = value;
attrs.name = value;
} else {
if ((aa = attrAliases[name])) name = aa;
attrs[name] = whiteSpace(value);
}
}
if (sep === ':') {
if ((sva = styleValueAliases[part])) {
_ref = sva.split(':'), name = _ref[0], value = _ref[1];
} else {
if ((sa = styleAliases[name])) name = sa;
if (name !== 'z-index' && /^-?\d+$/.test(value)) {
value = value + 'px';
} else {
value = whiteSpace(value);
}
}
styles[name] = value;
}
}
style = ((function () {
var _results;
_results = [];
for (k in styles) {
v = styles[k];
_results.push("" + k + ":" + v);
}
return _results;
})()).join('; ');
if (styleOnly) return style;
if (style) attrs['style'] = style;
return attrs;
};
expandStyle = function (v) {
var parts, pfx, s, style, x;
s = '';
while (parts = v.match(/^([^{]*)\{([^}]*)\}([\s\S]*)$/)) {
x = parts[0], pfx = parts[1], style = parts[2], v = parts[3];
s += pfx + '{' + expandAttrs(style, true) + '}';
}
return s + v;
};
extendX = function (newSpecStrs, oldSpecStrs) {
var addSpecStr, key, nameSep, newSpecStr, oldSpecStr, specsObj, val;
if (newSpecStrs == null) newSpecStrs = {};
for (key in newSpecStrs) {
newSpecStr = newSpecStrs[key];
if (!(oldSpecStr = oldSpecStrs[key])) {
oldSpecStrs[key] = newSpecStr;
continue;
}
specsObj = {};
addSpecStr = function (specStr) {
var spec, specParts, _i, _len, _ref;
_ref = specStr.replace(/\s+/g, '~`~').split('~`~');
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
spec = _ref[_i];
if (!(specParts = /^([^=:]*(=|:))(.*)$/.exec(spec))) continue;
specsObj[specParts[1]] = specParts[3];
}
return null;
};
addSpecStr(oldSpecStr);
addSpecStr(newSpecStr);
oldSpecStrs[key] = ((function () {
var _results;
_results = [];
for (nameSep in specsObj) {
val = specsObj[nameSep];
_results.push(nameSep + val);
}
return _results;
})()).join(' ');
}
return oldSpecStrs;
};
dbg = function (txt, obj) {
if (!(obj != null)) {
obj = txt;
txt = '';
}
//return util.puts('DBG ---> ' + txt + '\n' + util.inspect(obj) + '\n');
};
Drykup = (function () {
function Drykup(opts) {
var _ref, _ref2, _ref3;
if (opts == null) opts = {};
this.indent = (_ref = opts.indent) != null ? _ref : '';
this.htmlOut = (_ref2 = opts.htmlOut) != null ? _ref2 : '';
this.expand = (_ref3 = opts.expand) != null ? _ref3 : false;
}
Drykup.prototype.resetHtml = function (html) {
if (html == null) html = '';
return this.htmlOut = html;
};
Drykup.prototype.defineGlobalTagFuncs = function () {
var func, name, _results;
if (window) {
_results = [];
for (name in this) {
func = this[name];
_results.push(window[name] = func);
}
return _results;
}
};
Drykup.prototype.addText = function (s) {
if (s) {
this.htmlOut += this.indent + s + '\n';
return '';
}
};
Drykup.prototype.attrStr = function (obj) {
var attrstr, name, val;
attrstr = '';
for (name in obj) {
val = obj[name];
if (this.expand && name === 'x') {
attrstr += this.attrStr(expandAttrs(val));
} else {
attrstr += ' ' + name + '="' + val.toString().replace('"', '\\"') + '"';
}
}
return attrstr;
};
Drykup.prototype.normalTag = function (tagName, args) {
var arg, attrstr, func, innertext, _i, _len;
attrstr = '';
innertext = func = null;
for (_i = 0, _len = args.length; _i < _len; _i++) {
arg = args[_i];
switch (typeof arg) {
case 'string':
case 'number':
innertext = arg;
break;
case 'function':
func = arg;
break;
case 'object':
attrstr += this.attrStr(arg);
break;
default:
//console.log('DryKup: invalid argument, tag ' + tagName + ', ' + arg.toString());
}
}
this.htmlOut += this.indent + '<' + tagName + attrstr + '>';
if (func && tagName !== 'textarea') {
this.htmlOut += '\n';
this.indent += ' ';
this.addText(innertext);
if (typeof func === "function") func();
this.indent = this.indent.slice(0, -2);
return this.addText('</' + tagName + '>');
} else {
return this.htmlOut += innertext + '</' + tagName + '>' + '\n';
}
};
Drykup.prototype.selfClosingTag = function (tagName, args) {
var arg, attrstr, _i, _len;
attrstr = '';
for (_i = 0, _len = args.length; _i < _len; _i++) {
arg = args[_i];
if (typeof arg === 'object') {
attrstr += this.attrStr(arg);
} else {
//console.log('DryKup: invalid argument, tag ' + tagName + ', ' + arg.toString());
}
}
return this.addText('<' + tagName + attrstr + ' />' + '\n');
};
Drykup.prototype.styleFunc = function (str) {
if (typeof str !== 'string') {
//console.log('DryKup: invalid argument, tag style, ' + str.toString());
return;
}
return this.addText('<style>' + (this.expand ? expandStyle(str) : str) + '\n' + this.indent + '</style>');
};
Drykup.prototype.extendX = function (newSpecStrs, oldSpecStrs) {
var addSpecStr, key, nameSep, newSpecStr, oldSpecStr, specsObj, val;
if (newSpecStrs == null) newSpecStrs = {};
for (key in newSpecStrs) {
newSpecStr = newSpecStrs[key];
if (!(oldSpecStr = oldSpecStrs[key])) {
oldSpecStrs[key] = newSpecStr;
continue;
}
specsObj = {};
addSpecStr = function (specStr) {
var spec, specParts, _i, _len, _ref;
_ref = specStr.replace(/\s+/g, '~`~').split('~`~');
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
spec = _ref[_i];
if (!(specParts = /^([^=:]*(=|:))(.*)$/.exec(spec))) continue;
specsObj[specParts[1]] = specParts[3];
}
return null;
};
addSpecStr(oldSpecStr);
addSpecStr(newSpecStr);
oldSpecStrs[key] = ((function () {
var _results;
_results = [];
for (nameSep in specsObj) {
val = specsObj[nameSep];
_results.push(nameSep + val);
}
return _results;
})()).join(' ');
}
return oldSpecStrs;
};
return Drykup;
})();
drykup = function (opts) {
var dk, tagName, _fn, _fn2, _i, _j, _len, _len2, _ref, _ref2;
dk = new Drykup(opts);
dk.doctype = function (type) {
return dk.addText(doctypes[type]);
};
dk.text = function (s) {
return dk.addText(s);
};
dk.coffeescript = function () {
return dk.addText('coffeescript tag not implemented');
};
dk.style = function (s) {
return dk.styleFunc(s);
};
_ref = merge_elements('regular', 'obsolete');
_fn = function (tagName) {
return dk[tagName] = function () {
var args;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
return dk.normalTag(tagName, args);
};
};
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
tagName = _ref[_i];
_fn(tagName);
}
_ref2 = merge_elements('void', 'obsolete_void');
_fn2 = function (tagName) {
return dk[tagName] = function () {
var args;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
return dk.selfClosingTag(tagName, args);
};
};
for (_j = 0, _len2 = _ref2.length; _j < _len2; _j++) {
tagName = _ref2[_j];
_fn2(tagName);
}
return dk;
};
window.drykup = drykup;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment