12 次代碼提交 c6acbbfe91 ... a62cd6ccfc

作者 SHA1 備註 提交日期
  Herby Vojčík a62cd6ccfc 0.6.1 4 年之前
  Herby Vojčík 1c6b30f906 Recompile. 4 年之前
  Herby Vojčík 5bd74352dc 0.6.0 4 年之前
  Herby Vojčík e83bee7800 Recompile with new .js format. 4 年之前
  Herby Vojčík b77c22cc38 Typo. 4 年之前
  Herby Vojčík f01197b6f8 Revert "0.5.2" 4 年之前
  Herby Vojčík 1b85f2e8c7 0.5.2 4 年之前
  Herby Vojčík 8133da940a Convenience: #newSvgElement. 4 年之前
  Herby Vojčík 62510df349 Extract trait TSilkBuilder. 4 年之前
  Herby Vojčík e05851970e Compile. 4 年之前
  Herby Vojčík 57aae161e3 Merge branch 'xmlnsAddon' of Christian/silk into master 4 年之前
  Christian Haider b273123456 added xml namespace extension 4 年之前
共有 4 個文件被更改,包括 440 次插入327 次删除
  1. 2 2
      package.json
  2. 158 164
      src/Silk-Tests.js
  3. 214 148
      src/Silk.js
  4. 66 13
      src/Silk.st

+ 2 - 2
package.json

@@ -2,7 +2,7 @@
   "name": "@ambers/silk",
   "title": "Stream-based mochikit-inspired in-page Web framework",
   "description": "Stream-based, mochikit-inspired framework for creating and manipulating contents of a page. For Amber Smalltalk.",
-  "version": "0.5.1",
+  "version": "0.6.1",
   "homepage": "https://lolg.it/herby/silk",
   "author": {
     "name": "Herbert Vojčík",
@@ -31,7 +31,7 @@
     "test": "grunt test"
   },
   "dependencies": {
-    "@ambers/lang": ">0.22.6",
+    "@ambers/lang": ">=0.24.0",
     "@ambers/domite": "^0.9.0"
   },
   "devDependencies": {

+ 158 - 164
src/Silk-Tests.js

@@ -13,11 +13,6 @@ $core.addMethod(
 $core.method({
 selector: "testedClass",
 protocol: "fixture",
-fn: function (){
-var self=this,$self=this;
-return $globals.Silk;
-
-},
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
 source: "testedClass\x0a\x09^ Silk",
@@ -25,7 +20,11 @@ referencedClasses: ["Silk"],
 //>>excludeEnd("ide");
 pragmas: [],
 messageSends: []
-}),
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+return $globals.Silk;
+
+}; }),
 $globals.SilkInheritedTest);
 
 
