1 | (function() {
|
2 | var DOMElementType, HTMLCompiler, Tag, Template, copy_structure, deep_merge, example, example2, fs, hook, isArray, jQuery, jsonify, mask, match, new_tag, slim, slim_attrs, suitup, traverse, trim, util, _ref;
|
3 | var __slice = Array.prototype.slice;
|
4 |
|
5 | fs = require('fs');
|
6 |
|
7 | jQuery = require('jquery');
|
8 |
|
9 | isArray = Array.isArray;
|
10 |
|
11 | DOMElementType = {
|
12 | NORMAL: 1,
|
13 | TEXT: 3,
|
14 | CDATA: 4,
|
15 | FRAGMENT: 11
|
16 | };
|
17 |
|
18 | deep_merge = function() {
|
19 | var k, obj, objs, res, v, _i, _len;
|
20 | objs = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
|
21 | if (isArray(objs[0])) objs = objs[0];
|
22 | res = {};
|
23 | for (_i = 0, _len = objs.length; _i < _len; _i++) {
|
24 | obj = objs[_i];
|
25 | for (k in obj) {
|
26 | v = obj[k];
|
27 | if (typeof v === 'object' && !isArray(v)) {
|
28 | res[k] = deep_merge(res[k] || {}, v);
|
29 | } else {
|
30 | res[k] = v;
|
31 | }
|
32 | }
|
33 | }
|
34 | return res;
|
35 | };
|
36 |
|
37 | trim = function(str) {
|
38 | return str.replace(/^\s+|\s+$/g, "");
|
39 | };
|
40 |
|
41 | slim_attrs = function(el) {
|
42 | var attr, attrs, _i, _len, _ref, _ref2;
|
43 | attrs = {};
|
44 | _ref2 = (_ref = el.attributes) != null ? _ref : [];
|
45 | for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
|
46 | attr = _ref2[_i];
|
47 | attrs[attr.name] = attr.value;
|
48 | }
|
49 | return attrs;
|
50 | };
|
51 |
|
52 | slim = function(el) {
|
53 | return {
|
54 | name: el.nodeName.toLowerCase(),
|
55 | attrs: slim_attrs(el),
|
56 | children: traverse(el.childNodes)
|
57 | };
|
58 | };
|
59 |
|
60 | traverse = function(elems) {
|
61 | var el, res, _i, _len;
|
62 | if (elems == null) return [];
|
63 | res = [];
|
64 | for (_i = 0, _len = elems.length; _i < _len; _i++) {
|
65 | el = elems[_i];
|
66 | if (el.nodeType === DOMElementType.NORMAL) {
|
67 | res.push(slim(el));
|
68 | } else if (el.nodeType === DOMElementType.TEXT) {
|
69 | if (trim(el.value).length) res.push(el.value);
|
70 | } else {
|
71 | continue;
|
72 | }
|
73 | }
|
74 | return res;
|
75 | };
|
76 |
|
77 | jsonify = function(elems) {
|
78 | var el, _i, _len, _ref, _results;
|
79 | _ref = elems != null ? elems : [];
|
80 | _results = [];
|
81 | for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
82 | el = _ref[_i];
|
83 | _results.push(slim(el));
|
84 | }
|
85 | return _results;
|
86 | };
|
87 |
|
88 | copy_structure = function(tree) {
|
89 | var el, res, _i, _len, _ref;
|
90 | res = [];
|
91 | _ref = tree != null ? tree : [];
|
92 | for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
93 | el = _ref[_i];
|
94 | if (typeof el === 'string' || typeof el === 'number') {
|
95 | res.push(el);
|
96 | continue;
|
97 | }
|
98 | res.push({
|
99 | name: el.name,
|
100 | attrs: el.attrs,
|
101 | children: copy_structure(el.children)
|
102 | });
|
103 | }
|
104 | return res;
|
105 | };
|
106 |
|
107 | match = function(tag, el) {
|
108 | var key, value, _ref, _ref2;
|
109 | if (el == null) return true;
|
110 | if (tag.name !== el.name) return false;
|
111 | _ref = tag.attrs;
|
112 | for (key in _ref) {
|
113 | value = _ref[key];
|
114 | if (el.attrs[key] !== value) {
|
115 | if (typeof value !== 'string' || (((_ref2 = el.attrs[key]) != null ? _ref2.indexOf(value) : void 0) || -1) === -1) {
|
116 | return false;
|
117 | }
|
118 | }
|
119 | }
|
120 | return true;
|
121 | };
|
122 |
|
123 | new_tag = function(parent, el, callback) {
|
124 | var attrs;
|
125 | attrs = deep_merge(el.attrs);
|
126 | return parent.tag(el.name, attrs, function() {
|
127 | var child, _i, _len, _ref, _ref2;
|
128 | _ref2 = (_ref = el.children.slice()) != null ? _ref : [];
|
129 | for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
|
130 | child = _ref2[_i];
|
131 | if (typeof child === 'string' || typeof child === 'number') {
|
132 | this.text("" + child, {
|
133 | append: true
|
134 | });
|
135 | } else {
|
136 | new_tag(this, child, function() {
|
137 | if (typeof callback === "function") callback();
|
138 | return callback = null;
|
139 | });
|
140 | }
|
141 | }
|
142 | this.end();
|
143 | return typeof callback === "function" ? callback() : void 0;
|
144 | });
|
145 | };
|
146 |
|
147 | mask = function(tag, el) {
|
148 | if (el == null) return;
|
149 | tag.attr(el.attrs);
|
150 | return tag._elems = el.children;
|
151 | };
|
152 |
|
153 | hook = function(tpl) {
|
154 | return tpl.xml.use(function(parent, tag, next) {
|
155 | var elems, repeat;
|
156 | elems = parent._elems;
|
157 | if (elems == null) return next(tag);
|
158 | repeat = function() {
|
159 | var el;
|
160 | el = elems[0];
|
161 | if (typeof el === 'string' || typeof el === 'number') {
|
162 | console.log("text".blue, el);
|
163 | elems.shift();
|
164 | if (typeof parent.text === "function") {
|
165 | parent.text(el, {
|
166 | append: true
|
167 | });
|
168 | }
|
169 | return repeat();
|
170 | } else if (match(tag, el)) {
|
171 | console.log("match".yellow, el != null ? el.name : void 0, el != null ? el.attrs : void 0);
|
172 | elems.shift();
|
173 | mask(tag, el);
|
174 | return next(tag);
|
175 | } else {
|
176 | console.log("new".green, el != null ? el.name : void 0, el != null ? el.attrs : void 0, "(", tag.name, tag.attrs, ")");
|
177 | console.log("WTF WTF WTF WTF".bold.red, tag.name, tag.attrs);
|
178 | return new_tag(parent, el, function() {
|
179 | console.log("repeat".red, tag.name, tag.attrs, "(", el != null ? el.name : void 0, el != null ? el.attrs : void 0, ")");
|
180 | return repeat();
|
181 | });
|
182 | }
|
183 | };
|
184 | return repeat();
|
185 | });
|
186 | };
|
187 |
|
188 | suitup = function(rawtemplate, tree) {
|
189 | return function() {
|
190 | var args, elems, tpl;
|
191 | args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
|
192 | tpl = rawtemplate.apply(null, args);
|
193 | elems = copy_structure(tree);
|
194 | tpl.xml._elems = elems;
|
195 | hook(tpl);
|
196 | return tpl;
|
197 | };
|
198 | };
|
199 |
|
200 | HTMLCompiler = (function() {
|
201 |
|
202 | function HTMLCompiler() {
|
203 | this.$ = jQuery.create();
|
204 | this.loadSync = this.open;
|
205 | }
|
206 |
|
207 | HTMLCompiler.prototype.read = function(filename, callback) {
|
208 | var _this = this;
|
209 | return fs.readFile(filename, function(err, data) {
|
210 | return callback != null ? callback.call(_this, err, data != null ? data.toString() : void 0) : void 0;
|
211 | });
|
212 | };
|
213 |
|
214 | HTMLCompiler.prototype.readSync = function(filename) {
|
215 | var _ref;
|
216 | return (_ref = fs.readFileSync(filename)) != null ? _ref.toString() : void 0;
|
217 | };
|
218 |
|
219 | HTMLCompiler.prototype.parse = function(data) {
|
220 | return this.el = this.$(data);
|
221 | };
|
222 |
|
223 | HTMLCompiler.prototype.select = function(from, to) {
|
224 | var el;
|
225 | el = this.el.find(from);
|
226 | el = el.clone();
|
227 | el.find(to).remove();
|
228 | return el;
|
229 | };
|
230 |
|
231 | HTMLCompiler.prototype.use = function(data) {
|
232 | this.loaded = true;
|
233 | return this.parse(data);
|
234 | };
|
235 |
|
236 | HTMLCompiler.prototype.load = function(filename, callback) {
|
237 | return this.read(filename, function(err, data) {
|
238 | if (err) return callback.call(this, err);
|
239 | this.use(data);
|
240 | return callback(null, this.el);
|
241 | });
|
242 | };
|
243 |
|
244 | HTMLCompiler.prototype.open = function(filename) {
|
245 | var data;
|
246 | data = this.readSync(filename);
|
247 | return this.use(data);
|
248 | };
|
249 |
|
250 | HTMLCompiler.prototype.compile = function(rawtemplate, el) {
|
251 | var r, tree;
|
252 | if (!this.loaded) {
|
253 | throw new Error("no html file loaded or html string used.");
|
254 | }
|
255 | console.log("building data structure ...");
|
256 | if (el == null) el = this.el;
|
257 | tree = jsonify(el);
|
258 | console.log("design is ready loaded. suiting up the template ...");
|
259 | r = suitup(rawtemplate, tree);
|
260 | r.tree = tree;
|
261 | console.log("done.");
|
262 | return r;
|
263 | };
|
264 |
|
265 | |
266 |
|
267 |
|
268 |
|
269 |
|
270 |
|
271 |
|
272 |
|
273 |
|
274 |
|
275 |
|
276 |
|
277 |
|
278 | return HTMLCompiler;
|
279 |
|
280 | })();
|
281 |
|
282 | require('colors');
|
283 |
|
284 | util = require('util');
|
285 |
|
286 | util.orginspect = util.inspect;
|
287 |
|
288 | util.inspect = require('eyes').inspector({
|
289 | stream: null,
|
290 | hexy: {
|
291 | format: 'fours'
|
292 | }
|
293 | });
|
294 |
|
295 | _ref = require('./dynamictemplate'), Template = _ref.Template, Tag = _ref.Tag;
|
296 |
|
297 | example = function() {
|
298 | var channelsdesign, design, rawtemplate, streamshtml, template, _ref2;
|
299 | design = new HTMLCompiler;
|
300 | console.log("* loading html ...");
|
301 | streamshtml = design.open('/home/dodo/code/arbyt/buddycloud/webclient/brunch/build/streams.html');
|
302 | console.log("* selecting part of the html ...");
|
303 | channelsdesign = streamshtml.select('#channels', '.channel');
|
304 | console.log("S", (_ref2 = streamshtml.select('.channel')) != null ? _ref2.length : void 0);
|
305 | rawtemplate = function(ee) {
|
306 | return new Template({
|
307 | schema: 5
|
308 | }, function() {
|
309 | return this.$div({
|
310 | id: 'channels'
|
311 | }, function() {
|
312 | return this.$div(function() {
|
313 | var _this = this;
|
314 | return ee != null ? ee.on('new:channel', function(channel) {
|
315 | return _this.$div({
|
316 | "class": 'channel'
|
317 | }, function() {
|
318 | this.$div({
|
319 | "class": 'avatar',
|
320 | style: "background-image:url(" + channel.avatar + ")"
|
321 | }, function() {
|
322 | return this.$span({
|
323 | "class": 'counter'
|
324 | }, channel.counter);
|
325 | });
|
326 | return this.$div({
|
327 | "class": 'info'
|
328 | }, function() {
|
329 | var _ref3;
|
330 | this.$span({
|
331 | "class": 'owner'
|
332 | }, function() {
|
333 | var jid, _ref3;
|
334 | jid = ((_ref3 = channel.get('jid')) != null ? _ref3.split('@') : void 0) || [];
|
335 | this.text("" + jid[0]);
|
336 | return this.$span({
|
337 | "class": 'domain'
|
338 | }, "" + jid[1]);
|
339 | });
|
340 | return this.$span({
|
341 | "class": 'status'
|
342 | }, ((_ref3 = channel.nodes.get('status')) != null ? _ref3.last() : void 0) || "");
|
343 | });
|
344 | });
|
345 | }) : void 0;
|
346 | });
|
347 | });
|
348 | });
|
349 | };
|
350 | console.log("* start compiling ...");
|
351 | return template = design.compile(rawtemplate, channelsdesign);
|
352 | };
|
353 |
|
354 | example2 = function() {
|
355 | var design, rawtemplate, template;
|
356 | design = new HTMLCompiler;
|
357 | console.log("* using html ...");
|
358 | design.use("<div id=\"main\">\n <div class=\"logo\" id=\"big\">some <a href=\"#\">linked</a> logo</div>\n <div class=\"tor list\" id=\"zwiebel\">\n <div class=\"entry\">some random entry</div>\n </div>\n <span>impressum</span>\n</div>\n<script>alert('evil');</script>");
|
359 | rawtemplate = function() {
|
360 | return new Template({
|
361 | schema: 5
|
362 | }, function() {
|
363 | return this.$div({
|
364 | id: 'main'
|
365 | }, function() {
|
366 | this.$div({
|
367 | "class": 'list'
|
368 | }, function() {
|
369 | return this.$div({
|
370 | "class": 'entry'
|
371 | }, "specific text");
|
372 | });
|
373 | return this.$footer("stuff");
|
374 | });
|
375 | });
|
376 | };
|
377 | console.log("* start compiling ...");
|
378 | template = design.compile(rawtemplate);
|
379 | template.design = design;
|
380 | return template;
|
381 | };
|
382 |
|
383 | module.exports = {
|
384 | example: example,
|
385 | example2: example2,
|
386 | HTMLCompiler: HTMLCompiler,
|
387 | copy_structure: copy_structure
|
388 | };
|
389 |
|
390 | }).call(this);
|