-
Notifications
You must be signed in to change notification settings - Fork 2
/
index.html
900 lines (851 loc) · 48.8 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
<DOCTYPE html>
<html lang="en">
<head>
<title>⚐ Bender: a declarative framework for Web applications</title>
<meta charset="UTF-8">
<meta http-equiv="cache-control" content="no-cache">
<style>
body { font-family: Univers, "Helvetica Neue", Helvetica, sans-serif;
width: 960px; margin: auto; font-size: 16px;
background-color: #fef9f0; }
header { border-top: solid 2px #ff7f40; }
#manual, #todo { border-top: solid 2px #40ff40; }
#demos, #library, #tests { border-top: solid 2px #40bfff; }
footer { clear: both; padding: 40px 0; font-size: 12px;
text-align: center; border-bottom: solid 2px #ff7f40; }
h1, h2, h3, h4 { font-weight: normal; color: #102040; }
.g4, .g8, .g12 { display: inline; float: left; position: relative;
margin: 0 10px; }
.g4 { width: 300px; }
.g8 { width: 620px; }
.g12 { width: 940px; }
.clear { clear: both; display: block; overflow: hidden;
visibility: hidden; width: 0; height: 0; }
code, pre { font-family: Menlo, Consolas, monospace; font-size: 14px; }
a { color: #ff4040; text-decoration: none; }
.def { background-color: #ff0; }
.elem { background-color: #8f8; }
.prop, .param, .attr { background-color: #8ff; }
.TODO { background-color: #ddd; }
.sample { margin-left: 2em; }
.broken, .done { text-decoration: line-through; }
svg { width: 128px; height: 144px; margin: 8px 0; }
#welcome { border: dashed thin #102040; padding: 8px; margin: 0 20px; }
</style>
<script src="flexo.js"></script>
<script src="bender.js"></script>
</head>
<body>
<header class="g12">
<svg viewBox="0 0 128 144">
<defs>
<clipPath id="r">
<rect x="-64" y="-56" width="128" height="144" rx="8" ry="8"/>
</clipPath>
</defs>
<g transform="translate(64, 56)" stroke-width="16" stroke-linejoin="round"
clip-path="url(#r)">
<polygon>
<animateTransform attributeName="transform" attributeType="XML"
type="scale" from="3" to="1" dur="0.3s" fill="freeze"/>
<animateTransform attributeName="transform" attributeType="XML"
type="rotate" from="90" to="0" dur="0.3s" additive="sum"/>
</polygon>
<g stroke="#fef9f0" stroke-linecap="round" fill="none">
<line x1="-20" y1="-50" x2="-20" y2="0"/>
<circle r="20"/>
<animateTransform attributeName="transform" attributeType="XML"
type="scale" from="0" to="1" dur="0.4s" fill="freeze"/>
</g>
<text font-family="Univers, 'Helvetica Neue', Helvetica, sans-serif"
text-anchor="middle" font-size="32" y="76" stroke="none">Bender</text>
</g>
<script>
var color = flexo.random_element(["#ff4040", "#ff7f40", "#40ff40",
"#40bfff", "#102040"]);
var g = document.querySelector("g");
g.setAttribute("fill", color);
g.setAttribute("stroke", color);
var p = document.querySelector("polygon");
p.setAttribute("points",
flexo.svg_polygon_points(7, 42, Math.random()));
</script>
</svg>
<p><strong>Bender</strong> is a declarative framework for Web applications
and reusable components. It is free software and is released under the
Apache License v2.0 (see included <a
href="https://github.com/bendr/bender/blob/master/LICENSE">LICENSE
file</a>.) The purpose of Bender is to make authoring Web applications
easier by means of better and higher-level abstractions, and providing a
foundation for even more powerful authoring tools.</p>
<p>The source code repository is <a
href="https://github.com/bendr/bender">hosted on Github</a>. Please
contact <a href="mailto:bender@igel.co.jp">bender@igel.co.jp</a> for any
question regarding Bender.</p>
</header>
<div class="g8">
<section id="manual">
<h2>Manual</h2>
<p>This manual is a work in progress and not yet complete. Please have a
look at the test files and the source code for more detail. The demos in
the side bar will show some applications written in Bender.</p>
<section id="manual.concepts">
<h3>Bender in a nutshell</h3>
<p>Bender is a declarative framework for Web applications: the overall
<em>structure</em> of the application and its constituent parts is
meant to be made as explicit as possible. This should improve
application component reusability; relieve the need to generate a lot
of complex or tedious code; and allow for new tools to help develop
and debug applications. With Bender we are also exploring how, by
describing an application through a DOM tree just like any XML
document, we can make it more dynamic by responding to changes in the
tree in real-time, allowing to add and remove components at will from
a running application.</p>
<p>The core of Bender is the <em>component</em>, an extensible and
reusable unit of functionality. Components are built from other
components and communicate with each other through <em>properties</em>
and <em>events</em>. At their lowest level, components make use of
modern Web technologies such as HTML5, SVG, Javascript, CSS, &c.
to provide custom capabilities and visual rendering.</p>
<p>Bender applications have a tree structure which can be easily
expressed using XML. See for instance the following application:</p>
<pre class="sample" id="welcome-src"><app xmlns="http://bender.igel.co.jp"
xmlns:html="http://www.w3.org/1999/xhtml">
<title>Welcome to Bender!</title>
<view>
<html:p>Welcome to Bender!</html:p>
<html:p>
<use id="thanks-button" href="lib/button.xml">Thanks</use>
</html:p>
</view>
<watch>
<get use="thanks-button" event="@pushed">
alert("You're welcome!");
</get>
</watch>
</app></pre>
<p>Before describing it in more details, let's see it run below:</p>
<div class="bender" id="welcome"></div>
<p>Let's see the meaning of each element:</p>
<ul>
<li><code class="elem">app</code> stands for <em>application</em>
and is a container for a Bender application.
<ul>
<li><code class="elem">title</code> is a metadata element.</li>
<li><code class="elem">view</code> describes how the application
should be rendered. We use HTML to render this application.
<ul>
<li><code class="elem">html:p</code> is a regular HTML paragraph
element.</li>
<li><code class="elem">use</code>, however, is a Bender element
including another Bender component. In this case, it is a button
component pulled from the URL given by the <code
class="attr">href</code> parameter. Note how HTML and Bender
contents are interleaved; the <code>use</code> element itself
contains additional HTML content (the "<code>Thanks</code>" text
node.)</li>
</ul></li>
<li><code class="elem">watch</code> monitors events and property
changes in Bender components.
<ul>
<li><code class="elem">get</code> describes what is being
monitored. Here, the <code class="attr">use</code> and <code
class="attr">event</code> attributes point to
<code>@pushed</code> event generated by the button component
with id <code>thanks-button</code>. The content of this node is
Javascript code that gets executed when the event is received
from the button. This example is a simple event listener, but
watches have a lot of other capabilities.</li>
</ul></li>
</ul>
</li>
</ul>
</section>
<section id="manual.running">
<h3>Running a Bender application</h3>
<p>Running a Bender application requires:</p>
<ul>
<li>a <em>host application</em>, most commonly a Web browser,
capable of reading and displaying DOM trees and running Javascript
code;</li>
<li>a <em>target document</em>, open in the host application, where
the Bender content will be rendered;</li>
<li>the runtime engine, implemented in Javascript, which is
contained in the file <code><a
href="https://github.com/bendr/bender/blob/master/bender.js">bender.js</a></code>,
and relies on the <code><a
href="https://github.com/bendr/bender/blob/master/flexo.js">flexo.js</a></code>
support library (there are no other dependencies.)</li>
</ul>
<p>The sidebar showcases some demo applications and simpler tests that
can be run immediately in your browser. Note that while
<code>flexo.js</code> is the <em>de facto</em> utility library for
Bender applications, other frameworks may be used freely <span
class="TODO">(provide some examples.)</span> In order to run Bender
applications locally, you only need the two aforementioned Javascript
files. However, by cloning the <a
href="https://github.com/bendr/bender">development repository</a>, you
will also find many test files and library components. Because
external XML files are loaded through XMLHttpRequest, you will
probably want to run Bender through a Web server to bypass security
issues.</p>
<p>Bender content may be rendered in a target document as a complete
application, or individual components may be inserted in the document.
The Bender content may be read from XML description files or created
on the fly through scripting. A Bender application may even contain
another Bender application. For instance, the <a
href="lib/params.html?href=../apps/logo.xml">Bender logo example</a>
is an application that is run through another Bender application that
creates inputs to modify and monitor the parameters of the running
application. You can then change different values that control the
aspect of the logo. Another example is the <a
href="lib/params.html?href=../apps/calculator.xml">calculator</a>
application, where the inner workings of the calculator are
automatically exposed and can help in tracking down bugs.</p>
</section>
<section id="manual.context">
<h3>The context</h3>
<p>The <em>context</em> is the document hosting Bender elements (it is
a DOM Document node.) The root of the document is a
<code class="elem">bender</code> element, which is a special node that
is only used as the root a Bender context tree. A <code>bender</code>
element then has two children: a <code class="elem">context</code>
element and a <code class="elem">use</code> element. The
<code>context</code> is a special kind of Bender component (see below)
hosting all the current Bender content, while the <code>use</code>
element is necessary for rendering.</p>
<p><code class="def">bender.create_context(target)</code> creates a
new context with a rendering target specified by
<code class="param">target</code> (the target document by default.)
If the target is a DOM <code>Element</code> (<em>e.g.</em> the
<code>body</code> of an HTML document, or a <code>g</code> element in
an SVG document), rendered nodes will be appended to the given target.
In other cases (<em>e.g.</em>, when the target is a
<code>Document</code> node, which is the default), individual
components may be rendered by specifying a target node. The
<code>context</code> element is returned, <strong>not</strong> the
context document that was created (which can be accessed through the
DOM <code>ownerDocument</code> property of any node in the
document.)</p>
</section>
<section id="manual.elements">
<h3>Bender elements</h3>
<p>Elements in the Bender tree, whatever their namespace
(<em>i.e.</em>, Bender elements, HTML elements, SVG elements, &c.)
overload common DOM methods so that changes in the tree are reflected
in the running application. A convenience method <code
class="def">$(name, attributes, ...)</code> is defined on all elements
to create new nodes through scripting.</p>
<ul>
<li>The <code class="param">name</code> parameter is the name of the
element to be created and may be qualified by a known namespace
prefix (<code>html</code> or <code>xhtml</code>, <code>svg</code>,
<code>xlink</code>, <code>xml</code>, <code>xmlns</code>; the Bender
namespace <code>http://bender.igel.co.jp</code> is used if there is
no prefix) and may include an id prefixed by <code>#</code> and a
list of class names prefixed by <code>.</code>. For example, the
name string <code>html:div#body.calculator</code> describes an HTML
<code>div</code> element with id <code>body</code> and class
<code>calculator</code>, while <code>use</code> describes a Bender
<code>use</code> element.</li>
<li>The <code class="param">attributes</code> parameter is an
object in which keys are attribute names and values attribute values
to be set for the new element. For example,
<code>{ q: "app" }</code> sets the <code>q</code> attribute to
<code>app</code> for the element being created. A <code>null</code>
or <code>undefined</code> value for an attribute will not set it.
This parameter may be empty or omitted.</li>
<li>The remaining parameters, if any, are the contents of the
element: either a string, which creates a text node, or another
element, usually also created by the <code>$</code> method.</li>
</ul>
<p>Node manipulation is done through the DOM methods <code
class="def">appendChild</code>, <code class="def">insertBefore</code>,
<code class="def">setAttribute</code>, and <code
class="def">setAttributeNS</code>. (Other DOM methods are not
overloaded.) Additionally, Bender elements have a <code
class="def">_textContent(text)</code> method to replace
setting the <code>textContent</code> property, which can still be read
normally (and also be set, but changes will not cause the rendering to
update.) See also <code>_clone_node()</code> below, which is a
replacement for <code>cloneNode(true)</code>.</p>
<p>Since a Bender tree may be modified at runtime, it can be
serialized again through the <code class="def">_serialize()</code>
method. This simply returns a text string of the XML serialization of
the current state of the Bender tree. This method is available on any
element, so it may be used for instance for the main application or a
given component rather than the full context.</p>
<section id="manual.elements.component">
<h4>The component, app and context elements</h4>
<p>The <code class="elem">component</code> element describes a
Bender component. <code class="elem">app</code> is synonymous with
<code>component</code> and is provided to describe the main
component of a Bender application. <code class="elem">context</code>
is also a synonym and is only used at the top of the Bender tree, as
described above. A component may have metadata, a view, scripts,
watches, and define other components. These are described by the
following elements:</p>
<ul>
<li><code class="elem">component</code> describes other
components in the scope of this component;</li>
<li><code class="elem">desc</code> contains textual description
for the component. This is used as metadata; for intance, it can
be used to give hints about the usage of this component;</li>
<li><code class="elem">script</code> allows customizing both the
content and the behavior of the component through Javascript;</li>
<li><code class="elem">title</code> contains the title of the
component as plain text. This is used mostly as metadata, but gets
rendered as the document title when it is the child of an
<code>app</code> element;</li>
<li><code class="elem">use</code> creates a new instance of a
component and renders it in this component's view.
<code>use</code> elements <em>should</em> appear as descendants of
the <code>view</code> element of the component;</li>
<li><code class="elem">view</code> contains an interleaving of
foreign and text nodes and <code>use</code> elements that will be
rendered in the target document when this component is rendered. A
component may have only one view; setting a new view automatically
replaces the previous one;</li>
<li><code class="elem">watch</code> describes the behavior of the
component in the face of changes in its properties and events it
receives. See the section on watches below.</li>
</ul>
<p>All Bender elements may have an <code class="attr">id</code>
attribute which should be unique in the document where the element
appears (if importing elements from different documents, elements
with the same id can be distinguished by the URL of the original
document.) These ids are not rendered since many instances of the
same component may be rendered in a document. Bender elements have
an <code class="param">_id</code> property matching that
attribute.</p>
<p>Components can be small units of functionality, with or without
an actual view, like a <a href="https://github.com/bendr/bender/blob/master/lib/button.xml">button</a>
or a <a
href="https://github.com/bendr/bender/blob/master/lib/timer.xml">timer</a>,
or larger components relying on other components like toolbars,
dialogs, all the way to complete applications.</p>
<p><span class="TODO">Document @refresh event from context when
component instances are refreshed.</span></p>
</section>
<section id="manual.elements.use">
<h4>The use element</h4>
<p>The <code class="elem">use</code> element instantiates and
renders a component. For every <code>use</code> element, a new
<em>instance</em> of a component is created; if this component has a
view, or has <code>use</code> children, then these get rendered in
its place.</p>
<p>The component to be instantiated is designated by one and only
one of the following attributes:</p>
<ul>
<li><code class="attr">q</code> (short for <em>query
selector</em>) to refer to an element in the current context
(<span class="TODO">TODO: check the exact context of the
querySelector call</span>); note that using <code>#</code> for id
may not work, so it is safer to use <code>ref</code> below in that
situation;</li>
<li><code class="attr">ref</code> to refer to the id of an element
in the current document;</li>
<li><code class="attr">href</code> to refer to a component from an
XML file located at a given URL.</li>
</ul>
<p>Additional attributes (besides <code class="attr">id</code>) and
contents of the <code>use</code> elements are passed to the
instantiated component view during rendering as described below.</p>
</section>
<section id="manual.elements.view">
<h4>The view, content and target elements</h4>
<p>The <code class="elem">view</code> element contains foreign
elements (<em>e.g.</em>, HTML, SVG, &c.) and text nodes
describing the actual rendering of a component. <code>view</code>
may also include <code>use</code>, <code>target</code> and
<code>content</code> elements (other Bender elements are silently
ignored). Additionally, <code>use</code> and <code>target</code>
elements outside of a <code>view</code> element are also rendered as
siblings of the children of the <code>view</code> element.</p>
<p>When a component is rendered, the contents of the view are copied
as is (minus id attributes as discussed above) into the target
element. The <code class="elem">use</code> elements allows the
inclusion of a Bender component as described above. The <code
class="elem">content</code> element is a placeholder element that,
on rendering, is replaced by the contents of the referencing
<code>use</code> element. The <code>content</code> element may have
content of its own, which is the default content that gets rendered
when the referencing <code>use</code> element has no content.
Similarly, attributes of the referencing <code>use</code> elements
are also added to the top-level elements that get rendered; this
allows for instance to change the class of an element to alter its
rendering.</p>
<p>Additionally, the <code class="elem">target</code> element allows
to target a specific node for rendering. For instance, it may be
used to add a <code>style</code> element to the <code>head</code> of
an HTML target document, or a new definition in the <code>use</code>
element of an SVG document. The target element is selected through
the <code class="attr">q</code> or <code class="attr">ref</code>,
using a query selector (resp. an id) in the <em>target</em> document
to specify the target. Another optional attribute of
<code>target</code> is the flag <code class="attr">once</code>,
which when set to the value <code>true</code> means that the content
of the element are rendered exactly <em>once</em> to avoid
duplicating the content.</p>
<p><span class="TODO">Describe <code>content-id</code> and attribute
copying.</span></p>
</section>
<section id="manual.elements.script">
<h4>The component instance object, component properties, and the
script element</h4>
<p>Before rendering, a component gets <em>instantiated</em>, which
creates a new Javascript object acting as the <em>component
instance</em> of this component. A component instance has the
following methods and properties:</p>
<ul>
<li><code class="def">init(use, component)</code> initializes the
component after it was created. <code class="param">use</code> is
the <code>use</code> node instantiating the component, and <code
class="param">component</code> is the component node being
instantiated. The component instance has corresponding <code
class="param">use</code> and <code class="param">component</code>
properties to access these. The instance is returned.</li>
<li><code class="prop">views</code> maps the id of the foreign
nodes inside the view of the component and the actual rendered
nodes in the target. Elements that do not have an id are not
included. The target document may be referred to through the
pseudo-id <code>$document</code> (<em>e.g.</em>,
<code>instance.views.$document</code>.)</li>
<li><code class="prop">uses</code> maps the id of <code>use</code>
nodes inside the view of the component and the instance that was
created. Nodes that do not have an id are not included. Pseudo ids
for the instance itself (<code>$self</code>) and its parent
instance, if any (<code>$parent</code>) are also defined. The
former is used in watches (see below.)</li>
<li><code class="def">instantiated()</code> is called
<em>after</em> the instance was created and initialized, and right
before it will be rendered. By default, it does not do anything
but can be overloaded for component customization.</li>
</ul>
<div class="TODO">
<p>TODO: define properties:</p>
<ul>
<li>The <code>properties</code> property;</li>
<li>The attribute namespaces <code>b</code> (boolean value),
<code>e</code> (string value), <code>f</code> (float value), and
<code>j</code> (JSON value);</li>
</ul>
</div>
<p>The <code class="elem">script</code> element contains custom
Javascript code. This code is executed when the element is added to
its parent component element <em>and</em> its text content is set
(<span class="TODO">there will be an <code>href</code> attribute as
well to load external script files.</span>) The code is executed in
the context of the parent component element; in Javascript terms,
<code class="param">this</code> will point to the parent component
element.</p>
<p>One use of the <code>script</code> element is to customize the
behavior of the instances of the component. The <em>prototype</em>
of the component instances may be accessed and modified through the
<code class="param">_prototype</code> property, so that methods may
be added or redefined. See for instance the <a
href="https://github.com/bendr/bender/blob/master/lib/timer.xml">timer
component</a>.</p>
<p>Another use of the <code>script</code> element is to
programmatically add contents to a component. See for instance the
<a
href="https://github.com/bendr/bender/blob/master/apps/calculator.xml">calculator</a>
application where all buttons are added by a script (look for the
call to <code>context.$("use", ...)</code>.)</p>
</section>
<section id="manual.nodes.watch">
<h4>The watch, get and set nodes</h4>
<p>A <em>watch</em> is a part of a component that describes how to
react to events and property changes. For instance, if we build a <a
href="lib/run.html?href=../apps/calculator.xml">calculator</a>, we
want to update the result of operations after each button press
(events) and update the display on the screen when that result
changes (a property change.)</p>
<p>The <code class="elem">watch</code> element describes a watch.
This element has no parameter and contains zero or more <code
class="elem">get</code> and <code class="elem">set</code>
elements. The <code>get</code> element describes what the watch is
monitoring. This can be an DOM event from a DOM node, a
custom event from a component, or a property. Whenever the monitored
event occurs or the monitored property changes, the parent watch is
<em>activated</em>. The <code>set</code> elements describe what
properties and attributes are set in response to the activation of
the parent watch.</p>
<p><code class="elem">get</code> elements have three parameters:</p>
<ol>
<li>a target component or element;</li>
<li>an event or property being monitored for this target;</li>
<li>optionally, a function to transform the monitored value.</li>
</ol>
<p>The target is specified by one of the following attributes:</p>
<ul>
<li><code class="attr">view</code>, which must be the id of a
foreign element inside the <code>view</code> of the
component (or the pseudo id <code>$document</code>), or</li>
<li><code class="attr">use</code>, which must be the id of a
<code>use</code> element within the component (or the pseudo ids
<code>$self</code> or <code>$parent</code>.)</li>
</ul>
<p>The event or property is specified by one of the following
attributes:</p>
<ul>
<li><code class="attr">event</code>, which is the name of a DOM
event if the target is a view element (<em>e.g.</em>,
<code>click</code>), or a custom Bender event if the target is a
<code>use</code> element. (<span class="TODO">describe Bender
events</span>)</li>
<li><code class="attr">property</code>, which is the name of a
property of the target component (only if the target is a
<code>use</code> element.) The <code>use</code> attribute may be
omitted, in which case it defaults to the closest component
instance in the tree that has such a property.</li>
</ul>
<p>The parent watch is activated whenever an event is sent from the
target of a monitored element or a property changes in a monitored
component instance. The associated value for this activation is the
event object or the property value, but if the <code>get</code>
element has text content other than whitespace, then this content is
interpreted as a Javascript function that transforms the activation
value, and/or executes arbitrary code, just like a regular event
listener (indeed, monitoring a property change is similar to
listening to an event triggered any time the monitored property does
change.) In this function, the <code class="param">value</code>
parameter is the original activation value, and <code
class="param">this</code> is the component instance. The return
value is the new activation value (which may then be undefined.)</p>
<p>When a watch is activated by any of its <code>get</code> child,
then <em>all</em> child <code>set</code> elements are activated in
reaction, taking the (possibly transformed) activation value as
input. <code class="elem">set</code> elements have the same <code
class="attr">view</code> and <code class="attr">use</code>
parameters as <code>get</code> elements to define a target. For a
given target, the following may be set:</p>
<ul>
<li><code class="attr">attr</code>, an attribute of the target
node, or</li>
<li><code class="attr">property</code>, a property of a target
node.</li>
</ul>
<p>The attribute or property is set to the input activation value,
or may be transformed by a function defined as the text content of
the <code>set</code> element, in a similar fashion to the
<code>get</code> element.</p>
</section>
</section>
<section id="manual.clone">
<h3>Deriving new components through cloning</h3>
<p>Bender allows the derivation of new components from existing ones
through <em>cloning</em>. Similarly to the Javascript
<code>Object.create()</code> method, the <code
class="def">_clone_node(node, params)</code> method of the context
(document) create a deep clone of the given node. The second argument
is an object with key/value pairs for the <em>parameters</em> of the
source component.</p>
<p>Attribute and text nodes of the prototype component may contain
value placeholder of the form <code>{name}</code>, which get replaced
with the value for <code>name</code> in the <code
class="param">params</code> object, or the empty string if absent.</p>
</section>
<section id="manual.render-tree">
<h3>Rendering a Bender tree</h3>
<p>A self-contained Bender application tree can be rendered into any
host document by simply creating a context with the host document as
target, populating the tree, and having a <code>use</code> element as
a child of the root element pointing to the main application
component. Here is <a href="tests/hello.html">a simple HTML "Hello,
world!" example</a> being rendered in the body of the host
document:</p>
<pre class="sample">var context = bender.create_context(document.body);
context.appendChild(
context.$("component",
context.$("view",
context.$("html:p", "Hello, world!"))));
context.appendChild(context.$("use", { q: "component" }));</pre>
</section>
<section id="manual.render-component">
<h3>Rendering a Bender component in a document</h3>
<p>Another use case is to render individual components into an
existing document. We still need a context, but we'll leave the
default target to the host document so that the full tree is not
rendered by default. Then, we can use the convenience method <code
class="def">_insert_use(attrs, target)</code> to insert a new <code
class="elem">use</code> element with the given <code
class="param">attrs</code> in the context and render it to the
given <code class="param">target</code> element. For example, to <a
href="tests/insert.html">render a component in a <code>div</code>
element</a> with the id <code>here</code>:</p>
<pre class="sample">var context = bender.create_context();
context.appendChild(
context.$("component",
context.$("view",
context.$("html:p.bender", "But this is a Bender component!"))));
context._insert_use({ q: "component", document.getElementById("here"));</pre>
</section>
<section id="manual.load-xml">
<h3>Loading Bender components from XML files</h3>
<p>Real-size applications and components reside in XML files rather
than Javascript. Loading a component from XML is as simple as creating
a new <code class="elem">use</code> element with an <code
class="attr">href</code> attribute:</p>
<pre class="sample">var context = bender.create_context(document.body);
context.appendChild(context.$("use", { href: ... }));</pre>
</section>
</section>
<section id="todo">
<h2>TODO</h2>
<section id="todo.bugs">
<h3>Bugs</h3>
<ol>
<li id="bug.1" class="done">Watch activation (at get level?) and
loops</li>
<li id="bug.2"><span class="done">Watch nesting</span>: see watch
combinators in TODO list.</li>
<li id="bug.3" class="done">Calculator: <code>m</code> never set
properly</li>
<li id="bug.4" class="done">Waves/arrows rendering loop</li>
<li id="bug.5" class="done">Instantiate watches even if
sub-components need loading (<a
href="lib/run.html?href=../tests/scope-remove.xml">test</a>)</li>
<li id="bug.6">Initialization of parameters; see for instance
different values for <a
href="lib/run.html?href=../tests/watch-loop.xml">the loop test</a>
and <a href="lib/params.html?href=../tests/watch-loop.xml">the same
with parameters</a>.</li>
<li id="bug.7" class="done">Rendering of the <a
href="lib/params.html?href=../apps/clock.xml">clock with
parameters</a> fails (also calculator, same problem most
likely: has to do with component loading.)</li>
<li id="bug.8">Rendering vs. updating components (<a
href="lib/run.html?href=../tests/refresh-property.xml">test
case</a>)</li>
<li id="bug.9">View <code class="attr">id</code>s as
<code class="elem">content</code> inside <code
class="elem">use</code> elements? <strong>Reopened</strong> for
more than one level (see <a
href="lib/run.html?href=../apps/custom-calc.xml">custom
calculator</a>)</li>
<li id="bug.10" class="done">Placeholder nodes are not deleted.</li>
<li id="bug.11" class="done">Calculator: 1+2+3+= is 9, should be
6.</li>
</ol>
</section>
<section id="todo.features">
<h3>Features</h3>
<ul>
<li>Add a <code class="attr">href</code> attribute to <code
class="elem">script</code> elements to load external scripts.</li>
<li>Add a <code class="attr">href</code> attribute to <code
class="elem">component</code> elements so that components that are
reused throughout an application can be "imported" into the current
document and referred to by a local id rather than complete
URL.</li>
<li>Add a <code class="attr">href</code> attribute to <code
class="elem">get</code> elements to listen to URLs. Fetched at
initialization, then respond to server events.</li>
<li>Allow several <code class="elem">content</code> elements inside
<code class="elem">view</code>, each with an <code
class="attr">id</code> attribute; then, allow <code
class="elem">content</code> inside <code class="elem">use</code>
elements with a <code class="attr">ref</code> attribute to refere to
a specific content element.</code>
<li>Add a <code class="attr">name</code> attribute to <code
class="elem">content</code> elements for several named content
slots.</li>
<li>Signals?</li>
<li>Watch conditionals</li>
<li>Watch combinators</li>
<li class="done">Clone a component (like <code>Object.create</code>)
to modify an instance of the component rather than all of them.</li>
<li>More metadata: <code class="elem">property</code> and <code
class="elem">event</code> elements to describe properties and
events for a component so that specific tools can access them (e.g.
for the params bar.) Additionally a <code
class="elem">metadata</code> element could be introduced to group
metatadata in components.</li>
<li class="done">Attributes of the <code class="elem">content</code>
node are passed to the rendered nodes (like <code
class="elem">use</code>.) See <a
href="lib/run.html?href=../tests/svg-button.xml">SVG Button test
case</a> (related: <a href="#bug.9"/>bug #9</a>)</li>
<li>Easier component sub-classing, including through markup.</li>
<li><code class="elem">template</code> elements and <code
class="attr">derive</code> attributes to implement _clone_node
declaratively.</li>
<li>Restrict value ranges for properties (min/max, choice,
etc.)</li>
</ul>
</section>
<section id="todo.components">
<h3>Components</h3>
<ul>
<li>Params bar should have an "about" button displaying the content
of the <code class="elem">desc</code> of the running app.</li>
</ul>
</section>
<section id="todo.misc">
<h3>Miscellaneous</h3>
<ul>
<li>Component for logo instead of raw SVG</li>
</ul>
</section>
</section>
</div>
<aside class="g4">
<section id="demos">
<h2>Demos</h2>
<ol>
<li><a href="lib/params.html?href=../apps/logo.xml">Logo</a></li>
<li><a href="lib/params.html?href=../apps/clock.xml">SVG
Clock</a></li>
<li><a href="lib/params.html?href=../apps/arrows.xml">SVG
Arrows</a></li>
<li><a
href="lib/params.html?href=../apps/ttfd.xml">Transition Timing
Function Designer</a></li>
<li><a
href="lib/params.html?href=../apps/calculator.xml">Calculator</a></li>
<li><a
href="lib/params.html?href=../apps/custom-calc.xml">Customizable
Calculator</a> (work in progress)</li>
</ol>
</section>
<section id="library">
<h2>Library</h2>
<ul>
<li><a href="lib/run.html">Simple runtime</a>: a virtual <code
class="elem">use</code> element; specify a <code
class="attr">href</code> paremeter to load a Bender XML file
(<em>e.g.</em>, <a href="lib/run.html?href=../tests/hello.xml">Hello,
world</a>)</li>
<li><a href="lib/params.html">Runtime with parameters bar</a>: create
controls to modify the top-level parameters of the application. Use
the <code class="attr">href</code> attribute as well (see applications
above for examples.)</li>
<li><a href="lib/tree.html">Runtime with dynamic tree view</a>: show
the tree of the application running (<span class="TODO">and edit the
tree</span>.) Use the <code class="attr">href</code> attribute as
well (see applications above for examples; a <a
href="lib/tree.html?href=../tests/control2.xml">simple
example</a>.)</li>
<li><a
href="https://github.com/bendr/bender/blob/master/lib/button.xml">Button</a></li>
<li><a
href="https://github.com/bendr/bender/blob/master/lib/drag.xml">Draggable
object</a></li>
<li><a
href="https://github.com/bendr/bender/blob/master/lib/geolocation.xml">Geolocation
component</a></li>
<li><a
href="https://github.com/bendr/bender/blob/master/lib/movable.xml">Movable
component</a></li>
<li><a class="TODO"
href="https://github.com/bendr/bender/blob/master/lib/resizable.xml">Resizable component</a></li>
<li><a
href="https://github.com/bendr/bender/blob/master/lib/timer.xml">Timer</a></li>
</ul>
</section>
<section id="tests">
<h2>Tests</h2>
<ol>
<li><a href="tests/hello.svg">Hello, world!</a>: display the text
"Hello, world!" in SVG</li>
<li><a href="tests/hello.html">Hello, world!</a>: display the text
"Hello, world!" in HTML</li>
<li><a href="tests/hello_load.html">Hello, world!</a>: display the
text "Hello, world!" in HTML; loaded from an XML document.</li>
<li><a href="tests/disappearer.html">Disappearer</a>: same as above
but the content is quickly removed from the tree and as a result
disappears.</li>
<li><a href="tests/insert.html">Insert</a>: insert a Bender node in an
existing document.</li>
<li><a href="tests/title.html">Title setting and updating</a>: the
title bar should read "Newest title".</li>
<li><a href="lib/run.html?href=../tests/order.xml">Order of
definition</a> does not matter as long a component is referred to
in the same loading context.</li>
<li><a href="tests/use.html">Nested use modified at runtime</a>:
display A, B, C followed by - - - with 2 horizontal lines under each
and = = = between the horizontal lines</li>
<li><a href="tests/set_attr.html">Setting attributes at runtime</a>:
the letter A should become red.</li>
<li><a href="tests/add.html">Adding and removing components</a>:
display 5 paragraphs: "This is a p.", "This is a q.", "(with an extra
line)", "This one is added after rendering.", "(with an extra
line)"</li>
<li><a href="tests/calculator.html">Calculator (inactive buttons)</a>:
display a calculator and its buttons</li>
<li><a href="tests/timer.html">Timer component</a>: timer (script and
properties)</li>
<li><a href="tests/button.html">Button component</a>: display three
buttons "OK", "Cancel", "Retry"; generate an alert when clicked.</li>
<li><a href="tests/button_style.html">Button with style</a>: same but
OK is bold and Cancel is semi-transparent.</li>
<li><a href="tests/lib.html">Loading components from the
library</a></li>
<li><a href="lib/run.html?href=../tests/lib.xml">Loading components
from the library</a>: from an XML file.</li>
<li><a href="tests/render-order.html">Ordering of components</a></li>
<li><a href="tests/load-order.html">Ordering of components</a>: when
some need to be loaded</li>
<li><a href="lib/run.html?href=../tests/load-order.xml">Ordering of
components</a>: when some need to be loaded (from XML)</li>
<li><a href="lib/run.html?href=../tests/watch-property.xml">Watch a
property</a></li>
<li><a href="lib/params.html?href=../tests/watch-properties.xml">Watch
two properties</a> (simple tests for param bar)</li>
<li><a href="lib/run.html?href=../tests/watch-transform.xml">Watch a
property</a> with a transform (roman numbers)</li>
<li><a href="lib/run.html?href=../tests/watch-xy.xml">Watch a
property and set a property</a> creating a simple chain
reaction.</li>
<li><a href="lib/run.html?href=../tests/watch-xyz.xml">Watch a
property and set a cascade</a> of properties.</li>
<li><a href="lib/run.html?href=../tests/watch-loop.xml">Watch a
property and set a cascade</a> with a loop. <span
class="TODO">Review initialization of parameters.</span></li>
<li><a href="lib/run.html?href=../tests/textfield.xml">Text
fields</a></li>
<li><a href="lib/run.html?href=../tests/scope.xml">Scope test</a>:
getting/setting properties from the nearest ancestor</li>
<li><a href="lib/run.html?href=../tests/scope-remove.xml">Scope test
with component removal</a></li>
<li><a href="lib/run.html?href=../tests/control.xml">Control</a> the
size of a component from another component through a shared ancestor's
property.</li>
<li><a href="lib/run.html?href=../tests/control2.xml">Control (2)</a>
the number of elements</li>
<li><a href="lib/run.html?href=../tests/control3.xml">Control (3)</a>
the number of components</li>
<li><a href="lib/run.html?href=../tests/timer.xml">Timer</a> just
output to the console</li>
<li><a href="lib/params.html?href=../tests/waves.xml">Waves</a></li>
<li><a href="tests/rendered.html">@rendered event test</a> (HTML)</li>
<li><a href="lib/run.html?href=../tests/rendered.xml">@rendered event
test</a> (XML)</li>
<li><a href="lib/run.html?href=../tests/geolocation.xml">Geolocation
component test</a></li>
<li><a href="lib/run.html?href=../tests/svg-button.xml">SVG Button</a>
with button template.</li>
<li><a class="broken"
href="lib/run.html?href=../tests/refresh-property.xml">Refresh
application after properties have changed</a></li>
<li><a href="lib/run.html?href=../tests/drag.xml">Drag
component</a></li>
<li><a
href="lib/params.html?href=../tests/bezier.xml">Bézier
curve</a></li>
<li><a href="lib/params.html?href=../tests/parse_property.xml">Parsing
properties</a></li>
</ol>
</section>
</aside>
<div class="clear"></div>
<footer id="copyright">Copyright © 2011, 2012,
<a href="http://www.igel.co.jp/">IGEL Co., Ltd.</a></footer>
<script>
var context = bender.create_context();
context._insert_use({ href: "tests/welcome.xml" },
document.getElementById("welcome"));
</script>
</body>
</html>