@@ -35,61 +34,67 @@ $core.addMethod(
 $core.method({
 selector: "assertBodyEndsWith:",
 protocol: "fixture",
-fn: function (aString){
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aString"],
+source: "assertBodyEndsWith: aString\x0a\x09| sanitizedBody sanitizedAssertion |\x0a\x09sanitizedBody := document body innerHTML replace: '\x5cs*' with: ''.\x0a\x09sanitizedAssertion := aString replace: '\x5cs*' with: ''.\x0a\x09self assert: sanitizedBody size >= sanitizedAssertion size.\x0a\x09self\x0a\x09\x09assert: (sanitizedBody last: sanitizedAssertion size)\x0a\x09\x09equals: sanitizedAssertion",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["replace:with:", "innerHTML", "body", "assert:", ">=", "size", "assert:equals:", "last:"]
+}, function ($methodClass){ return function (aString){
 var self=this,$self=this;
 var sanitizedBody,sanitizedAssertion;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $2,$3,$1;
-sanitizedBody=$recv($recv($recv(document)._body())._innerHTML())._replace_with_("\x5cs*","");
+sanitizedBody=[$recv($recv($recv(document)._body())._innerHTML())._replace_with_("\x5cs*","")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["replace:with:"]=1;
+,$ctx1.sendIdx["replace:with:"]=1
 //>>excludeEnd("ctx");
+][0];
 sanitizedAssertion=$recv(aString)._replace_with_("\x5cs*","");
-$2=$recv(sanitizedBody)._size();
+$self._assert_($recv([$recv(sanitizedBody)._size()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["size"]=1;
+,$ctx1.sendIdx["size"]=1
 //>>excludeEnd("ctx");
-$3=$recv(sanitizedAssertion)._size();
+][0]).__gt_eq([$recv(sanitizedAssertion)._size()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["size"]=2;
+,$ctx1.sendIdx["size"]=2
 //>>excludeEnd("ctx");
-$1=$recv($2).__gt_eq($3);
-$self._assert_($1);
+][0]));
 $self._assert_equals_($recv(sanitizedBody)._last_($recv(sanitizedAssertion)._size()),sanitizedAssertion);
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"assertBodyEndsWith:",{aString:aString,sanitizedBody:sanitizedBody,sanitizedAssertion:sanitizedAssertion})});
 //>>excludeEnd("ctx");
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: ["aString"],
-source: "assertBodyEndsWith: aString\x0a\x09| sanitizedBody sanitizedAssertion |\x0a\x09sanitizedBody := document body innerHTML replace: '\x5cs*' with: ''.\x0a\x09sanitizedAssertion := aString replace: '\x5cs*' with: ''.\x0a\x09self assert: sanitizedBody size >= sanitizedAssertion size.\x0a\x09self\x0a\x09\x09assert: (sanitizedBody last: sanitizedAssertion size)\x0a\x09\x09equals: sanitizedAssertion",
-referencedClasses: [],
-//>>excludeEnd("ide");
-pragmas: [],
-messageSends: ["replace:with:", "innerHTML", "body", "assert:", ">=", "size", "assert:equals:", "last:"]
-}),
+}; }),
 $globals.SilkTest);
 
 $core.addMethod(
 $core.method({
 selector: "assertBodyEndsWithOneOf:",
 protocol: "fixture",
-fn: function (aStringArray){
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aStringArray"],
+source: "assertBodyEndsWithOneOf: aStringArray\x0a\x09| sanitizedBody err |\x0a\x09sanitizedBody := document body innerHTML replace: '\x5cs*' with: ''.\x0a\x09aStringArray do: [ :aString |\x0a\x09\x09| sanitizedAssertion |\x0a\x09\x09sanitizedAssertion := aString replace: '\x5cs*' with: ''.\x0a\x09\x09[ self\x0a\x09\x09\x09assert: sanitizedBody size >= sanitizedAssertion size;\x0a\x09\x09\x09assert: (sanitizedBody last: sanitizedAssertion size)\x0a\x09\x09\x09equals: sanitizedAssertion. ^ self ] on: Error do: [ :e | err := e ]].\x0a\x09err ifNotNil: [ err signal ]",
+referencedClasses: ["Error"],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["replace:with:", "innerHTML", "body", "do:", "on:do:", "assert:", ">=", "size", "assert:equals:", "last:", "ifNotNil:", "signal"]
+}, function ($methodClass){ return function (aStringArray){
 var self=this,$self=this;
 var sanitizedBody,err;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $2,$3,$1,$4,$receiver;
+var $1;
 var $early={};
 try {
-sanitizedBody=$recv($recv($recv(document)._body())._innerHTML())._replace_with_("\x5cs*","");
+sanitizedBody=[$recv($recv($recv(document)._body())._innerHTML())._replace_with_("\x5cs*","")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["replace:with:"]=1;
+,$ctx1.sendIdx["replace:with:"]=1
 //>>excludeEnd("ctx");
+][0];
 $recv(aStringArray)._do_((function(aString){
 var sanitizedAssertion;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -100,16 +105,15 @@ return $recv((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx3) {
 //>>excludeEnd("ctx");
-$2=$recv(sanitizedBody)._size();
+$self._assert_($recv([$recv(sanitizedBody)._size()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx3.sendIdx["size"]=1;
+,$ctx3.sendIdx["size"]=1
 //>>excludeEnd("ctx");
-$3=$recv(sanitizedAssertion)._size();
+][0]).__gt_eq([$recv(sanitizedAssertion)._size()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx3.sendIdx["size"]=2;
+,$ctx3.sendIdx["size"]=2
 //>>excludeEnd("ctx");
-$1=$recv($2).__gt_eq($3);
-$self._assert_($1);
+][0]));
 $self._assert_equals_($recv(sanitizedBody)._last_($recv(sanitizedAssertion)._size()),sanitizedAssertion);
 throw $early=[self];
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -124,9 +128,9 @@ return err;
 }, function($ctx2) {$ctx2.fillBlock({aString:aString,sanitizedAssertion:sanitizedAssertion},$ctx1,1)});
 //>>excludeEnd("ctx");
 }));
-$4=err;
-if(($receiver = $4) == null || $receiver.a$nil){
-$4;
+$1=err;
+if($1 == null || $1.a$nil){
+$1;
 } else {
 $recv(err)._signal();
 }
@@ -136,22 +140,21 @@ catch(e) {if(e===$early)return e[0]; throw e}
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"assertBodyEndsWithOneOf:",{aStringArray:aStringArray,sanitizedBody:sanitizedBody,err:err})});
 //>>excludeEnd("ctx");
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: ["aStringArray"],
-source: "assertBodyEndsWithOneOf: aStringArray\x0a\x09| sanitizedBody err |\x0a\x09sanitizedBody := document body innerHTML replace: '\x5cs*' with: ''.\x0a\x09aStringArray do: [ :aString |\x0a\x09\x09| sanitizedAssertion |\x0a\x09\x09sanitizedAssertion := aString replace: '\x5cs*' with: ''.\x0a\x09\x09[ self\x0a\x09\x09\x09assert: sanitizedBody size >= sanitizedAssertion size;\x0a\x09\x09\x09assert: (sanitizedBody last: sanitizedAssertion size)\x0a\x09\x09\x09equals: sanitizedAssertion. ^ self ] on: Error do: [ :e | err := e ]].\x0a\x09err ifNotNil: [ err signal ]",
-referencedClasses: ["Error"],
-//>>excludeEnd("ide");
-pragmas: [],
-messageSends: ["replace:with:", "innerHTML", "body", "do:", "on:do:", "assert:", ">=", "size", "assert:equals:", "last:", "ifNotNil:", "signal"]
-}),
+}; }),
 $globals.SilkTest);
 
 $core.addMethod(
 $core.method({
 selector: "setUp",
 protocol: "fixture",
-fn: function (){
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "setUp\x0a\x09fixtureDiv := document createElement: 'div'.\x0a\x09document body appendChild: fixtureDiv.\x0a\x09fixtureDiv setAttribute: 'id' to: 'fixture'.\x0a\x09fixtureDiv innerHTML: 'sentinel'",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["createElement:", "appendChild:", "body", "setAttribute:to:", "innerHTML:"]
+}, function ($methodClass){ return function (){
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
@@ -164,55 +167,52 @@ return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"setUp",{})});
 //>>excludeEnd("ctx");
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "setUp\x0a\x09fixtureDiv := document createElement: 'div'.\x0a\x09document body appendChild: fixtureDiv.\x0a\x09fixtureDiv setAttribute: 'id' to: 'fixture'.\x0a\x09fixtureDiv innerHTML: 'sentinel'",
-referencedClasses: [],
-//>>excludeEnd("ide");
-pragmas: [],
-messageSends: ["createElement:", "appendChild:", "body", "setAttribute:to:", "innerHTML:"]
-}),
+}; }),
 $globals.SilkTest);
 
 $core.addMethod(
 $core.method({
 selector: "tearDown",
 protocol: "fixture",
-fn: function (){
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "tearDown\x0a\x09| lastChild |\x0a\x09lastChild := document body lastChild.\x0a\x09self assert: lastChild equals: fixtureDiv.\x0a\x09document body removeChild: lastChild",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["lastChild", "body", "assert:equals:", "removeChild:"]
+}, function ($methodClass){ return function (){
 var self=this,$self=this;
 var lastChild;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1;
-$1=$recv(document)._body();
+lastChild=$recv([$recv(document)._body()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["body"]=1;
+,$ctx1.sendIdx["body"]=1
 //>>excludeEnd("ctx");
-lastChild=$recv($1)._lastChild();
+][0])._lastChild();
 $self._assert_equals_(lastChild,$self.fixtureDiv);
 $recv($recv(document)._body())._removeChild_(lastChild);
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"tearDown",{lastChild:lastChild})});
 //>>excludeEnd("ctx");
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "tearDown\x0a\x09| lastChild |\x0a\x09lastChild := document body lastChild.\x0a\x09self assert: lastChild equals: fixtureDiv.\x0a\x09document body removeChild: lastChild",
-referencedClasses: [],
-//>>excludeEnd("ide");
-pragmas: [],
-messageSends: ["lastChild", "body", "assert:equals:", "removeChild:"]
-}),
+}; }),
 $globals.SilkTest);
 
 $core.addMethod(
 $core.method({
 selector: "testInsertTable",
 protocol: "testing",
-fn: function (){
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "testInsertTable\x0a\x0a\x09| d tbl  |\x0a\x0a\x09d := 'html body div#fixture' asSilk.\x0a\x0a\x09tbl := d TABLE.\x0a\x0a\x09tbl TR\x0a\x09\x09TD: 'A';\x0a\x09\x09TD: 'B';\x0a\x09\x09TD: 'C'.\x0a\x09\x0a\x09tbl TR\x0a\x09\x09TD: 'D';\x0a\x09\x09TD: 'E';\x0a\x09\x09TD: 'F'.\x0a\x09\x0a\x09self assertBodyEndsWith: '>sentinel<table><tr><td>A</td><td>B</td><td>C</td></tr><tr><td>D</td><td>E</td><td>F</td></tr></table></div>'",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["asSilk", "TABLE", "TD:", "TR", "assertBodyEndsWith:"]
+}, function ($methodClass){ return function (){
 var self=this,$self=this;
 var d,tbl;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -221,163 +221,166 @@ return $core.withContext(function($ctx1) {
 var $1,$2;
 d="html body div#fixture"._asSilk();
 tbl=$recv(d)._TABLE();
-$1=$recv(tbl)._TR();
+$1=[$recv(tbl)._TR()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["TR"]=1;
+,$ctx1.sendIdx["TR"]=1
 //>>excludeEnd("ctx");
-$recv($1)._TD_("A");
+][0];
+[$recv($1)._TD_("A")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["TD:"]=1;
+,$ctx1.sendIdx["TD:"]=1
 //>>excludeEnd("ctx");
-$recv($1)._TD_("B");
+][0];
+[$recv($1)._TD_("B")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["TD:"]=2;
+,$ctx1.sendIdx["TD:"]=2
 //>>excludeEnd("ctx");
-$recv($1)._TD_("C");
+][0];
+[$recv($1)._TD_("C")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["TD:"]=3;
+,$ctx1.sendIdx["TD:"]=3
 //>>excludeEnd("ctx");
+][0];
 $2=$recv(tbl)._TR();
-$recv($2)._TD_("D");
+[$recv($2)._TD_("D")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["TD:"]=4;
+,$ctx1.sendIdx["TD:"]=4
 //>>excludeEnd("ctx");
-$recv($2)._TD_("E");
+][0];
+[$recv($2)._TD_("E")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["TD:"]=5;
+,$ctx1.sendIdx["TD:"]=5
 //>>excludeEnd("ctx");
+][0];
 $recv($2)._TD_("F");
 $self._assertBodyEndsWith_(">sentinel<table><tr><td>A</td><td>B</td><td>C</td></tr><tr><td>D</td><td>E</td><td>F</td></tr></table></div>");
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"testInsertTable",{d:d,tbl:tbl})});
 //>>excludeEnd("ctx");
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "testInsertTable\x0a\x0a\x09| d tbl  |\x0a\x0a\x09d := 'html body div#fixture' asSilk.\x0a\x0a\x09tbl := d TABLE.\x0a\x0a\x09tbl TR\x0a\x09\x09TD: 'A';\x0a\x09\x09TD: 'B';\x0a\x09\x09TD: 'C'.\x0a\x09\x0a\x09tbl TR\x0a\x09\x09TD: 'D';\x0a\x09\x09TD: 'E';\x0a\x09\x09TD: 'F'.\x0a\x09\x0a\x09self assertBodyEndsWith: '>sentinel<table><tr><td>A</td><td>B</td><td>C</td></tr><tr><td>D</td><td>E</td><td>F</td></tr></table></div>'",
-referencedClasses: [],
-//>>excludeEnd("ide");
-pragmas: [],
-messageSends: ["asSilk", "TABLE", "TD:", "TR", "assertBodyEndsWith:"]
-}),
+}; }),
 $globals.SilkTest);
 
 $core.addMethod(
 $core.method({
 selector: "testInsertTable2",
 protocol: "testing",
-fn: function (){
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "testInsertTable2\x0a\x0a\x09| d tbl  |\x0a\x0a\x09d := 'html body div#fixture' asSilk.\x0a\x0a\x09tbl := d TABLE.\x0a\x0a\x09tbl TR: {\x0a\x09\x09Silk TD: 'A'.\x0a\x09\x09Silk TD: 'B'.\x0a\x09\x09Silk TD: 'C'};\x0a\x09\x09TR: {\x0a\x09\x09Silk TD: 'D'.\x0a\x09\x09Silk TD: 'E'.\x0a\x09\x09Silk TD: 'F'}.\x0a\x09\x0a\x09self assertBodyEndsWith: '>sentinel<table><tr><td>A</td><td>B</td><td>C</td></tr><tr><td>D</td><td>E</td><td>F</td></tr></table></div>'",
+referencedClasses: ["Silk"],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["asSilk", "TABLE", "TR:", "TD:", "assertBodyEndsWith:"]
+}, function ($methodClass){ return function (){
 var self=this,$self=this;
 var d,tbl;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1,$3,$4,$5,$2,$7,$8,$6;
+var $1;
 d="html body div#fixture"._asSilk();
 tbl=$recv(d)._TABLE();
 $1=tbl;
-$3=$recv($globals.Silk)._TD_("A");
+[$recv($1)._TR_([[$recv($globals.Silk)._TD_("A")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["TD:"]=1;
+,$ctx1.sendIdx["TD:"]=1
 //>>excludeEnd("ctx");
-$4=$recv($globals.Silk)._TD_("B");
+][0],[$recv($globals.Silk)._TD_("B")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["TD:"]=2;
+,$ctx1.sendIdx["TD:"]=2
 //>>excludeEnd("ctx");
-$5=$recv($globals.Silk)._TD_("C");
+][0],[$recv($globals.Silk)._TD_("C")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["TD:"]=3;
+,$ctx1.sendIdx["TD:"]=3
 //>>excludeEnd("ctx");
-$2=[$3,$4,$5];
-$recv($1)._TR_($2);
+][0]])
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["TR:"]=1;
+,$ctx1.sendIdx["TR:"]=1
 //>>excludeEnd("ctx");
-$7=$recv($globals.Silk)._TD_("D");
+][0];
+$recv($1)._TR_([[$recv($globals.Silk)._TD_("D")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["TD:"]=4;
+,$ctx1.sendIdx["TD:"]=4
 //>>excludeEnd("ctx");
-$8=$recv($globals.Silk)._TD_("E");
+][0],[$recv($globals.Silk)._TD_("E")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["TD:"]=5;
+,$ctx1.sendIdx["TD:"]=5
 //>>excludeEnd("ctx");
-$6=[$7,$8,$recv($globals.Silk)._TD_("F")];
-$recv($1)._TR_($6);
+][0],$recv($globals.Silk)._TD_("F")]);
 $self._assertBodyEndsWith_(">sentinel<table><tr><td>A</td><td>B</td><td>C</td></tr><tr><td>D</td><td>E</td><td>F</td></tr></table></div>");
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"testInsertTable2",{d:d,tbl:tbl})});
 //>>excludeEnd("ctx");
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "testInsertTable2\x0a\x0a\x09| d tbl  |\x0a\x0a\x09d := 'html body div#fixture' asSilk.\x0a\x0a\x09tbl := d TABLE.\x0a\x0a\x09tbl TR: {\x0a\x09\x09Silk TD: 'A'.\x0a\x09\x09Silk TD: 'B'.\x0a\x09\x09Silk TD: 'C'};\x0a\x09\x09TR: {\x0a\x09\x09Silk TD: 'D'.\x0a\x09\x09Silk TD: 'E'.\x0a\x09\x09Silk TD: 'F'}.\x0a\x09\x0a\x09self assertBodyEndsWith: '>sentinel<table><tr><td>A</td><td>B</td><td>C</td></tr><tr><td>D</td><td>E</td><td>F</td></tr></table></div>'",
-referencedClasses: ["Silk"],
-//>>excludeEnd("ide");
-pragmas: [],
-messageSends: ["asSilk", "TABLE", "TR:", "TD:", "assertBodyEndsWith:"]
-}),
+}; }),
 $globals.SilkTest);
 
 $core.addMethod(
 $core.method({
 selector: "testNestedDIVsWithAttributes",
 protocol: "testing",
-fn: function (){
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "testNestedDIVsWithAttributes\x0a \x22demonstrates how DIVs are nested and given attributes\x22\x0a\x09| s |\x0a\x0a\x09s := '#fixture' asSilk.\x0a\x09\x0a\x09s := s DIV << ('id' -> 'container') << ('class' -> 'mySilkContainerClass').\x0a\x09s DIV << ('id' -> 'contentarea') << 'here comes the content'.\x0a\x09s := s DIV << ('id' -> 'toolbar') << ('class' -> 'myToolbarClass').\x0a\x09(s BUTTON: 'do something') on: 'click' bind: [Transcript show: 'button pressed'].\x0a\x09\x0a\x09self assertBodyEndsWithOneOf: #(\x0a\x09\x09'>sentinel<div class=\x22mySilkContainerClass\x22 id=\x22container\x22><div id=\x22contentarea\x22>here comes the content</div><div class=\x22myToolbarClass\x22 id=\x22toolbar\x22><button>do something</button></div></div></div>'\x0a\x09\x09'>sentinel<div id=\x22container\x22 class=\x22mySilkContainerClass\x22><div id=\x22contentarea\x22>here comes the content</div><div id=\x22toolbar\x22 class=\x22myToolbarClass\x22><button>do something</button></div></div></div>'\x0a\x09)",
+referencedClasses: ["Transcript"],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["asSilk", "<<", "DIV", "->", "on:bind:", "BUTTON:", "show:", "assertBodyEndsWithOneOf:"]
+}, function ($methodClass){ return function (){
 var self=this,$self=this;
 var s;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $2,$3,$1,$4,$6,$7,$5,$9,$10,$8;
 s="#fixture"._asSilk();
-$2=$recv(s)._DIV();
+s=[$recv([$recv([$recv(s)._DIV()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["DIV"]=1;
+,$ctx1.sendIdx["DIV"]=1
 //>>excludeEnd("ctx");
-$3="id".__minus_gt("container");
+][0]).__lt_lt(["id".__minus_gt("container")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["->"]=1;
+,$ctx1.sendIdx["->"]=1
 //>>excludeEnd("ctx");
-$1=$recv($2).__lt_lt($3);
+][0])
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["<<"]=2;
+,$ctx1.sendIdx["<<"]=2
 //>>excludeEnd("ctx");
-$4="class".__minus_gt("mySilkContainerClass");
+][0]).__lt_lt(["class".__minus_gt("mySilkContainerClass")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["->"]=2;
+,$ctx1.sendIdx["->"]=2
 //>>excludeEnd("ctx");
-s=$recv($1).__lt_lt($4);
+][0])
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["<<"]=1;
+,$ctx1.sendIdx["<<"]=1
 //>>excludeEnd("ctx");
-$6=$recv(s)._DIV();
+][0];
+[$recv([$recv([$recv(s)._DIV()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["DIV"]=2;
+,$ctx1.sendIdx["DIV"]=2
 //>>excludeEnd("ctx");
-$7="id".__minus_gt("contentarea");
+][0]).__lt_lt(["id".__minus_gt("contentarea")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["->"]=3;
+,$ctx1.sendIdx["->"]=3
 //>>excludeEnd("ctx");
-$5=$recv($6).__lt_lt($7);
+][0])
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["<<"]=4;
+,$ctx1.sendIdx["<<"]=4
 //>>excludeEnd("ctx");
-$recv($5).__lt_lt("here comes the content");
+][0]).__lt_lt("here comes the content")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["<<"]=3;
+,$ctx1.sendIdx["<<"]=3
 //>>excludeEnd("ctx");
-$9=$recv(s)._DIV();
-$10="id".__minus_gt("toolbar");
+][0];
+s=[$recv($recv($recv(s)._DIV()).__lt_lt(["id".__minus_gt("toolbar")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["->"]=4;
+,$ctx1.sendIdx["->"]=4
 //>>excludeEnd("ctx");
-$8=$recv($9).__lt_lt($10);
-s=$recv($8).__lt_lt("class".__minus_gt("myToolbarClass"));
+][0])).__lt_lt("class".__minus_gt("myToolbarClass"))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["<<"]=5;
+,$ctx1.sendIdx["<<"]=5
 //>>excludeEnd("ctx");
+][0];
 $recv($recv(s)._BUTTON_("do something"))._on_bind_("click",(function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
@@ -392,22 +395,21 @@ return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"testNestedDIVsWithAttributes",{s:s})});
 //>>excludeEnd("ctx");
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "testNestedDIVsWithAttributes\x0a \x22demonstrates how DIVs are nested and given attributes\x22\x0a\x09| s |\x0a\x0a\x09s := '#fixture' asSilk.\x0a\x09\x0a\x09s := s DIV << ('id' -> 'container') << ('class' -> 'mySilkContainerClass').\x0a\x09s DIV << ('id' -> 'contentarea') << 'here comes the content'.\x0a\x09s := s DIV << ('id' -> 'toolbar') << ('class' -> 'myToolbarClass').\x0a\x09(s BUTTON: 'do something') on: 'click' bind: [Transcript show: 'button pressed'].\x0a\x09\x0a\x09self assertBodyEndsWithOneOf: #(\x0a\x09\x09'>sentinel<div class=\x22mySilkContainerClass\x22 id=\x22container\x22><div id=\x22contentarea\x22>here comes the content</div><div class=\x22myToolbarClass\x22 id=\x22toolbar\x22><button>do something</button></div></div></div>'\x0a\x09\x09'>sentinel<div id=\x22container\x22 class=\x22mySilkContainerClass\x22><div id=\x22contentarea\x22>here comes the content</div><div id=\x22toolbar\x22 class=\x22myToolbarClass\x22><button>do something</button></div></div></div>'\x0a\x09)",
-referencedClasses: ["Transcript"],
-//>>excludeEnd("ide");
-pragmas: [],
-messageSends: ["asSilk", "<<", "DIV", "->", "on:bind:", "BUTTON:", "show:", "assertBodyEndsWithOneOf:"]
-}),
+}; }),
 $globals.SilkTest);
 
 $core.addMethod(
 $core.method({
 selector: "testOnClickEvent",
 protocol: "testing",
-fn: function (){
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "testOnClickEvent\x0a\x09\x22#on:bind\x22\x0a\x09\x0a\x09| s para |\x0a\x0a\x09s := '#fixture' asSilk.\x0a\x09para := s P: 'DOM'. \x0a\x0a\x09self timeout: 100.\x0a\x0a\x09(self async: [para on: 'click' bind:\x0a\x09\x09\x09[\x22Test successful\x22 self finished].\x0a\x0a\x09\x09'#fixture p' asJQuery trigger: 'click'.\x0a\x09\x09]) fork",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["asSilk", "P:", "timeout:", "fork", "async:", "on:bind:", "finished", "trigger:", "asJQuery"]
+}, function ($methodClass){ return function (){
 var self=this,$self=this;
 var s,para;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -438,15 +440,7 @@ return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"testOnClickEvent",{s:s,para:para})});
 //>>excludeEnd("ctx");
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "testOnClickEvent\x0a\x09\x22#on:bind\x22\x0a\x09\x0a\x09| s para |\x0a\x0a\x09s := '#fixture' asSilk.\x0a\x09para := s P: 'DOM'. \x0a\x0a\x09self timeout: 100.\x0a\x0a\x09(self async: [para on: 'click' bind:\x0a\x09\x09\x09[\x22Test successful\x22 self finished].\x0a\x0a\x09\x09'#fixture p' asJQuery trigger: 'click'.\x0a\x09\x09]) fork",
-referencedClasses: [],
-//>>excludeEnd("ide");
-pragmas: [],
-messageSends: ["asSilk", "P:", "timeout:", "fork", "async:", "on:bind:", "finished", "trigger:", "asJQuery"]
-}),
+}; }),
 $globals.SilkTest);
 
 

