omf_web 0.9.6 → 0.9.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. data/README.md +168 -13
  2. data/bin/omf-web-basic +3 -3
  3. data/doc/index.md +205 -0
  4. data/example/NOT_WORKING/brooklyn/brooklyn_server.rb +2 -2
  5. data/example/NOT_WORKING/frisbee/data_sources/parse_log.rb +1 -1
  6. data/example/NOT_WORKING/frisbee/viz_server.rb +1 -1
  7. data/example/NOT_WORKING/gec12/gec12_demo_server.rb +1 -1
  8. data/example/NOT_WORKING/gec12/visualization.rb +2 -2
  9. data/example/NOT_WORKING/network/network_server.rb +2 -2
  10. data/example/NOT_WORKING/wimax/test.rb +2 -2
  11. data/example/NOT_WORKING/wimax/viz_server.rb +2 -2
  12. data/example/bridge/auth_basic.rb +75 -0
  13. data/example/bridge/config.ru +101 -0
  14. data/example/bridge/configure/configure_widget.rb +32 -0
  15. data/example/bridge/data_sources/sensor-sqlite.rb +28 -6
  16. data/example/bridge/data_sources/test31.sq3 +0 -0
  17. data/example/bridge/htdocs/{js/graph → graph/js}/bridge.js +2 -2
  18. data/example/bridge/htdocs/{js/graph → graph/js}/event_line_chart.js +7 -6
  19. data/example/bridge/htdocs/{js/graph → graph/js}/event_table.js +13 -5
  20. data/example/bridge/htdocs/template/login.html +23 -0
  21. data/example/bridge/viz_server.rb +3 -5
  22. data/example/bridge/widgets/configure.yaml +12 -0
  23. data/example/bridge/widgets/login.yaml +16 -0
  24. data/example/bridge/{overview.yaml → widgets/overview.yaml} +7 -4
  25. data/example/demo/data_sources/animals.rb +1 -1
  26. data/example/demo/data_sources/downloads.rb +1 -1
  27. data/example/demo/data_sources/generator.rb +1 -1
  28. data/example/demo/data_sources/histogram.rb +1 -1
  29. data/example/demo/data_sources/mobile_network.rb +4 -3
  30. data/example/demo/data_sources/movies.rb +1 -1
  31. data/example/demo/data_sources/network.rb +4 -3
  32. data/example/demo/data_sources/returns.rb +1 -1
  33. data/example/demo/data_sources/static_network.rb +4 -3
  34. data/example/demo/data_sources/walk.rb +1 -1
  35. data/example/demo/demo_viz_server.rb +1 -1
  36. data/example/demo/widgets/linked_graphs_tab.yaml +1 -1
  37. data/example/openflow-gec15/README.md +21 -0
  38. data/example/openflow-gec15/code_tab.yaml +36 -0
  39. data/example/openflow-gec15/dashboard_tab.yaml +72 -0
  40. data/example/openflow-gec15/doc/screenshot.png +0 -0
  41. data/example/openflow-gec15/exp_source.rb +104 -0
  42. data/example/openflow-gec15/of_viz_server.rb +63 -0
  43. data/example/openflow-gec15/openflow-demo.sq3 +0 -0
  44. data/example/openflow-gec15/raw_tab.yaml +37 -0
  45. data/example/openflow-gec15/repository/of-exp.rb +12 -0
  46. data/example/openflow-gec15/repository/sample.md +52 -0
  47. data/example/openflow-gec15/repository/trema-ctl6.rb +148 -0
  48. data/example/simple/README.md +2 -0
  49. data/example/simple/data_sources/gimi31.sq3 +0 -0
  50. data/example/simple/data_sources/ping_source.rb +56 -0
  51. data/example/simple/simple_viz_server.rb +39 -0
  52. data/example/simple/widgets/charts_tab.yaml +38 -0
  53. data/lib/omf-web/config.ru +31 -3
  54. data/lib/omf-web/data_source_proxy.rb +29 -26
  55. data/lib/omf-web/rack/session_authenticator.rb +93 -0
  56. data/lib/omf-web/rack/tab_mapper.rb +10 -5
  57. data/lib/omf-web/rack/websocket_handler.rb +17 -6
  58. data/lib/omf-web/theme/abstract_page.rb +1 -1
  59. data/lib/omf-web/theme/bright/flow_renderer.rb +2 -2
  60. data/lib/omf-web/theme/bright/layout_renderer.rb +15 -0
  61. data/lib/omf-web/theme/bright/mustache_renderer.rb +29 -0
  62. data/lib/omf-web/theme/bright/one_column_renderer.rb +2 -2
  63. data/lib/omf-web/theme/bright/page.rb +33 -8
  64. data/lib/omf-web/theme/bright/tabbed_renderer.rb +2 -3
  65. data/lib/omf-web/theme/bright/two_columns_renderer.rb +3 -4
  66. data/lib/omf-web/version.rb +1 -1
  67. data/lib/omf-web/widget/code_widget.rb +0 -7
  68. data/lib/omf-web/widget/layout/two_columns_layout.rb +3 -2
  69. data/lib/omf-web/widget/mustache_widget.rb +44 -0
  70. data/lib/omf-web/widget.rb +14 -1
  71. data/lib/omf_common/lobject.rb +6 -3
  72. data/omf_web.gemspec +3 -1
  73. data/share/htdocs/graph/js/abstract_nv_chart.js +14 -4
  74. data/share/htdocs/graph/js/abstract_widget.js +5 -4
  75. data/share/htdocs/graph/js/line_chart3.js +2 -0
  76. data/share/htdocs/graph/js/map2.js +3 -3
  77. data/share/htdocs/graph/js/network2.js +51 -19
  78. data/share/htdocs/graph/js/scatter_plot.js +6 -2
  79. data/share/htdocs/graph/js/table2.js +5 -2
  80. data/share/htdocs/js/data_source2.js +40 -8
  81. data/share/htdocs/js/mustache.js +29 -0
  82. data/share/htdocs/theme/abstract/abstract.js +10 -3
  83. data/share/htdocs/vendor/mustache-0.7.0/CHANGES +21 -0
  84. data/share/htdocs/vendor/mustache-0.7.0/LICENSE +10 -0
  85. data/share/htdocs/vendor/mustache-0.7.0/README.md +374 -0
  86. data/share/htdocs/vendor/mustache-0.7.0/jquery.mustache.js +635 -0
  87. data/share/htdocs/vendor/mustache-0.7.0/mustache.js +612 -0
  88. data/share/htdocs/vendor/nv_d3/js/nv.d3.js +9 -1
  89. data/share/htdocs/vendor/raphael-2.1.0/raphael.js +5815 -0
  90. metadata +74 -9
  91. data/DESIGN_NOTES.txt +0 -56
