Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

[lib] rewrite, [tests] added

  • Loading branch information...
commit 3236d61e618ec92e8d9d30a044c8582d26ef01b4 1 parent 90abd5a
Paolo Fragomeni authored
View
199 lib/plates.js
@@ -5,21 +5,18 @@
Merge.prototype = {
- tag: new RegExp(
- [
- '(<',
+ tag: new RegExp([
+ '<',
'(/?)', // 2 - is closing
'([-:\\w]+)', // 3 - name
- '((?:\\s+[-\\w]+(?:', '=', '(?:' +
- '\\w+|' +
- '"[^"]*"|' +
- '\'[^\']*\'))?)*)', // 4 - attributes
+ '((?:[-\\w]+(?:', '=',
+ '(?:\\w+|["|\'](?:.*)["|\']))?)*)', // 4 - attributes
'(/?)', // 5 - is self-closing
- '>)(.*)'
+ '>'
].join('\\s*')
),
- attr: /([-\w]*)=(?:["\']([-\.\w\s]*)["\'])/gi,
+ attr: /([\-\w]*)=(?:["\']([\-\.\w\s\/]*)["\'])/gi,
hasClass: function(str, className) {
return str.indexOf(className) > -1;
@@ -27,45 +24,63 @@
bind: function bind(html, data, map) {
+ html = html || '';
data = data || {};
+ var that = this;
+
if (map) {
map = map.mappings;
}
- var that = this;
- var str = html;
- var buffer = '';
-
- var matchmode = false;
- var openers = 0;
-
- var right = 0, left = 0;
- var match, tag, text;
-
- do {
-
- tag = '', text = '';
- left = right;
- match = this.tag.exec(str); // test
- str = match && match[6]; // next
+ var openers = 0,
+ components,
+ attributes,
+ intag = false,
+ tagname = '',
+ isClosing = false,
+ isSelfClosing = false
+ matchmode = false;
+
+ var c,
+ buffer = '',
+ left;
+
+ for (var i = 0, l = html.length; i < l; i++) {
+
+ c = html[i];
+
+ if (c === '!' && intag && !matchmode) {
+ intag = false;
+ buffer += html.slice(left, i+1);
+ }
+ else if (c === '<' && !intag) {
+ closing = true;
+ intag = true;
+ left = i;
+ }
+ else if (c === '>' && intag) {
- if (match) {
+ intag = false;
+ tagbody = html.slice(left, i+1);
+
+ components = this.tag.exec(tagbody);
- right += match.index + match[1].length;
+ if(!components) { continue; }
- //
- // get the prior text to the left of the tag that was found.
- // if it is a self closing tag, it will never have text.
- //
+ isClosing = components[1];
+ tagname = components[2];
+ attributes = components[3];
+ isSelfClosing = components[4];
if (matchmode) {
//
// and its a closing.
//
- if (!!match[2]) {
- if(openers <= 0) {
+ if (!!isClosing) {
+
+ if (openers <= 0) {
matchmode = false;
}
else {
@@ -73,101 +88,91 @@
}
}
//
- // and its not a closing tag!
+ // and its not a self-closing tag
//
- else if (!match[5]) {
+ else if (!isSelfClosing) {
++openers;
}
-
}
- else if (!match[5]) {
- text = html.slice(left, right - match[1].length);
- }
+ if (attributes && !isClosing && !matchmode) {
- //
- // get the next tag from the stream.
- //
- tag = html.slice(left + match.index, right);
-
- //
- // if there is a map, we may want to replace the value
- // in an attribute or replace the body of the tag based
- // on a specified attribute value. Closing tags are ignored.
- //
- if (map && !match[2]) {
-
- for (var i = map.length - 1; i >= 0; i--) {
+ //
+ // if there is a match in progress and
+ //
+ if (map) {
- tag = tag.replace(
- this.attr,
- function (attr, key, value, idx) {
+ for (var ii = map.length - 1; ii >= 0; ii--) {
- console.log(key, !map[i].replace, map[i].attribute === key, map[i].value, value)
+ tagbody = tagbody.replace(this.attr, function(str, key, value, a) {
+
+ var newdata = map[ii].dataKey ? data[map[ii].dataKey] : data[key];
- if (map[i].replace === key) {
+ if (map[ii].replace === key) {
//
// if there is data intended to replace the attribute, use that
// otherwise look at the data structure and try to use that.
//
- var newdata = map[i].dataKey ? data[map[i].dataKey] : data[key];
+ var newdata = map[ii].dataKey ? data[map[ii].dataKey] : data[key];
return key + '="' + (newdata || '') + '"';
}
- else if (!map[i].replace && map[i].attribute === key && map[i].value === value) {
-
- buffer += text + tag + data[map[i].dataKey];
- matchmode = true;
- return attr;
+ else if (!map[ii].replace && map[ii].attribute === key) {
+
+ if (map[ii].value === value || that.hasClass(value, map[ii].value)) {
+
+ buffer += tagbody + (newdata || '');
+ matchmode = true;
+ }
}
- else {
- return attr;
+ return str;
+
+ });
+ }
+ }
+ else {
+
+ //
+ // if there is no map, we are just looking to match
+ // the specified id to a data key in the data object.
+ //
+ tagbody.replace(
+ this.attr,
+ function (attr, key, value, idx) {
+ if (key === 'id' && data[value]) {
+ buffer += tagbody + data[value];
+ matchmode = true;
}
}
);
-
- console.log(tag);
}
- }
- else if (!match[5]) { // cant be self closing to have text in the body.
-
- //
- // if there is no map, we are just looking to match
- // the specified id to a data key in the data object.
- //
- tag.replace(
- this.attr,
- function (attr, key, value, idx) {
- if (key === 'id' && data[value]) {
- buffer += text + tag + data[value];
- matchmode = true;
- }
- }
- );
}
+ //
+ // if there is currently no match in progress
+ // just write the tagbody to the buffer.
+ //
if (!matchmode) {
-
- buffer += (text || '') + (tag || '');
+ buffer += tagbody;
}
+
}
- }
- while (str);
-
- //
- // write anything that is leftover, as it will
- // be arbitrary bites leftover from the stream.
- //
- if (html) {
- buffer += html.slice(right);
- }
+ else if (!intag && !matchmode) {
- return buffer;
+ //
+ // currently not inside a tag and there is no
+ // match in progress, we can write the char to
+ // the buffer.
+ //
+ buffer += c;
+ }
+ }
+ return buffer;
}
- };
+ };
var Mapper = function Mapper(val) {
if (!(this instanceof Mapper)) { return new Mapper(val); }
this.mappings = [];
View
79 test/api-test.js
@@ -1,47 +1,76 @@
var vows = require('vows'),
assert = require('assert'),
Plates = require('../lib/plates');
- common = require('./fixtures/common');
+ common = require('./common');
vows.describe('merge data into markup').addBatch({
'when providing both data and markup': {
- '(1) a single tag with an `id` that corresponds to a `data-key`.': (
+ // '(1) a single tag with an `id` that corresponds to a `data-key`.': (
- function() {
- return common.createTest('test-1');
- }()
+ // function() {
+ // return common.createTest('test-1');
+ // }()
- ),
- '(2) a deeply nested tag with an `id` that corresponds to a `data-key`.': (
+ // ),
+
+ // '(2) a deeply nested tag with an `id` that corresponds to a `data-key`.': (
- function() {
- return common.createTest('test-2');
- }()
+ // function() {
+ // return common.createTest('test-2');
+ // }()
- ),
- '(3) a tag with an `id` that corresponds to a `data-key`, having a body of nested tags.': (
+ // ),
- function() {
- return common.createTest('test-3');
- }()
+ // '(3) a tag with an `id` that corresponds to a `data-key`, having a body of nested tags.': (
- ),
- '(4) a tag with an arbitrary attribute that corresponds to a `data-key`.': (
+ // function() {
+ // return common.createTest('test-3');
+ // }()
- function() {
+ // ),
+
+ // '(4) a tag with an arbitrary attribute that corresponds to a `data-key`.': (
+
+ // function() {
+ // var map = new Plates.Map();
+ // map.where('src').is('google.com').use('key1');
+ // map.where('src').is('yahoo.com').use('key2');
+
+ // return common.createTest('test-4', map);
+
+ // }()
+
+ // ),
+
+ // '(5) a tag with a class attribute whith a value that corresponds to a `data-key`.': (
+
+ // function() {
+
+ // var map = new Plates.Map();
+ // map.where('class').is('hidden').use('key1');
+
+ // return common.createTest('test-5', map);
+
+ // }()
+
+ // ),
+
+
+ '(6) a tag with a class attribute whith a value that corresponds to a `data-key`.': (
+
+ function() {
+
var map = new Plates.Map();
- map.where('src').is('google.com').use('key1');
- map.where('src').is('yahoo.com').use('key2');
+ map.where('class').is('hidden').use('key1');
+ map.where('href').is('/foo').use('key2').as('href');
- return common.createTest('test-4', map);
+ return common.createTest('test-6', map);
}()
- ),
- '(5) a tag that matches a specified attribute in the map': {
-
- }
+ )
}
}).export(module);
+
View
4 test/fixtures/common.js → test/common.js
@@ -2,14 +2,14 @@
var common = exports,
assert = require('assert'),
fs = require('fs'),
- Plates = require('../../lib/plates');
+ Plates = require('../lib/plates');
function get(name, extension) {
try {
return fs.readFileSync(
__dirname +
- '/../templates/' +
+ '/fixtures/' +
name + '.' +
extension
).toString();
View
0  test/templates/test-1.html → test/fixtures/test-1.html
File renamed without changes
View
0  test/templates/test-1.json → test/fixtures/test-1.json
File renamed without changes
View
0  test/templates/test-1.out → test/fixtures/test-1.out
File renamed without changes
View
1  test/fixtures/test-2.html
@@ -0,0 +1 @@
+<!-- foo --><div id="key1"><div id="key2"></div><img src="/"/></div>
View
0  test/templates/test-2.json → test/fixtures/test-2.json
File renamed without changes
View
2  test/templates/test-2.out → test/fixtures/test-2.out
@@ -1 +1 @@
-<!-- foo --><div id="key1"><div id="key2">value2</div><img src="/"></div>
+<!-- foo --><div id="key1"><div id="key2">value2</div><img src="/"/></div>
View
0  test/templates/test-3.html → test/fixtures/test-3.html
File renamed without changes
View
0  test/templates/test-3.json → test/fixtures/test-3.json
File renamed without changes
View
0  test/templates/test-3.out → test/fixtures/test-3.out
File renamed without changes
View
0  test/templates/test-4.html → test/fixtures/test-4.html
File renamed without changes
View
0  test/templates/test-4.json → test/fixtures/test-4.json
File renamed without changes
View
0  test/templates/test-4.out → test/fixtures/test-4.out
File renamed without changes
View
1  test/fixtures/test-5.html
@@ -0,0 +1 @@
+<a id="someid" class="red hidden large" href="/foo">Old Value</a>
View
3  test/fixtures/test-5.json
@@ -0,0 +1,3 @@
+{
+ "key1": "New Value"
+}
View
1  test/fixtures/test-5.out
@@ -0,0 +1 @@
+<a id="someid" class="red hidden large" href="/foo">New Value</a>
View
1  test/fixtures/test-6.html
@@ -0,0 +1 @@
+<a id="someid" class="red hidden large" href="/foo">Old Value</a>
View
4 test/fixtures/test-6.json
@@ -0,0 +1,4 @@
+{
+ "key1": "New Value",
+ "key2": "/bar"
+}
View
1  test/fixtures/test-6.out
@@ -0,0 +1 @@
+<a id="someid" class="red hidden large" href="/bar">New Value</a>
View
0  test/perf/benchpress.js → test/perf-test.js
File renamed without changes
View
1  test/templates/test-2.html
@@ -1 +0,0 @@
-<!-- foo --><div id="key1"><div id="key2"></div><img src="/"></div>
Please sign in to comment.
Something went wrong with that request. Please try again.