+ 214 - 148
src/Silk.js

@@ -10,66 +10,81 @@ $globals.Silk.comment="I am subclass of `Domite` with more convenient high-level
 //>>excludeEnd("ide");
 $core.addMethod(
 $core.method({
-selector: "doesNotUnderstand:",
-protocol: "writing",
-fn: function (aMessage){
+selector: "namespace",
+protocol: "accessing",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "namespace\x0a\x09\x22<String>\x0a\x09XML namespace for elements: html.\x0a\x09The default for all virtual Silk tag messages\x22\x0a\x09\x0a\x09^ self element namespaceURI",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["namespaceURI", "element"]
+}, function ($methodClass){ return function (){
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1,$2,$receiver;
-$1=$recv($self._class())._tryMakeDnuElement_(aMessage);
-if(($receiver = $1) == null || $receiver.a$nil){
-$2=(
+return $recv($self._element())._namespaceURI();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.supercall = true,
+}, function($ctx1) {$ctx1.fill(self,"namespace",{})});
 //>>excludeEnd("ctx");
-($globals.Silk.superclass||$boot.nilAsClass).fn.prototype._doesNotUnderstand_.apply($self, [aMessage]));
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.supercall = false;
-//>>excludeEnd("ctx");;
-return $2;
-} else {
-var newElement;
-newElement=$receiver;
-$self.__lt_lt(newElement);
-return newElement;
-}
-return self;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"doesNotUnderstand:",{aMessage:aMessage})});
-//>>excludeEnd("ctx");
-},
+}; }),
+$globals.Silk);
+
+$core.addMethod(
+$core.method({
+selector: "newElement:xmlns:",
+protocol: "writing",
 //>>excludeStart("ide", pragmas.excludeIdeData);
-args: ["aMessage"],
-source: "doesNotUnderstand: aMessage\x0a\x09\x22`aSilk DIV` creates a div element and inserts it.\x0a\x09`aSilk DIV: anObject` creates a div element, inserts it\x0a\x09and puts contents in it\x22\x0a\x09(self class tryMakeDnuElement: aMessage)\x0a\x09\x09ifNil: [ ^ super doesNotUnderstand: aMessage ]\x0a\x09\x09ifNotNil: [ :newElement | self << newElement. ^ newElement ]",
+args: ["aString", "anotherString"],
+source: "newElement: aString xmlns: anotherString\x0a\x09| el |\x0a\x09\x0a\x09el := self class newElement: aString xmlns: anotherString.\x0a\x09self << el.\x0a\x09^ el",
 referencedClasses: [],
 //>>excludeEnd("ide");
 pragmas: [],
-messageSends: ["ifNil:ifNotNil:", "tryMakeDnuElement:", "class", "doesNotUnderstand:", "<<"]
-}),
+messageSends: ["newElement:xmlns:", "class", "<<"]
+}, function ($methodClass){ return function (aString,anotherString){
+var self=this,$self=this;
+var el;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+el=$recv($self._class())._newElement_xmlns_(aString,anotherString);
+$self.__lt_lt(el);
+return el;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"newElement:xmlns:",{aString:aString,anotherString:anotherString,el:el})});
+//>>excludeEnd("ctx");
+}; }),
 $globals.Silk);
 
 $core.addMethod(
 $core.method({
 selector: "nextPut:",
 protocol: "writing",
-fn: function (anObject){
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["anObject"],
+source: "nextPut: anObject\x0a\x09\x22Double-dispatches anObject via renderOnSilk: message.\x0a\x09If a message returns nil, this fallbacks to superclass.\x0a\x09Otherwise, it is assumed renderOnSilk: did its job.\x22\x0a\x0a\x09(anObject renderOnSilk: self)\x0a\x09\x09ifNil: [ super nextPut: anObject ]",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["ifNil:", "renderOnSilk:", "nextPut:"]
+}, function ($methodClass){ return function (anObject){
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1,$receiver;
+var $1;
 $1=$recv(anObject)._renderOnSilk_(self);
-if(($receiver = $1) == null || $receiver.a$nil){
-(
+if($1 == null || $1.a$nil){
+[(
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.supercall = true,
 //>>excludeEnd("ctx");
-($globals.Silk.superclass||$boot.nilAsClass).fn.prototype._nextPut_.apply($self, [anObject]));
+($methodClass.superclass||$boot.nilAsClass).fn.prototype._nextPut_.call($self,anObject))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.supercall = false;
-//>>excludeEnd("ctx");;
+,$ctx1.supercall = false
+//>>excludeEnd("ctx");
+][0];
 } else {
 $1;
 }
@@ -77,76 +92,142 @@ return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"nextPut:",{anObject:anObject})});
 //>>excludeEnd("ctx");
-},
+}; }),
+$globals.Silk);
+
+
+$core.addMethod(
+$core.method({
+selector: "htmlNamespace",
+protocol: "accessing",
 //>>excludeStart("ide", pragmas.excludeIdeData);
-args: ["anObject"],
-source: "nextPut: anObject\x0a\x09\x22Double-dispatches anObject via renderOnSilk: message.\x0a\x09If a message returns nil, this fallbacks to superclass.\x0a\x09Otherwise, it is assumed renderOnSilk: did its job.\x22\x0a\x0a\x09(anObject renderOnSilk: self)\x0a\x09\x09ifNil: [ super nextPut: anObject ]",
+args: [],
+source: "htmlNamespace\x0a\x09\x22<String>\x0a\x09XML namespace for HTML elements.\x0a\x09The default for all virtual Silk tag messages\x22\x0a\x09\x0a\x09^ 'http://www.w3.org/1999/xhtml'",
 referencedClasses: [],
 //>>excludeEnd("ide");
 pragmas: [],
-messageSends: ["ifNil:", "renderOnSilk:", "nextPut:"]
-}),
-$globals.Silk);
+messageSends: []
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+return "http://www.w3.org/1999/xhtml";
 