@@ -0,0 +1,635 @@
1
+ /*
2
+ Shameless port of a shameless port
3
+ @defunkt => @janl => @aq
4
+
5
+ See http://github.com/defunkt/mustache for more info.
6
+ */
7
+
8
+ ;(function($) {
9
+
10
+ /*!
11
+ * mustache.js - Logic-less {{mustache}} templates with JavaScript
12
+ * http://github.com/janl/mustache.js
13
+ */
14
+
15
+ /*global define: false*/
16
+
17
+ var Mustache;
18
+
19
+ (function (exports) {
20
+ if (typeof module !== "undefined" && module.exports) {
21
+ module.exports = exports; // CommonJS
22
+ } else if (typeof define === "function") {
23
+ define(exports); // AMD
24
+ } else {
25
+ Mustache = exports; // <script>
26
+ }
27
+ }((function () {
28
+
29
+ var exports = {};
30
+
31
+ exports.name = "mustache.js";
32
+ exports.version = "0.7.0";
33
+ exports.tags = ["{{", "}}"];
34
+
35
+ exports.Scanner = Scanner;
36
+ exports.Context = Context;
37
+ exports.Writer = Writer;
38
+
39
+ var whiteRe = /\s*/;
40
+ var spaceRe = /\s+/;
41
+ var nonSpaceRe = /\S/;
42
+ var eqRe = /\s*=/;
43
+ var curlyRe = /\s*\}/;
44
+ var tagRe = /#|\^|\/|>|\{|&|=|!/;
45
+
46
+ // Workaround for https://issues.apache.org/jira/browse/COUCHDB-577
47
+ // See https://github.com/janl/mustache.js/issues/189
48
+ function testRe(re, string) {
49
+ return RegExp.prototype.test.call(re, string);
50
+ }
51
+
52
+ function isWhitespace(string) {
53
+ return !testRe(nonSpaceRe, string);
54
+ }
55
+
56
+ var isArray = Array.isArray || function (obj) {
57
+ return Object.prototype.toString.call(obj) === "[object Array]";
58
+ };
59
+
60
+ function escapeRe(string) {
61
+ return string.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
62
+ }
63
+
64
+ var entityMap = {
65
+ "&": "&amp;",
66
+ "<": "&lt;",
67
+ ">": "&gt;",
68
+ '"': '&quot;',
69
+ "'": '&#39;',
70
+ "/": '&#x2F;'
71
+ };
72
+
73
+ function escapeHtml(string) {
74
+ return String(string).replace(/[&<>"'\/]/g, function (s) {
75
+ return entityMap[s];
76
+ });
77
+ }
78
+
79
+ // Export the escaping function so that the user may override it.
80
+ // See https://github.com/janl/mustache.js/issues/244
81
+ exports.escape = escapeHtml;
82
+
83
+ function Scanner(string) {
84
+ this.string = string;
85
+ this.tail = string;
86
+ this.pos = 0;
87
+ }
88
+
89
+ /**
90
+ * Returns `true` if the tail is empty (end of string).
91
+ */
92
+ Scanner.prototype.eos = function () {
93
+ return this.tail === "";
94
+ };
95
+
96
+ /**
97
+ * Tries to match the given regular expression at the current position.
98
+ * Returns the matched text if it can match, the empty string otherwise.
99
+ */
100
+ Scanner.prototype.scan = function (re) {
101
+ var match = this.tail.match(re);
102
+
103
+ if (match && match.index === 0) {
104
+ this.tail = this.tail.substring(match[0].length);
105
+ this.pos += match[0].length;
106
+ return match[0];
107
+ }
108
+
109
+ return "";
110
+ };
111
+
112
+ /**
113
+ * Skips all text until the given regular expression can be matched. Returns
114
+ * the skipped string, which is the entire tail if no match can be made.
115
+ */
116
+ Scanner.prototype.scanUntil = function (re) {
117
+ var match, pos = this.tail.search(re);
118
+
119
+ switch (pos) {
120
+ case -1:
121
+ match = this.tail;
122
+ this.pos += this.tail.length;
123
+ this.tail = "";
124
+ break;
125
+ case 0:
126
+ match = "";
127
+ break;
128
+ default:
129
+ match = this.tail.substring(0, pos);
130
+ this.tail = this.tail.substring(pos);
131
+ this.pos += pos;
132
+ }
133
+
134
+ return match;
135
+ };
136
+
137
+ function Context(view, parent) {
138
+ this.view = view;
139
+ this.parent = parent;
140
+ this.clearCache();
141
+ }
142
+
143
+ Context.make = function (view) {
144
+ return (view instanceof Context) ? view : new Context(view);
145
+ };
146
+
147
+ Context.prototype.clearCache = function () {
148
+ this._cache = {};
149
+ };
150
+
151
+ Context.prototype.push = function (view) {
152
+ return new Context(view, this);
153
+ };
154
+
155
+ Context.prototype.lookup = function (name) {
156
+ var value = this._cache[name];
157
+
158
+ if (!value) {
159
+ if (name === ".") {
160
+ value = this.view;
161
+ } else {
162
+ var context = this;
163
+
164
+ while (context) {
165
+ if (name.indexOf(".") > 0) {
166
+ var names = name.split("."), i = 0;
167
+
168
+ value = context.view;
169
+
170
+ while (value && i < names.length) {
171
+ value = value[names[i++]];
172
+ }
173
+ } else {
174
+ value = context.view[name];
175
+ }
176
+
177
+ if (value != null) {
178
+ break;
179
+ }
180
+
181
+ context = context.parent;
182
+ }
183
+ }
184
+
185
+ this._cache[name] = value;
186
+ }
187
+
188
+ if (typeof value === "function") {
189
+ value = value.call(this.view);
190
+ }
191
+
192
+ return value;
193
+ };
194
+
195
+ function Writer() {
196
+ this.clearCache();
197
+ }
198
+
199
+ Writer.prototype.clearCache = function () {
200
+ this._cache = {};
201
+ this._partialCache = {};
202
+ };
203
+
204
+ Writer.prototype.compile = function (template, tags) {
205
+ return this._compile(this._cache, template, template, tags);
206
+ };
207
+
208
+ Writer.prototype.compilePartial = function (name, template, tags) {
209
+ return this._compile(this._partialCache, name, template, tags);
210
+ };
211
+
212
+ Writer.prototype.render = function (template, view, partials) {
213
+ return this.compile(template)(view, partials);
214
+ };
215
+
216
+ Writer.prototype._compile = function (cache, key, template, tags) {
217
+ if (!cache[key]) {
218
+ var tokens = exports.parse(template, tags);
219
+ var fn = compileTokens(tokens);
220
+
221
+ var self = this;
222
+ cache[key] = function (view, partials) {
223
+ if (partials) {
224
+ if (typeof partials === "function") {
225
+ self._loadPartial = partials;
226
+ } else {
227
+ for (var name in partials) {
228
+ self.compilePartial(name, partials[name]);
229
+ }
230
+ }
231
+ }
232
+
233
+ return fn(self, Context.make(view), template);
234
+ };
235
+ }
236
+
237
+ return cache[key];
238
+ };
239
+
240
+ Writer.prototype._section = function (name, context, text, callback) {
241
+ var value = context.lookup(name);
242
+
243
+ switch (typeof value) {
244
+ case "object":
245
+ if (isArray(value)) {
246
+ var buffer = "";
247
+
248
+ for (var i = 0, len = value.length; i < len; ++i) {
249
+ buffer += callback(this, context.push(value[i]));
250
+ }
251
+
252
+ return buffer;
253
+ }
254
+
255
+ return value ? callback(this, context.push(value)) : "";
256
+ case "function":
257
+ var self = this;
258
+ var scopedRender = function (template) {
259
+ return self.render(template, context);
260
+ };
261
+
262
+ return value.call(context.view, text, scopedRender) || "";
263
+ default:
264
+ if (value) {
265
+ return callback(this, context);
266
+ }
267
+ }
268
+
269
+ return "";
270
+ };
271
+
272
+ Writer.prototype._inverted = function (name, context, callback) {
273
+ var value = context.lookup(name);
274
+
275
+ // Use JavaScript's definition of falsy. Include empty arrays.
276
+ // See https://github.com/janl/mustache.js/issues/186
277
+ if (!value || (isArray(value) && value.length === 0)) {
278
+ return callback(this, context);
279
+ }
280
+
281
+ return "";
282
+ };
283
+
284
+ Writer.prototype._partial = function (name, context) {
285
+ if (!(name in this._partialCache) && this._loadPartial) {
286
+ this.compilePartial(name, this._loadPartial(name));
287
+ }
288
+
289
+ var fn = this._partialCache[name];
290
+
291
+ return fn ? fn(context) : "";
292
+ };
293
+
294
+ Writer.prototype._name = function (name, context) {
295
+ var value = context.lookup(name);
296
+
297
+ if (typeof value === "function") {
298
+ value = value.call(context.view);
299
+ }
300
+
301
+ return (value == null) ? "" : String(value);
302
+ };
303
+
304
+ Writer.prototype._escaped = function (name, context) {
305
+ return exports.escape(this._name(name, context));
306
+ };
307
+
308
+ /**
309
+ * Calculates the bounds of the section represented by the given `token` in
310
+ * the original template by drilling down into nested sections to find the
311
+ * last token that is part of that section. Returns an array of [start, end].
312
+ */
313
+ function sectionBounds(token) {
314
+ var start = token[3];
315
+ var end = start;
316
+
317
+ var tokens;
318
+ while ((tokens = token[4]) && tokens.length) {
319
+ token = tokens[tokens.length - 1];
320
+ end = token[3];
321
+ }
322
+
323
+ return [start, end];
324
+ }
325
+
326
+ /**
327
+ * Low-level function that compiles the given `tokens` into a function
328
+ * that accepts two arguments: a Context and a Writer.
329
+ */
330
+ function compileTokens(tokens) {
331
+ var subRenders = {};
332
+
333
+ function subRender(i, tokens, template) {
334
+ if (!subRenders[i]) {
335
+ var fn = compileTokens(tokens);
336
+ subRenders[i] = function (writer, context) {
337
+ return fn(writer, context, template);
338
+ };
339
+ }
340
+
341
+ return subRenders[i];
342
+ }
343
+
344
+ function renderFunction(writer, context, template) {
345
+ var buffer = "";
346
+ var token, sectionText;
347
+
348
+ for (var i = 0, len = tokens.length; i < len; ++i) {
349
+ token = tokens[i];
350
+
351
+ switch (token[0]) {
352
+ case "#":
353
+ sectionText = template.slice.apply(template, sectionBounds(token));
354
+ buffer += writer._section(token[1], context, sectionText, subRender(i, token[4], template));
355
+ break;
356
+ case "^":
357
+ buffer += writer._inverted(token[1], context, subRender(i, token[4], template));
358
+ break;
359
+ case ">":
360
+ buffer += writer._partial(token[1], context);
361
+ break;
362
+ case "&":
363
+ buffer += writer._name(token[1], context);
364
+ break;
365
+ case "name":
366
+ buffer += writer._escaped(token[1], context);
367
+ break;
368
+ case "text":
369
+ buffer += token[1];
370
+ break;
371
+ }
372
+ }
373
+
374
+ return buffer;
375
+ }
376
+
377
+ return renderFunction;
378
+ }
379
+
380
+ /**
381
+ * Forms the given array of `tokens` into a nested tree structure where
382
+ * tokens that represent a section have a fifth item: an array that contains
383
+ * all tokens in that section.
384
+ */
385
+ function nestTokens(tokens) {
386
+ var tree = [];
387
+ var collector = tree;
388
+ var sections = [];
389
+ var token, section;
390
+
391
+ for (var i = 0; i < tokens.length; ++i) {
392
+ token = tokens[i];
393
+
394
+ switch (token[0]) {
395
+ case "#":
396
+ case "^":
397
+ token[4] = [];
398
+ sections.push(token);
399
+ collector.push(token);
400
+ collector = token[4];
401
+ break;
402
+ case "/":
403
+ if (sections.length === 0) {
404
+ throw new Error("Unopened section: " + token[1]);
405
+ }
406
+
407
+ section = sections.pop();
408
+
409
+ if (section[1] !== token[1]) {
410
+ throw new Error("Unclosed section: " + section[1]);
411
+ }
412
+
413
+ if (sections.length > 0) {
414
+ collector = sections[sections.length - 1][4];
415
+ } else {
416
+ collector = tree;
417
+ }
418
+ break;
419
+ default:
420
+ collector.push(token);
421
+ }
422
+ }
423
+
424
+ // Make sure there were no open sections when we're done.
425
+ section = sections.pop();
426
+
427
+ if (section) {
428
+ throw new Error("Unclosed section: " + section[1]);
429
+ }
430
+
431
+ return tree;
432
+ }
433
+
434
+ /**
435
+ * Combines the values of consecutive text tokens in the given `tokens` array
436
+ * to a single token.
437
+ */
438
+ function squashTokens(tokens) {
439
+ var token, lastToken;
440
+
441
+ for (var i = 0; i < tokens.length; ++i) {
442
+ token = tokens[i];
443
+
444
+ if (lastToken && lastToken[0] === "text" && token[0] === "text") {
445
+ lastToken[1] += token[1];
446
+ lastToken[3] = token[3];
447
+ tokens.splice(i--, 1); // Remove this token from the array.
448
+ } else {
449
+ lastToken = token;
450
+ }
451
+ }
452
+ }
453
+
454
+ function escapeTags(tags) {
455
+ if (tags.length !== 2) {
456
+ throw new Error("Invalid tags: " + tags.join(" "));
457
+ }
458
+
459
+ return [
460
+ new RegExp(escapeRe(tags[0]) + "\\s*"),
461
+ new RegExp("\\s*" + escapeRe(tags[1]))
462
+ ];
463
+ }
464
+
465
+ /**
466
+ * Breaks up the given `template` string into a tree of token objects. If
467
+ * `tags` is given here it must be an array with two string values: the
468
+ * opening and closing tags used in the template (e.g. ["<%", "%>"]). Of
469
+ * course, the default is to use mustaches (i.e. Mustache.tags).
470
+ */
471
+ exports.parse = function (template, tags) {
472
+ tags = tags || exports.tags;
473
+
474
+ var tagRes = escapeTags(tags);
475
+ var scanner = new Scanner(template);
476
+
477
+ var tokens = [], // Buffer to hold the tokens
478
+ spaces = [], // Indices of whitespace tokens on the current line
479
+ hasTag = false, // Is there a {{tag}} on the current line?
480
+ nonSpace = false; // Is there a non-space char on the current line?
481
+
482
+ // Strips all whitespace tokens array for the current line
483
+ // if there was a {{#tag}} on it and otherwise only space.
484
+ function stripSpace() {
485
+ if (hasTag && !nonSpace) {
486
+ while (spaces.length) {
487
+ tokens.splice(spaces.pop(), 1);
488
+ }
489
+ } else {
490
+ spaces = [];
491
+ }
492
+
493
+ hasTag = false;
494
+ nonSpace = false;
495
+ }
496
+
497
+ var start, type, value, chr;
498
+
499
+ while (!scanner.eos()) {
500
+ start = scanner.pos;
501
+ value = scanner.scanUntil(tagRes[0]);
502
+
503
+ if (value) {
504
+ for (var i = 0, len = value.length; i < len; ++i) {
505
+ chr = value.charAt(i);
506
+
507
+ if (isWhitespace(chr)) {
508
+ spaces.push(tokens.length);
509
+ } else {
510
+ nonSpace = true;
511
+ }
512
+
513
+ tokens.push(["text", chr, start, start + 1]);
514
+ start += 1;
515
+
516
+ if (chr === "\n") {
517
+ stripSpace(); // Check for whitespace on the current line.
518
+ }
519
+ }
520
+ }
521
+
522
+ start = scanner.pos;
523
+
524
+ // Match the opening tag.
525
+ if (!scanner.scan(tagRes[0])) {
526
+ break;
527
+ }
528
+
529
+ hasTag = true;
530
+ type = scanner.scan(tagRe) || "name";
531
+
532
+ // Skip any whitespace between tag and value.
533
+ scanner.scan(whiteRe);
534
+
535
+ // Extract the tag value.
536
+ if (type === "=") {
537
+ value = scanner.scanUntil(eqRe);
538
+ scanner.scan(eqRe);
539
+ scanner.scanUntil(tagRes[1]);
540
+ } else if (type === "{") {
541
+ var closeRe = new RegExp("\\s*" + escapeRe("}" + tags[1]));
542
+ value = scanner.scanUntil(closeRe);
543
+ scanner.scan(curlyRe);
544
+ scanner.scanUntil(tagRes[1]);
545
+ type = "&";
546
+ } else {
547
+ value = scanner.scanUntil(tagRes[1]);
548
+ }
549
+
550
+ // Match the closing tag.
551
+ if (!scanner.scan(tagRes[1])) {
552
+ throw new Error("Unclosed tag at " + scanner.pos);
553
+ }
554
+
555
+ tokens.push([type, value, start, scanner.pos]);
556
+
557
+ if (type === "name" || type === "{" || type === "&") {
558
+ nonSpace = true;
559
+ }
560
+
561
+ // Set the tags for the next time around.
562
+ if (type === "=") {
563
+ tags = value.split(spaceRe);
564
+ tagRes = escapeTags(tags);
565
+ }
566
+ }
567
+
568
+ squashTokens(tokens);
569
+
570
+ return nestTokens(tokens);
571
+ };
572
+
573
+ // The high-level clearCache, compile, compilePartial, and render functions
574
+ // use this default writer.
575
+ var _writer = new Writer();
576
+
577
+ /**
578
+ * Clears all cached templates and partials in the default writer.
579
+ */
580
+ exports.clearCache = function () {
581
+ return _writer.clearCache();
582
+ };
583
+
584
+ /**
585
+ * Compiles the given `template` to a reusable function using the default
586
+ * writer.
587
+ */
588
+ exports.compile = function (template, tags) {
589
+ return _writer.compile(template, tags);
590
+ };
591
+
592
+ /**
593
+ * Compiles the partial with the given `name` and `template` to a reusable
594
+ * function using the default writer.
595
+ */
596
+ exports.compilePartial = function (name, template, tags) {
597
+ return _writer.compilePartial(name, template, tags);
598
+ };
599
+
600
+ /**
601
+ * Renders the `template` with the given `view` and `partials` using the
602
+ * default writer.
603
+ */
604
+ exports.render = function (template, view, partials) {
605
+ return _writer.render(template, view, partials);
606
+ };
607
+
608
+ // This is here for backwards compatibility with 0.4.x.
609
+ exports.to_html = function (template, view, partials, send) {
610
+ var result = exports.render(template, view, partials);
611
+
612
+ if (typeof send === "function") {
613
+ send(result);
614
+ } else {
615
+ return result;
616
+ }
617
+ };
618
+
619
+ return exports;
620
+
621
+ }())));
622
+
623
+ $.mustache = function (template, view, partials) {
624
+ return Mustache.render(template, view, partials);
625
+ };
626
+
627
+ $.fn.mustache = function (view, partials) {
628
+ return $(this).map(function (i, elm) {
629
+ var template = $(elm).html().trim();
630
+ var output = $.mustache(template, view, partials);
631
+ return $(output).get();
632
+ });
633
+ };
634
+
635
+ })(jQuery);