diff --git a/.gitignore b/.gitignore index da7f48c..b72d4a9 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,4 @@ jspm_packages .node_repl_history .DS_Store +.*.swp diff --git a/dist/no.min.js b/dist/no.min.js index 90b7737..641c854 100644 --- a/dist/no.min.js +++ b/dist/no.min.js @@ -1 +1 @@ -!function(){function e(e){this.js(e)}e.prototype.js=function(e){e=e||"html";var t=this,r=!1;document.querySelector(e).querySelectorAll("[no-js]").forEach(function(e){Object.keys(e.attributes).forEach(function(n){var o=e.attributes[n];if(0===o.name.indexOf("on--")){var a=!0;console.warn('Deprecation warning: using double dashes "--" are deprecated. Use a single dash "-" instead.')}else{if(0!==o.name.indexOf("on-"))return;var a=!1}var p=o.name.split(a?"--":"-"),i=o.value.split(" "),s=p[1],u=p[2],c=p[3];if(p.length>3&&"self"===p[p.length-1]){var l=e;r=!0}else{r=!1;var l=i[0]}var y,v=c;if("reset"!==u){var d=t._getPropertyValueIndex(c,r);y=i.slice(d).join(" "),"attribute"===c&&(v=i[d-1])}var f={action:u,target:l,sourceElement:e,propertyOrEventType:c,propertyValue:y,propertyName:v};e.addEventListener(s,function(e){t._handler(f)})})})},e.prototype._handler=function(e){var t="string"==typeof e.target?document.querySelectorAll(e.target):[e.target];t.forEach(function(t){return"trigger"===e.action&&"function"==typeof t[e.propertyOrEventType]?void t[e.propertyOrEventType]():void("class"===e.propertyOrEventType?"set"===e.action?t.className=e.propertyValue:"switch"==e.action?(t.classList.remove(e.propertyValue),e.sourceElement.classList.add(e.propertyValue)):t.classList[e.action](e.propertyValue):"attribute"===e.propertyOrEventType||"id"===e.propertyOrEventType?"remove"===e.action?t.removeAttribute(e.propertyName):"add"!==e.action&&"set"!=e.action||t.setAttribute(e.propertyName,e.propertyValue):"dom"===e.propertyOrEventType&&"remove"===e.action?t.remove():"value"===e.propertyOrEventType?"set"===e.action?t.value=e.propertyValue:"reset"===e.action&&(t.value=null):"text"===e.propertyOrEventType&&"set"===e.action&&(t.innerText=e.propertyValue))})},e.prototype._getPropertyValueIndex=function(e,t){var r="attribute"===e?2:1;return t?r-1:r},document.addEventListener("DOMContentLoaded",function(){window.no=new e})}(); \ No newline at end of file +"use strict";!function(){function e(e){this.targetTypes={},this.templates={}}function t(e){var t=e.toLowerCase();no.targetTypes[t]={},no.targetTypes[t].process=function(e,t){("trigger"!==e.actionType||t.length>0)&&(e.invalid=!0)},no.targetTypes[t].apply=function(t,n,a){a[e]()}}e.prototype.splitParams=function(e){if(null==e)return null;for(var t=[],n="",a=!1,o=!1,i=!1,s=!1,r=!0,l=0;l0){var s=e.timeout.count;i=function(t){s-- >0?(o(t),setTimeout(i,e.timeout.time)):s=e.timeout.count}}else i=function(t){setInterval(function(){o(t)},e.timeout.time)};"immediately"===e.eventType?setTimeout(function(){i(null)}):n.addEventListener(e.eventType,i)}},e.prototype.templateArgs=function(e,t){for(var n=0;n=2?(e.attributeName=t.shift(),e.attributeValue=t.join(" ")):e.invalid=!0:"remove"===e.actionType&&1===t.length?e.attributeName=t.shift():e.invalid=!0},no.targetTypes.attribute.apply=function(e,t,n){"remove"===t.actionType?n.removeAttribute(t.attributeName):n.setAttribute(t.attributeName,t.attributeValue)},no.targetTypes.class={},no.targetTypes.class.process=function(e,t){"add"===e.actionType||"set"===e.actionType||"remove"===e.actionType||"toggle"===e.actionType||"switch"===e.actionType?e.classNames=t:e.invalid=!0},no.targetTypes.class.apply=function(e,t,n){"set"===t.actionType?n.className=t.classNames.join(" "):"switch"===t.actionType?t.classNames.forEach(function(e){n.classList.remove(e),t.sourceElement.classList.add(e)}):t.classNames.forEach(function(e){n.classList[t.actionType](e)})},no.targetTypes.id={},no.targetTypes.id.process=function(e,t){e.targetType="attribute",t.unshift("id"),no.targetTypes.attribute.process(e,t)},no.targetTypes.dom={},no.targetTypes.dom.process=function(e,t){"remove"!==e.actionType&&0!=t.length&&e.invalid},no.targetTypes.dom.apply=function(e,t,n){"remove"===t.actionType&&n.remove()},no.targetTypes.value={},no.targetTypes.value.process=function(e,t){"set"===e.actionType?e.value=t.join(" "):"reset"===e.actionType&&0===t.length||(e.invalid=!0)},no.targetTypes.value.apply=function(e,t,n){"set"===t.actionType?n.value=t.value:"reset"===t.actionType&&(n.value=null)},no.targetTypes.text={},no.targetTypes.text.process=function(e,t){"set"===e.actionType?e.text=t.join(" "):"copy"===e.actionType?e.source=t.shift():e.invalid=!0},no.targetTypes.text.apply=function(e,t,n){"set"===t.actionType?n.innerText=t.text:"copy"===t.actionType&&(n.innerText=document.querySelector(t.source).innerText)},no.targetTypes.html={},no.targetTypes.html.process=function(e,t){"set"===e.actionType?e.html=t.join(" "):"copy"===e.actionType?e.source=t.shift():e.invalid=!0},no.targetTypes.html.apply=function(e,t,n){"set"===t.actionType?n.innerHTML=t.html:"copy"===t.actionType&&(n.innerHTML=document.querySelector(t.source).innerHTML)},t("click"),t("focus"),t("blur"),t("scrollIntoView"),no.targetTypes.template={},no.targetTypes.template.process=function(e,t){"apply"===e.actionType?(e.template=e.target,e.target=e.sourceElement,e.isSelf=!0,e.args=t):e.invalid=!0},no.targetTypes.template.apply=function(e,t,n){for(var a=no.templates[t.template],o=0;o 3 && signatureParts[signatureParts.length -1] === 'self') { - var target = el; - isSelf = true; - } else { - isSelf = false; - var target = paramValues[0]; + return ret; + }; + + NoJS.prototype.processTrigger = function(keys, vals) { + var trigger = {}; + trigger.eventType = keys.shift(); + trigger.invalid = false; + if(keys[0] === "timeout") { + keys.shift(); + trigger.timeout = {}; + trigger.timeout.time = parseInt(vals.shift()); + trigger.timeout.count = parseInt(vals.shift()); + if(isNaN(trigger.timeout.time) || isNaN(trigger.timeout.count)) { + trigger.invalid = true; + } + } else { trigger.timeout = null; } + return trigger; + }; + + NoJS.prototype.processAction = function(keys, vals, elt) { + var action = {}; + action.actionType = keys.shift(); + action.targetType = keys.shift().toLowerCase(); + action.sourceElement = elt; + action.isSelf = keys[keys.length - 1] === "self"; + + if(action.isSelf) { action.target = elt; } + else { action.target = vals.shift(); } + + action.invalid = false; + + var targetType = this.targetTypes[action.targetType]; + if(action.actionType == null || action.targetType == null + || targetType == null || action.target == null) { + action.invalid = true; + } else { + targetType.process(action, vals); + } + + return action; + }; + + NoJS.prototype.processListener = function(trig, act, elt) { + var targetType = this.targetTypes[act.targetType]; + if(targetType != null) { + var apply = function(evt) { + if(act.isSelf) { targetType.apply(evt, act, act.target); } + else { + var tgts = document.querySelectorAll(act.target); + tgts.forEach(function (target) { + targetType.apply(evt, act, target); + }); } + }; + var listener = null; - var propertyName = propertyOrEventType; - var propertyValue; - if (action !== 'reset') { - var index = this_._getPropertyValueIndex(propertyOrEventType, isSelf); - // join space containing values that might have been split. - propertyValue = paramValues.slice(index).join(' '); - if (propertyOrEventType === 'attribute') { - propertyName = paramValues[index - 1]; + if(trig.timeout == null) { listener = apply; } + else if(trig.timeout.count > 0) { + var countDown = trig.timeout.count; + listener = function(evnt) { + if(countDown-- > 0) { + apply(evnt); + setTimeout(listener, trig.timeout.time); } + else { + countDown = trig.timeout.count; + } + }; + } else { + listener = function(evnt) { + setInterval(function() { apply(evnt); }, trig.timeout.time); } + } - var options = { - action: action, - target: target, - sourceElement: el, - propertyOrEventType: propertyOrEventType, - propertyValue: propertyValue, - propertyName: propertyName - } + if(trig.eventType === "immediately") { + // apply it after all the listeners are installed. + setTimeout(function() { listener(null) }); + } else { + elt.addEventListener(trig.eventType, listener); + } + } + }; - el.addEventListener(eventType, function(e) { - this_._handler(options); - }) - }) - }) + NoJS.prototype.templateArgs = function(vals, args) { + for(var j = 0; j < vals.length; j++) { + for(var k = 0; k < args.length; k++) { + var re = new RegExp("\\$" + k, "g"); + vals[j] = vals[j].replace(re, args[k]); + } + } } - NoJS.prototype._handler = function (options) { - var targets = typeof options.target === "string" ? document.querySelectorAll(options.target) : [options.target]; - targets.forEach(function(el) { - if (options.action === 'trigger' && typeof el[options.propertyOrEventType] === 'function') { - el[options.propertyOrEventType](); + NoJS.prototype.processTemplate = function(elt, argStr) { + var args = this.splitParams(argStr); + if(args === "invalid") { + console.warn("invalid no-js template no-js=\"" + argStr + "\""); + } + + var template = this.templates[args.shift()]; + + if(template == null || template.argc !== args.length) { + console.warn("invalid no-js template no-js=\"" + argStr + "\""); + } + + for(var i = 0; i < template.copyActions.length; i++) { + var keys = template.copyActions[i].keyStr.split("-"); + keys.shift(); + var vals = this.splitParams(template.copyActions[i].valStr); + + this.templateArgs(vals, args); + + var trigger = this.processTrigger(keys, vals); + var action = this.processAction(keys, vals, elt); + + if(action.invalid || trigger.invalid) { + console.warn("invalid no-js template no-js=\"" + argStr + "\""); + } else { + this.processListener(trigger, action, elt); + } + } + }; + + NoJS.prototype.processElement = function(elt) { + // returns a list of actions to be added to the element. + var this_ = this; + Object.keys(elt.attributes).forEach(function(prop) { + var attr = elt.attributes[prop]; + + // to enable support for single and double dashes. + // note the order of condition checking is important. + var doubleDash = false; + if(attr.name === "no-js" && attr.value != null && attr.value !== "") { + this_.processTemplate(elt, attr.value); + return; + } + else if (attr.name.indexOf('on--') === 0) { + doubleDash = true; + console.warn('Deprecation warning: using double dashes "--" are deprecated. Use a single dash "-" instead.') + } else if (attr.name.indexOf('on-') !== 0) { + // This is a regular HTML attribute, no action required. return; } - if (options.propertyOrEventType === 'class') { - if (options.action === 'set') { - el.className = options.propertyValue; - } else if (options.action == 'switch') { - // @todo add and remove based on the class presence - // during time of action - el.classList.remove(options.propertyValue); - options.sourceElement.classList.add(options.propertyValue); - } else { - el.classList[options.action](options.propertyValue); - } + var signatureParts = attr.name.split(doubleDash ? '--' : '-'); + signatureParts.shift(); + var paramValues = this_.splitParams(attr.value); + + if(paramValues === "invalid") { + console.warn("invalid no-js parameter " + attr.name + "=\"" + + attr.value + "\""); } - else if (options.propertyOrEventType === 'attribute' || options.propertyOrEventType === 'id') { - if (options.action === 'remove') { - el.removeAttribute(options.propertyName); - } else if (options.action === 'add' || options.action == 'set') { - el.setAttribute(options.propertyName, options.propertyValue); - } + var trigger = this_.processTrigger(signatureParts, paramValues); + var action = this_.processAction(signatureParts, paramValues, elt); + + if(action.invalid || trigger.invalid) { + console.warn("invalid no-js attribute " + attr.name + "=\"" + + attr.value + "\""); + } else { + this_.processListener(trigger, action, elt); } + }); + }; + + NoJS.prototype.processMeta = function(meta) { + var template = {}; + template.copyActions = []; + template.applyActions = []; + var noJsStr = null; - else if (options.propertyOrEventType === 'dom' && options.action === 'remove') { - el.remove(); + Object.keys(meta.attributes).forEach(function(prop) { + var attr = meta.attributes[prop]; + + if(attr.name == "no-js") { noJsStr = attr.value; } + else if(attr.name.indexOf("on-") === 0) { + var copy = {}; + copy.keyStr = attr.name; + copy.valStr = attr.value; + template.copyActions.push(copy); + } else { + var apply = {}; + apply.keyStr = attr.name; + apply.valStr = attr.value; + template.applyActions.push(apply); } + }); - else if (options.propertyOrEventType === 'value') { - if (options.action === 'set') { - el.value = options.propertyValue; - } else if (options.action === 'reset') { - el.value = null; - } + var noJsArgs = this.splitParams(noJsStr); + if(noJsArgs != null && noJsArgs.length === 2) { + template.argc = parseInt(noJsArgs[1]); + } + + if(template.argc == null || isNaN(template.argc) + || this.templates[noJsArgs[0]] != null) { + console.warn("invalid no-js meta template"); + console.warn(meta); + } else { + this.templates[noJsArgs[0]] = template; + } + }; + + NoJS.prototype.js = function (dom) { + var this_ = this; + dom = dom || 'html'; + document.querySelector(dom).querySelectorAll('[no-js]').forEach(function(el) { + if(el.tagName.toLowerCase() === "meta") { + this_.processMeta(el); + } else { + this_.processElement(el); } + }); + }; - else if (options.propertyOrEventType === 'text' && options.action === 'set') { - el.innerText = options.propertyValue; + window.no = new NoJS(); + + no.targetTypes.attribute = {}; + no.targetTypes.attribute.process = function(action, values) { + if(action.actionType === "add" || action.actionType === "set") { + if(values.length >= 2) { + action.attributeName = values.shift(); + action.attributeValue = values.join(" "); + } else { action.invalid = true; } + } else if(action.actionType === "remove") { + if(values.length === 1) { + action.attributeName = values.shift(); + } else { action.invalid = true; } + } else { action.invalid = true; } + }; + no.targetTypes.attribute.apply = function(evnt, action, target) { + if(action.actionType === "remove") { + target.removeAttribute(action.attributeName); + } else { + target.setAttribute(action.attributeName, action.attributeValue); + } + }; + + no.targetTypes["class"] = {}; + no.targetTypes["class"].process = function(action, values) { + if(action.actionType === "add" || action.actionType === "set" + || action.actionType === "remove" || action.actionType === "toggle" + || action.actionType === "switch") { + action.classNames = values; + } else { action.invalid = true; } + }; + no.targetTypes["class"].apply = function(evnt, action, target) { + if(action.actionType === "set") { + target.className = action.classNames.join(" "); + } else if(action.actionType === "switch") { + // @todo add and remove based on the class presence + // during time of action + action.classNames.forEach(function(name) { + target.classList.remove(name); + action.sourceElement.classList.add(name); + }); + } else { + action.classNames.forEach(function(name) { + target.classList[action.actionType](name); + }); + } + }; + + no.targetTypes.id = {}; + no.targetTypes.id.process = function(action, values) { + action.targetType = "attribute"; + values.unshift("id"); + no.targetTypes.attribute.process(action, values); + }; + + no.targetTypes.dom = {}; + no.targetTypes.dom.process = function(action, values) { + if(action.actionType !== "remove" && values.length != 0) { + action.invalid; + } + }; + no.targetTypes.dom.apply = function(evnt, action, target) { + if(action.actionType === "remove") { + target.remove(); + } + }; + + no.targetTypes.value = {}; + no.targetTypes.value.process = function(action, values) { + if(action.actionType === "set") { + action.value = values.join(" "); + } else if(action.actionType !== "reset" || values.length !== 0) { + action.invalid = true; + } + }; + no.targetTypes.value.apply = function(evnt, action, target) { + if(action.actionType === "set") { + target.value = action.value; + } else if(action.actionType === "reset") { + target.value = null; + } + }; + + no.targetTypes.text = {}; + no.targetTypes.text.process = function(action, values) { + if(action.actionType === "set") { + action.text = values.join(" "); + } else if(action.actionType === "copy") { + action.source = values.shift(); + } else { + action.invalid = true; + } + }; + no.targetTypes.text.apply = function(evnt, action, target) { + if(action.actionType === "set") { + target.innerText = action.text; + } else if(action.actionType === "copy") { + target.innerText = document.querySelector(action.source).innerText; + } + }; + + no.targetTypes.html = {}; + no.targetTypes.html.process = function(action, values) { + if(action.actionType === "set") { + action.html = values.join(" "); + } else if(action.actionType === "copy") { + action.source = values.shift(); + } else { + action.invalid = true; + } + }; + no.targetTypes.html.apply = function(evnt, action, target) { + if(action.actionType === "set") { + target.innerHTML = action.html; + } else if(action.actionType === "copy") { + target.innerHTML = document.querySelector(action.source).innerHTML; + } + }; + + function addTrigger(type) { + var ltype = type.toLowerCase(); + no.targetTypes[ltype] = {}; + no.targetTypes[ltype].process = function(action, values) { + if(action.actionType !== "trigger" || values.length > 0) { + action.invalid = true; } - }) + } + no.targetTypes[ltype].apply = function(evnt, action, target) { + target[type](); + } } - NoJS.prototype._getPropertyValueIndex = function (propertyOrEventType, isSelf) { - // if props type is attribute, the signature takes the form - // on-[evtType]-[action]-attribute = "target propertyName propertyValue" - var index = propertyOrEventType === 'attribute' ? 2 : 1; - return isSelf ? index - 1 : index; + addTrigger("click"); + addTrigger("focus"); + addTrigger("blur"); + addTrigger("scrollIntoView"); + + no.targetTypes.template = {}; + no.targetTypes.template.process = function(action, values) { + if(action.actionType === "apply") { + action.template = action.target; + action.target = action.sourceElement; + action.isSelf = true; + action.args = values; + } else { action.invalid = true; } + }; + no.targetTypes.template.apply = function(evnt, action, target) { + var template = no.templates[action.template]; + + for(var i = 0; i < template.applyActions.length; i++) { + var keys = template.applyActions[i].keyStr.split("-"); + var vals = no.splitParams(template.applyActions[i].valStr); + + no.templateArgs(vals, action.args); + var newAct = no.processAction(keys, vals, target); + if(newAct.isSelf) { + no.targetTypes[newAct.targetType].apply(evnt, newAct, target); + } else { + document.querySelectorAll(newAct.target).forEach(function(newTarget) { + no.targetTypes[newAct.targetType].apply(evnt, newAct, newTarget); + }); + } + } + }; + + no.targetTypes.form = {}; + no.targetTypes.form.process = function(action, values) { + action.form = action.target; + action.property = values.shift(); + action.target = action.sourceElement; + action.isSelf = true; + if(action.actionType === "set") { + action.value = values.join(" "); + } else if(action.actionType !== "reset") { + action.invalid = true; + } + } + no.targetTypes.form.apply = function(evnt, action, target) { + var prop = document.forms[action.form][action.property]; + if(action.actionType === "set") { + if(prop.type === "checkbox") { + if(action.value === "true" || action.value === "yes" + || action.value === "checked" || action.value === "on") { + prop.checked = true; + } else { prop.checked = false; } + } else { + prop.value = action.value; + } + } else { + if(prop.type === "checkbox") { prop.checked = false; } + else { prop.value = null; } + } } document.addEventListener('DOMContentLoaded', function() { - window.no = new NoJS(); - }) -})() \ No newline at end of file + no.js(); + }); +})(); diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..523755c --- /dev/null +++ b/package-lock.json @@ -0,0 +1,246 @@ +{ + "name": "nojs", + "version": "0.1.3", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "align-text": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "dev": true, + "requires": { + "kind-of": "^3.0.2", + "longest": "^1.0.1", + "repeat-string": "^1.5.2" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "camelcase": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", + "dev": true + }, + "center-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", + "dev": true, + "requires": { + "align-text": "^0.1.3", + "lazy-cache": "^1.0.3" + } + }, + "cliui": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "dev": true, + "requires": { + "center-align": "^0.1.1", + "right-align": "^0.1.1", + "wordwrap": "0.0.2" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "jasmine": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-3.4.0.tgz", + "integrity": "sha512-sR9b4n+fnBFDEd7VS2el2DeHgKcPiMVn44rtKFumq9q7P/t8WrxsVIZPob4UDdgcDNCwyDqwxCt4k9TDRmjPoQ==", + "dev": true, + "requires": { + "glob": "^7.1.3", + "jasmine-core": "~3.4.0" + } + }, + "jasmine-core": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.4.0.tgz", + "integrity": "sha512-HU/YxV4i6GcmiH4duATwAbJQMlE0MsDIR5XmSVxURxKHn3aGAdbY1/ZJFmVRbKtnLwIxxMJD7gYaPsypcbYimg==", + "dev": true + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + }, + "lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", + "dev": true + }, + "longest": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "right-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", + "dev": true, + "requires": { + "align-text": "^0.1.1" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "uglify-js": { + "version": "2.8.29", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", + "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", + "dev": true, + "requires": { + "source-map": "~0.5.1", + "uglify-to-browserify": "~1.0.0", + "yargs": "~3.10.0" + } + }, + "uglify-to-browserify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", + "dev": true, + "optional": true + }, + "window-size": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", + "dev": true + }, + "wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "yargs": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "dev": true, + "requires": { + "camelcase": "^1.0.2", + "cliui": "^2.1.0", + "decamelize": "^1.0.0", + "window-size": "0.1.0" + } + } + } +} diff --git a/package.json b/package.json index bd3c3b7..d73c3e0 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "Library that helps minimize js you have to write", "main": "no.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", + "test": "jasmine test/*.test.js", "uglify": "uglifyjs --compress --mangle -o dist/no.min.js -- no.js" }, "repository": { @@ -23,11 +23,18 @@ ], "author": "Ifedapo .A. Olarewaju", "license": "MIT", + "contributors": [ + { + "name": "Kimberlee Model", + "url": "www.redbow.kim/blog/" + } + ], "bugs": { "url": "https://github.com/ifedapoolarewaju/nojs/issues" }, "homepage": "https://github.com/ifedapoolarewaju/nojs#readme", "devDependencies": { - "uglify-js": "^2.7.5" + "uglify-js": "^2.7.5", + "jasmine": "^3.4.0" } } diff --git a/test.html b/test.html new file mode 100644 index 0000000..ebc3aa8 --- /dev/null +++ b/test.html @@ -0,0 +1,123 @@ + + + + + + + + + + + + +

Attributes

+ (add and set are equivelant) + + + + change my color +

Classes

+ + + + + change my classes +

Select class

+
    +
  • thing 1
  • +
  • thing 2
  • +
  • thing 3
  • +
  • thing 4
  • +
+

Id

+ + + change my color +

Remove an element

+ + Remove me +

Set Text

+ + + Set my text +

Value

+ + + + +

triggers

+ + + +
+ + + + + +

timeout

+ + using immediately timeout with negative count to flash forever + + + flash me a few times +

templates

+ + and it will copy actions from a template + + + and actions will be triggered with the template is triggered. + + + diff --git a/test/no.test.js b/test/no.test.js new file mode 100644 index 0000000..b8538c3 --- /dev/null +++ b/test/no.test.js @@ -0,0 +1,82 @@ +global.document = {}; +global.window = global; + +describe("no", function() { + document.querySelectorAll = function(selector) { return []; }; + document.querySelector = function(selector) { + var ret = {}; + ret.querySelectorAll = function(selector) { return []; }; + return ret; + }; + document.addEventListener = function(evt, act) { + act(); + }; + + var nojs = require("../no.js"); + var no = window.no; + + describe("splitParams", function() { + it("can split parameters with spaces", function() { + expect(no.splitParams("")).toEqual([ ]); + expect(no.splitParams(" ")).toEqual([ ]); + expect(no.splitParams("a")).toEqual(["a"]); + expect(no.splitParams("a b")).toEqual(["a", "b"]); + expect(no.splitParams("a b c")).toEqual(["a", "b", "c"]); + }); + + it("can split parameters with spaces and escapes", function() { + expect(no.splitParams("\\ ")).toEqual([" "]); + expect(no.splitParams("\\\\")).toEqual(["\\"]); + expect(no.splitParams("\\ ")).toEqual([" "]); + }); + + it("can split quoted parameters", function() { + expect(no.splitParams("\'a\'")).toEqual(["a"]); + expect(no.splitParams("\'a\' \'b\'")).toEqual(["a", "b"]); + expect(no.splitParams("\'a\' \'b\' \'c\'")).toEqual(["a", "b", "c"]); + }); + + it("can split quoted parameters with spaces and thingsin them", function() { + expect(no.splitParams("\'a b c\'")).toEqual(["a b c"]); + expect(no.splitParams("\'-a-\' \'+b+\'")).toEqual(["-a-", "+b+"]); + expect(no.splitParams("\' $a!>* \' \'b c \' \'c:d:e \'")).toEqual([" $a!>* ", "b c ", "c:d:e "]); + }); + + it("can split mixed quoted and unquoted", function() { + expect(no.splitParams("a \'b\'")).toEqual(["a", "b"]); + expect(no.splitParams("\'a\' b")).toEqual(["a", "b"]); + expect(no.splitParams("a \'b\' c")).toEqual(["a", "b", "c"]); + expect(no.splitParams("\'a\' b \'c\'")).toEqual(["a", "b", "c"]); + }); + + it("can have escapes in quoted", function() { + expect(no.splitParams("\'\\\'\\ \\\\\'")).toEqual(["\' \\"]); + expect(no.splitParams("\'\\\'\' \'\\ \' \'\\\\\'")).toEqual(["\'", " ", "\\"]); + expect(no.splitParams("\'a\\\'b\\ c\\\\\d'")).toEqual(["a\'b c\\d"]); + expect(no.splitParams("\'a\\\'b\' \'c\\ d\' \'e\\\\f\'")).toEqual(["a\'b", "c d", "e\\f"]); + }); + + it("can mix escapes with quotes and nonquotes", function() { + expect(no.splitParams("\'a \\ b\' c\\'\\ \'d\'")).toEqual(["a b", "c\' ", "d"]); + }); + + it("detects errors ", function() { + // no space between quoted strings. + expect(no.splitParams("\'a\'\'b\'")).toEqual("invalid"); + // unclosed string + expect(no.splitParams("\'a")).toEqual("invalid"); + // illegal escapes + expect(no.splitParams("\\n")).toEqual("invalid"); + }); + }); + + describe("templateArgs", function() { + it("should replace args", function() { + var vals = ["1 $0", "2 $1", "3 $2"]; + var args = ["aaaa", "bbbb", "cccc"]; + no.templateArgs(vals, args) + expect(vals).toEqual(["1 aaaa", "2 bbbb", "3 cccc"]); + }); + }); + +});