+}; }),
+$globals.Silk.a$cls);
 
+$core.addMethod(
+$core.method({
+selector: "namespace",
+protocol: "accessing",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "namespace\x0a\x09\x22<String>\x0a\x09XML namespace for elements: html.\x0a\x09The default for all virtual Silk tag messages\x22\x0a\x09\x0a\x09^ self htmlNamespace",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["htmlNamespace"]
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+return $self._htmlNamespace();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"namespace",{})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.Silk.a$cls);
+
+
+$core.addTrait("TSilkBuilder", "Silk");
+//>>excludeStart("ide", pragmas.excludeIdeData);
+$globals.TSilkBuilder.comment="I contain Silk's \x22build element via DNU\x22 behaviour.\x0a\x0aI expect #namespace and #newElement:xmlns: to be implemented.";
+//>>excludeEnd("ide");
 $core.addMethod(
 $core.method({
 selector: "doesNotUnderstand:",
 protocol: "message handling",
-fn: function (aMessage){
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aMessage"],
+source: "doesNotUnderstand: aMessage\x0a\x09\x22`self DIV` creates (and optionally inserts) a div element.\x0a\x09`aSilk DIV: anObject` creates (and optionally inserts)\x0a\x09a div element, and puts contents in it\x22\x0a\x09^ (self tryMakeDnuElement: aMessage)\x0a\x09\x09ifNil: [ super doesNotUnderstand: aMessage ]",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["ifNil:", "tryMakeDnuElement:", "doesNotUnderstand:"]
+}, function ($methodClass){ return function (aMessage){
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1,$receiver;
+var $1;
 $1=$self._tryMakeDnuElement_(aMessage);
-if(($receiver = $1) == null || $receiver.a$nil){
-return (
+if($1 == null || $1.a$nil){
+return [(
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.supercall = true,
 //>>excludeEnd("ctx");
-($globals.Silk.a$cls.superclass||$boot.nilAsClass).fn.prototype._doesNotUnderstand_.apply($self, [aMessage]));
+($methodClass.superclass||$boot.nilAsClass).fn.prototype._doesNotUnderstand_.call($self,aMessage))
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.supercall = false;
-//>>excludeEnd("ctx");;
+,$ctx1.supercall = false
+//>>excludeEnd("ctx");
+][0];
 } else {
 return $1;
 }
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"doesNotUnderstand:",{aMessage:aMessage})});
 //>>excludeEnd("ctx");
-},
+}; }),
+$globals.TSilkBuilder);
+
+$core.addMethod(
+$core.method({
+selector: "newSvgElement",
+protocol: "convenience",
 //>>excludeStart("ide", pragmas.excludeIdeData);
-args: ["aMessage"],
-source: "doesNotUnderstand: aMessage\x0a\x09\x22`Silk DIV` creates a div element.\x0a\x09`Silk DIV: anObject` creates a div element and puts contents in it\x22\x0a\x09^ (self tryMakeDnuElement: aMessage)\x0a\x09\x09ifNil: [ super doesNotUnderstand: aMessage ]",
+args: [],
+source: "newSvgElement\x0a\x09^ self newElement: 'svg' xmlns: 'http://www.w3.org/2000/svg'",
 referencedClasses: [],
 //>>excludeEnd("ide");
 pragmas: [],
-messageSends: ["ifNil:", "tryMakeDnuElement:", "doesNotUnderstand:"]
-}),
-$globals.Silk.a$cls);
+messageSends: ["newElement:xmlns:"]
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+return $self._newElement_xmlns_("svg","http://www.w3.org/2000/svg");
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"newSvgElement",{})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.TSilkBuilder);
 
 $core.addMethod(
 $core.method({
 selector: "tryMakeDnuElement:",
 protocol: "instance creation",
-fn: function (aMessage){
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aMessage"],
+source: "tryMakeDnuElement: aMessage\x0a\x09\x22`DIV` creates a div element.\x0a\x09`DIV: anObject` creates a div element and puts contents in it.\x0a\x09An element can be optionally inserted by #newElement:xmlns:.\x0a\x09When self is an instance and not the class Silk, \x0a\x09then the instance's namespace is used for the new element.\x0a\x09You can do:\x0a\x09\x09svg := Silk newElement: 'svg' xmlns: 'http://www.w3.org/2000/svg'.\x0a\x09\x09svg CIRCLE: {'cx' -> 60. 'cy' -> 25. 'r' -> 10}.\x0a\x09This creates a svg circle, not a html circle.\x22\x0a\x09\x0a\x09| selector newElement useArg |\x0a\x09selector := aMessage selector.\x0a\x09selector asUppercase = selector\x0a\x09\x09ifFalse: [ ^ nil ].\x0a\x09selector last = ':'\x0a\x09\x09ifTrue: [ useArg := true. selector := selector allButLast ]\x0a\x09\x09ifFalse: [ useArg := false ].\x0a\x09(selector includes: ':')\x0a\x09\x09ifTrue: [ ^ nil ].\x0a\x09newElement := self newElement: selector asLowercase xmlns: self namespace.\x0a\x09useArg ifTrue: [ newElement << aMessage arguments first ].\x0a\x09^ newElement",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["selector", "ifFalse:", "=", "asUppercase", "ifTrue:ifFalse:", "last", "allButLast", "ifTrue:", "includes:", "newElement:xmlns:", "asLowercase", "namespace", "<<", "first", "arguments"]
+}, function ($methodClass){ return function (aMessage){
 var self=this,$self=this;
 var selector,newElement,useArg;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1,$2,$3,$4;
 selector=$recv(aMessage)._selector();
-$1=$recv($recv(selector)._asUppercase()).__eq(selector);
+if(!$core.assert([$recv($recv(selector)._asUppercase()).__eq(selector)
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["="]=1;
+,$ctx1.sendIdx["="]=1
 //>>excludeEnd("ctx");
-if(!$core.assert($1)){
+][0])){
 return nil;
 }
-$2=$recv($recv(selector)._last()).__eq(":");
-if($core.assert($2)){
+if($core.assert($recv($recv(selector)._last()).__eq(":"))){
 useArg=true;
 selector=$recv(selector)._allButLast();
 selector;
@@ -154,35 +235,35 @@ selector;
 useArg=false;
 useArg;
 }
-$3=$recv(selector)._includes_(":");
-if($core.assert($3)){
+if($core.assert($recv(selector)._includes_(":"))){
 return nil;
 }
-newElement=$self._newElement_($recv(selector)._asLowercase());
-$4=useArg;
-if($core.assert($4)){
+newElement=$self._newElement_xmlns_($recv(selector)._asLowercase(),$self._namespace());
+if($core.assert(useArg)){
 $recv(newElement).__lt_lt($recv($recv(aMessage)._arguments())._first());
 }
 return newElement;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"tryMakeDnuElement:",{aMessage:aMessage,selector:selector,newElement:newElement,useArg:useArg})});
 //>>excludeEnd("ctx");
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: ["aMessage"],
-source: "tryMakeDnuElement: aMessage\x0a\x09\x22`DIV` creates a div element.\x0a\x09`DIV: anObject` creates a div element and puts contents in it\x22\x0a\x09| selector newElement useArg |\x0a\x09selector := aMessage selector.\x0a\x09selector asUppercase = selector\x0a\x09\x09ifFalse: [ ^ nil ].\x0a\x09selector last = ':'\x0a\x09\x09ifTrue: [ useArg := true. selector := selector allButLast ]\x0a\x09\x09ifFalse: [ useArg := false ].\x0a\x09(selector includes: ':')\x0a\x09\x09ifTrue: [ ^ nil ].\x0a\x09newElement := self newElement: selector asLowercase.\x0a\x09useArg ifTrue: [ newElement << aMessage arguments first ].\x0a\x09^ newElement",
-referencedClasses: [],
-//>>excludeEnd("ide");
-pragmas: [],
-messageSends: ["selector", "ifFalse:", "=", "asUppercase", "ifTrue:ifFalse:", "last", "allButLast", "ifTrue:", "includes:", "newElement:", "asLowercase", "<<", "first", "arguments"]
-}),
-$globals.Silk.a$cls);
+}; }),
+$globals.TSilkBuilder);
+
+$core.setTraitComposition([{trait: $globals.TSilkBuilder}], $globals.Silk);
+$core.setTraitComposition([{trait: $globals.TSilkBuilder}], $globals.Silk.a$cls);
 
 $core.addMethod(
 $core.method({
 selector: "renderOnSilk:",
 protocol: "*Silk",
-fn: function (aSilk){
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aSilk"],
+source: "renderOnSilk: aSilk\x0a\x09key attrPut: value on: aSilk",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["attrPut:on:"]
+}, function ($methodClass){ return function (aSilk){
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
@@ -192,22 +273,21 @@ return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"renderOnSilk:",{aSilk:aSilk})});
 //>>excludeEnd("ctx");
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: ["aSilk"],
-source: "renderOnSilk: aSilk\x0a\x09key attrPut: value on: aSilk",
-referencedClasses: [],
-//>>excludeEnd("ide");
-pragmas: [],
-messageSends: ["attrPut:on:"]
-}),
+}; }),
 $globals.Association);
 
 $core.addMethod(
 $core.method({
 selector: "renderOnSilk:",
 protocol: "*Silk",
-fn: function (aSilk){
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aSilk"],
+source: "renderOnSilk: aSilk\x0a\x09self value: aSilk",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["value:"]
+}, function ($methodClass){ return function (aSilk){
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
@@ -217,22 +297,21 @@ return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"renderOnSilk:",{aSilk:aSilk})});
 //>>excludeEnd("ctx");
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: ["aSilk"],
-source: "renderOnSilk: aSilk\x0a\x09self value: aSilk",
-referencedClasses: [],
-//>>excludeEnd("ide");
-pragmas: [],
-messageSends: ["value:"]
-}),
+}; }),
 $globals.BlockClosure);
 
 $core.addMethod(
 $core.method({
 selector: "inSilk",
 protocol: "*Silk",
-fn: function (){
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "inSilk\x0a\x09^ Silk newStream << self; yourself",
+referencedClasses: ["Silk"],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["<<", "newStream", "yourself"]
+}, function ($methodClass){ return function (){
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
@@ -244,26 +323,13 @@ return $recv($1)._yourself();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"inSilk",{})});
 //>>excludeEnd("ctx");
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "inSilk\x0a\x09^ Silk newStream << self; yourself",
-referencedClasses: ["Silk"],
-//>>excludeEnd("ide");
-pragmas: [],
-messageSends: ["<<", "newStream", "yourself"]
-}),
+}; }),
 $globals.JSObjectProxy);
 
 $core.addMethod(
 $core.method({
 selector: "renderOnSilk:",
 protocol: "*Silk",
-fn: function (aSilk){
-var self=this,$self=this;
-return nil;
-
-},
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aSilk"],
 source: "renderOnSilk: aSilk\x0a\x09^ nil",
@@ -271,14 +337,25 @@ referencedClasses: [],
 //>>excludeEnd("ide");
 pragmas: [],
 messageSends: []
-}),
+}, function ($methodClass){ return function (aSilk){
+var self=this,$self=this;
+return nil;
+
+}; }),
 $globals.JSObjectProxy);
 
 $core.addMethod(
 $core.method({
 selector: "inSilk",
 protocol: "*Silk",
-fn: function (){
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "inSilk\x0a\x09^ Silk newStream << self; yourself",
+referencedClasses: ["Silk"],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["<<", "newStream", "yourself"]
+}, function ($methodClass){ return function (){
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
@@ -290,26 +367,13 @@ return $recv($1)._yourself();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"inSilk",{})});
 //>>excludeEnd("ctx");
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "inSilk\x0a\x09^ Silk newStream << self; yourself",
-referencedClasses: ["Silk"],
-//>>excludeEnd("ide");
-pragmas: [],
-messageSends: ["<<", "newStream", "yourself"]
-}),
+}; }),
 $globals.Object);
 
 $core.addMethod(
 $core.method({
 selector: "renderOnSilk:",
 protocol: "*Silk",
-fn: function (aSilk){
-var self=this,$self=this;
-return nil;
-
-},
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aSilk"],
 source: "renderOnSilk: aSilk\x0a\x09^ nil",
@@ -317,14 +381,25 @@ referencedClasses: [],
 //>>excludeEnd("ide");
 pragmas: [],
 messageSends: []
-}),
+}, function ($methodClass){ return function (aSilk){
+var self=this,$self=this;
+return nil;
+
+}; }),
 $globals.Object);
 
 $core.addMethod(
 $core.method({
 selector: "asSilk",
 protocol: "*Silk",
-fn: function (){
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "asSilk\x0a\x09^ Silk at: self asString",
+referencedClasses: ["Silk"],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["at:", "asString"]
+}, function ($methodClass){ return function (){
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
@@ -333,22 +408,21 @@ return $recv($globals.Silk)._at_($self._asString());
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"asSilk",{})});
 //>>excludeEnd("ctx");
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "asSilk\x0a\x09^ Silk at: self asString",
-referencedClasses: ["Silk"],
-//>>excludeEnd("ide");
-pragmas: [],
-messageSends: ["at:", "asString"]
-}),
+}; }),
 $globals.String);
 
 $core.addMethod(
 $core.method({
 selector: "attrPut:on:",
 protocol: "*Silk",
-fn: function (anObject,aSilk){
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["anObject", "aSilk"],
+source: "attrPut: anObject on: aSilk\x0a\x09aSilk attrAt: self put: anObject",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["attrAt:put:"]
+}, function ($methodClass){ return function (anObject,aSilk){
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
@@ -358,15 +432,7 @@ return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"attrPut:on:",{anObject:anObject,aSilk:aSilk})});
 //>>excludeEnd("ctx");
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: ["anObject", "aSilk"],
-source: "attrPut: anObject on: aSilk\x0a\x09aSilk attrAt: self put: anObject",
-referencedClasses: [],
-//>>excludeEnd("ide");
-pragmas: [],
-messageSends: ["attrAt:put:"]
-}),
+}; }),
 $globals.String);
 
 });

