liveui.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. /* appjet:version 0.1 */
  2. /* appjet:library */
  3. // Copyright (c) 2009, Herbert Vojčík
  4. // Licensed by MIT license (http://www.opensource.org/licenses/mit-license.php)
  5. // ====== Rendering context ======
  6. var _stack = [];
  7. // ====== API ======
  8. /**
  9. * A seq is like DIV() or SPAN() without having attributes and without
  10. * any tags rendered.
  11. */
  12. function seq(element1, element2, etc) {
  13. return new _seq(arguments);
  14. }
  15. /**
  16. * A box is seq, which can have model set via given(model).
  17. * By default, model is false.
  18. * If a box's model evaluates to false, it renders to ""; otherwise,
  19. * it renders normally (eg. renders its contents).
  20. */
  21. function box(element1, element2, etc) {
  22. return new _box(arguments);
  23. }
  24. /**
  25. * A lazy is an object which calls appropriate function when rendered
  26. * to obtain actual object to be rendered.
  27. * This function gets actually rendered boxes' models as its arguments,
  28. * the innermost model being the first argument, parent being the second, etc.
  29. @param f the rendering function. Returns the structure (eg. DIV(), TABLE()
  30. or whatever else which you would put inside print()). It should not print() directly.
  31. */
  32. function lazy(f) {
  33. return new _lazy(f);
  34. }
  35. // ====== Convenience functions ======
  36. /** Convenience lazy that returns data from model, arguments (if any) denote property chain. */
  37. function data(prop1, prop2, etc) {
  38. var args = arguments;
  39. return lazy(function(model) {
  40. Array.forEach(args, function(p) { model = model[p]; });
  41. return model;
  42. });
  43. }
  44. /** Convenience lazy that returns data from parent's model, arguments (if any) denote property chain. */
  45. function outerdata(prop1, prop2, etc) {
  46. var args = arguments;
  47. return lazy(function(model, parent) {
  48. Array.forEach(args, function(p) { parent = parent[p]; });
  49. return parent;
  50. });
  51. }
  52. /**
  53. * Convenience proxy lazily representing the box's model.
  54. * Use dot notation to lazily represent particular contents of the model, to any depth.
  55. */
  56. //var data = _subdata([]);
  57. /**
  58. * Convenience proxy lazily representing the box's parent's model.
  59. * Use dot notation to lazily represent particular contents of the parent's model, to any depth.
  60. */
  61. //var outerdata = _subdata([], 1);
  62. /**
  63. * Convenience lazy that wraps a box and sets its model from supplied value model
  64. * (either lazy or plain value).
  65. */
  66. function sub(valueModel, box) {
  67. return lazy(function() { return box.given(valueModel.valueOf()); });
  68. }
  69. /**
  70. * Convenience lazy that iteratively repeats a sub-box with elements
  71. * of supplied valueModel (either lazy or plain value) set as a sub-boxes' models.
  72. */
  73. function iter(valueModel, box) {
  74. return lazy(function() {
  75. var result = seq();
  76. valueModel.valueOf().forEach(function(element) {
  77. result.push(lazy(function() { return box.given(element); }));
  78. });
  79. return result;
  80. });
  81. }
  82. // ====== Workers ======
  83. function _seq(content) {
  84. this.push.apply(this, content);
  85. }
  86. _seq.prototype = object(Array.prototype);
  87. _seq.prototype.toHTML = function() { return this.map(toHTML).join(""); };
  88. _seq.prototype.toString = function() { return this.toHTML(); };
  89. function _box(content) {
  90. _seq.apply(this, arguments);
  91. }
  92. _box.prototype = object(_seq.prototype);
  93. _box.prototype.model = false;
  94. _box.prototype.toHTML = function() {
  95. if (!this.model) { return ""; }
  96. try { _stack.unshift(this.model); return this.map(toHTML).join(""); }
  97. finally { _stack.shift(); }
  98. };
  99. /** Sets model for the box. Returns the box. */
  100. _box.prototype.given = function(model) {
  101. /** Model of the box */
  102. this.model = model;
  103. return this;
  104. };
  105. function _lazy(f) {
  106. this.f = f;
  107. }
  108. _lazy.prototype.valueOf = function() {
  109. return this.f.apply(null, _stack);
  110. };
  111. _lazy.prototype.toHTML = function() { return toHTML(this.valueOf()); };
  112. _lazy.prototype.toString = function() { return this.valueOf().toString(); };
  113. /*function _subdata(props, i) {
  114. if (!i) { i = 0; }
  115. var valueFun = props.length ?
  116. function() {
  117. var inner = _stack[i];
  118. props.forEach(function(p) { inner = inner[p]; });
  119. return inner;
  120. } : function() { return _stack[i]; };
  121. return appjet._native.createProxyObject(
  122. function(p) {
  123. switch(p) {
  124. case "valueOf": return valueFun;
  125. default: return _lazy.prototype[p] || _subdata(props.concat([p]), i);
  126. }
  127. },
  128. function() {}, function() {}, function() {return [];}, _lazy.prototype
  129. );
  130. }*/
  131. /* appjet:server */
  132. import("lib-app/liveui");
  133. print(
  134. box(
  135. "<div>", data("hello"), "</div> <-- div tags should be written",
  136. HR(),
  137. sub(data("innerwld"), box(
  138. "<div>", outerdata("hello"), ", ", data("foo"), "</div> <-- here as well"
  139. )),
  140. UL(iter(data("squares"), box(
  141. LI(data("n")," squared is ", data("n2"))
  142. )))
  143. ).given({
  144. hello: "hello",
  145. innerwld: {foo: "world"},
  146. squares: [1,2,3,4,5].map(function(x) { return { n:x, n2:x*x }; })
  147. })
  148. );