+ 66 - 13
src/Silk.st

@@ -51,15 +51,24 @@ Taken all this together, one can do pretty neat constructs:
 adds `<p id="mission">We are the champions.</p>` into `aSilk`
 and returns the Silk-wrapped `<p>` with insertion cursor at the end.!
 
+!Silk methodsFor: 'accessing'!
+
+namespace
+	"<String>
+	XML namespace for elements: html.
+	The default for all virtual Silk tag messages"
+	
+	^ self element namespaceURI
+! !
+
 !Silk methodsFor: 'writing'!
 
-doesNotUnderstand: aMessage
-	"`aSilk DIV` creates a div element and inserts it.
-	`aSilk DIV: anObject` creates a div element, inserts it
-	and puts contents in it"
-	(self class tryMakeDnuElement: aMessage)
-		ifNil: [ ^ super doesNotUnderstand: aMessage ]
-		ifNotNil: [ :newElement | self << newElement. ^ newElement ]
+newElement: aString xmlns: anotherString
+	| el |
+	
+	el := self class newElement: aString xmlns: anotherString.
+	self << el.
+	^ el
 !
 
 nextPut: anObject
@@ -71,11 +80,50 @@ nextPut: anObject
 		ifNil: [ super nextPut: anObject ]
 ! !
 
-!Silk class methodsFor: 'instance creation'!
+!Silk class methodsFor: 'accessing'!
+
+htmlNamespace
+	"<String>
+	XML namespace for HTML elements.
+	The default for all virtual Silk tag messages"
+	
+	^ 'http://www.w3.org/1999/xhtml'
+!
+
+namespace
+	"<String>
+	XML namespace for elements: html.
+	The default for all virtual Silk tag messages"
+	
+	^ self htmlNamespace
+! !
+
+Trait named: #TSilkBuilder
+	package: 'Silk'!
+!TSilkBuilder commentStamp!
+I contain Silk's "build element via DNU" behaviour.
+
+I expect #namespace and #newElement:xmlns: to be implemented.!
+
+!TSilkBuilder methodsFor: 'convenience'!
+
+newSvgElement
+	^ self newElement: 'svg' xmlns: 'http://www.w3.org/2000/svg'
+! !
+
+!TSilkBuilder methodsFor: 'instance creation'!
 
 tryMakeDnuElement: aMessage
 	"`DIV` creates a div element.
-	`DIV: anObject` creates a div element and puts contents in it"
+	`DIV: anObject` creates a div element and puts contents in it.
+	An element can be optionally inserted by #newElement:xmlns:.
+	When self is an instance and not the class Silk, 
+	then the instance's namespace is used for the new element.
+	You can do:
+		svg := Silk newElement: 'svg' xmlns: 'http://www.w3.org/2000/svg'.
+		svg CIRCLE: {'cx' -> 60. 'cy' -> 25. 'r' -> 10}.
+	This creates a svg circle, not a html circle."
+	
 	| selector newElement useArg |
 	selector := aMessage selector.
 	selector asUppercase = selector
@@ -85,20 +133,25 @@ tryMakeDnuElement: aMessage
 		ifFalse: [ useArg := false ].
 	(selector includes: ':')
 		ifTrue: [ ^ nil ].
-	newElement := self newElement: selector asLowercase.
+	newElement := self newElement: selector asLowercase xmlns: self namespace.
 	useArg ifTrue: [ newElement << aMessage arguments first ].
 	^ newElement
 ! !
 
-!Silk class methodsFor: 'message handling'!
+!TSilkBuilder methodsFor: 'message handling'!
 
 doesNotUnderstand: aMessage
-	"`Silk DIV` creates a div element.
-	`Silk DIV: anObject` creates a div element and puts contents in it"
+	"`self DIV` creates (and optionally inserts) a div element.
+	`aSilk DIV: anObject` creates (and optionally inserts)
+	a div element, and puts contents in it"
 	^ (self tryMakeDnuElement: aMessage)
 		ifNil: [ super doesNotUnderstand: aMessage ]
 ! !
 
+Silk setTraitComposition: {TSilkBuilder} asTraitComposition!
+Silk class setTraitComposition: {TSilkBuilder} asTraitComposition!
+! !
+
 !Association methodsFor: '*Silk'!
 
 renderOnSilk: aSilk