1
0
Selaa lähdekoodia

Quite some improvements made to Moka.

- new dropdown list view
- refactorings
- better event handlers
Nicolas Petton 11 vuotta sitten
vanhempi
commit
0a103a96ad

+ 386 - 90
css/moka.css

@@ -1,5 +1,5 @@
 @import "reset.css";
-@import url(http://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800&subset=latin,latin-ext);
+@import url("http://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800&subset=latin,latin-ext");
 .no-select {
   -webkit-touch-callout: none;
   -webkit-user-select: none;
@@ -8,159 +8,268 @@
   -ms-user-select: none;
   user-select: none;
 }
-body {
-  background: #f1f1f1;
+::-webkit-scrollbar {
+  width: 8px;
+  height: 8px;
 }
-.moka_view {
-  display: inline-block;
+::-webkit-scrollbar-button {
+  height: 0;
+  width: 0;
+}
+::-webkit-resizer {
+  background-color: #eeeeee;
+}
+::-webkit-scrollbar-track {
+  background-color: #eeeeee;
+}
+::-webkit-scrollbar-track-piece {
+  background-color: #eeeeee;
+}
+::-webkit-scrollbar-corner {
+  background-color: #eeeeee;
+}
+::-webkit-scrollbar-thumb {
+  background: #e1e1e1;
+  background: -webkit-gradient(linear, left top, right top, color-stop(0, #e1e1e1), color-stop(1, #cfcfcf));
+  background: -ms-linear-gradient(left, #e1e1e1, #cfcfcf);
+  background: -moz-linear-gradient(right, #e1e1e1 0%, #cfcfcf 100%);
+  border: 1px solid #959595;
+  -webkit-border-radius: 8px;
+  -moz-border-radius: 8px;
+  border-radius: 8px;
 }
-.moka_view .mk_default {
+::-webkit-scrollbar-thumb:hover {
+  background: #c3c3c3;
+  background: -webkit-gradient(linear, left top, right top, color-stop(0, #c3c3c3), color-stop(1, #aaaaaa));
+  background: -ms-linear-gradient(left, #c3c3c3, #aaaaaa);
+  background: -moz-linear-gradient(right, #c3c3c3 0%, #aaaaaa 100%);
+  border: 1px solid #919191;
+}
+.mk_default {
   font-size: 12px;
   font-family: "Open Sans";
-  color: #555;
+  line-height: 1.5em;
+  color: #444444;
   text-shadow: 0 1px 0 white;
+  padding: 0;
+  margin: 0;
+}
+.mk_absolute {
+  position: absolute;
+  display: block;
+  overflow: hidden;
+}
+.mk_overlay {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  zindex: 1000;
+  background: transparent;
+}
+.moka_view {
+  position: absolute;
+  display: block;
+  overflow: hidden;
 }
-.moka_view span {
+.moka_view.mk_label {
   font-size: 12px;
   font-family: "Open Sans";
-  color: #555;
+  line-height: 1.5em;
+  color: #444444;
   text-shadow: 0 1px 0 white;
-  color: #333;
+  padding: 0;
+  margin: 0;
+  color: #333333;
   padding: 4px;
 }
+.moka_view.mk_label.mk_heading {
+  font-weight: bold;
+}
+.moka_view.mk_label.mk_heading.level1 {
+  font-size: 2em;
+}
+.moka_view.mk_label.mk_heading.level2 {
+  font-size: 1.8em;
+}
+.moka_view.mk_label.mk_heading.level3 {
+  font-size: 1.6em;
+}
+.moka_view.mk_label.mk_heading.level4 {
+  font-size: 1.4em;
+}
+.moka_view.mk_label.mk_heading.level5 {
+  font-size: 1.2em;
+}
+.moka_view.mk_pane.mk_panel {
+  background: #eeeeee;
+  border-color: #888888;
+  border-style: solid;
+  overflow: auto;
+}
+.moka_view.mk_pane.mk_modal {
+  z-index: 1001;
+  background: transparent;
+  border: 0 none;
+}
+.moka_view.mk_pane.mk_modal:focus {
+  outline: 0 none;
+}
 .moka_view .mk_control,
 .moka_view .mk_control:active,
 .moka_view .mk_control:focus {
   font-size: 12px;
   font-family: "Open Sans";
-  color: #555;
+  line-height: 1.5em;
+  color: #444444;
   text-shadow: 0 1px 0 white;
-  margin: 4px;
-  padding: 3px 10px;
+  padding: 0;
+  margin: 0;
+  position: absolute;
+  display: block;
+  overflow: hidden;
   -webkit-border-radius: 3px;
   -moz-border-radius: 3px;
   border-radius: 3px;
-  border-top: solid 1px #999999;
-  border-left: solid 1px #999999;
-  border-right: solid 1px #999999;
-  border-bottom: solid 1px #999999;
-  -webkit-box-shadow: 0 0 3px 0 #cccccc;
-  -moz-box-shadow: 0 0 3px 0 #cccccc;
-  box-shadow: 0 0 3px 0 #cccccc;
-  background: white;
+  border: 1px solid #aaaaaa;
+  -webkit-box-shadow: inset 0 0 3px 0 #c3c3c3;
+  -moz-box-shadow: inset 0 0 3px 0 #c3c3c3;
+  box-shadow: inset 0 0 3px 0 #c3c3c3;
+  background-color: white;
+  background: -webkit-linear-gradient(top, #eee 0%, white 6px);
+  background: -moz-linear-gradient(top, #eee 0%, white 6px);
+  background: -ms-linear-gradient(top, #eee 0%, white 6px);
+  background: -o-linear-gradient(top, #eee 0%, white 6px);
+  background: linear-gradient(top, #eee 0%, white 6px);
 }
 .moka_view .mk_control:focus,
 .moka_view .mk_control:active:focus,
 .moka_view .mk_control:focus:focus {
   outline: 0;
 }
-.moka_view button {
+.moka_view.mk_button {
   font-size: 12px;
   font-family: "Open Sans";
-  color: #555;
+  line-height: 1.5em;
+  color: #444444;
   text-shadow: 0 1px 0 white;
-  margin: 4px;
-  padding: 3px 10px;
+  padding: 0;
+  margin: 0;
+  position: absolute;
+  display: block;
+  overflow: hidden;
   -webkit-border-radius: 3px;
   -moz-border-radius: 3px;
   border-radius: 3px;
-  border-top: solid 1px #999999;
-  border-left: solid 1px #999999;
-  border-right: solid 1px #999999;
-  border-bottom: solid 1px #999999;
-  -webkit-box-shadow: 0 0 3px 0 #cccccc;
-  -moz-box-shadow: 0 0 3px 0 #cccccc;
-  box-shadow: 0 0 3px 0 #cccccc;
-  background: white;
+  border: 1px solid #aaaaaa;
+  -webkit-box-shadow: inset 0 0 3px 0 #c3c3c3;
+  -moz-box-shadow: inset 0 0 3px 0 #c3c3c3;
+  box-shadow: inset 0 0 3px 0 #c3c3c3;
+  background-color: white;
+  background: -webkit-linear-gradient(top, #eee 0%, white 6px);
+  background: -moz-linear-gradient(top, #eee 0%, white 6px);
+  background: -ms-linear-gradient(top, #eee 0%, white 6px);
+  background: -o-linear-gradient(top, #eee 0%, white 6px);
+  background: linear-gradient(top, #eee 0%, white 6px);
   -webkit-touch-callout: none;
   -webkit-user-select: none;
   -khtml-user-select: none;
   -moz-user-select: none;
   -ms-user-select: none;
   user-select: none;
+  -webkit-box-shadow: 0 1px 1px 0 #d8d8d8;
+  -moz-box-shadow: 0 1px 1px 0 #d8d8d8;
+  box-shadow: 0 1px 1px 0 #d8d8d8;
   background: #fafafa;
   background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #dedede), color-stop(1, #ffffff));
   background: -ms-linear-gradient(bottom, #dedede, #ffffff);
   background: -moz-linear-gradient(center bottom, #dedede 0%, #ffffff 100%);
   background: -o-linear-gradient(#ffffff, #dedede);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#dedede', GradientType=0);
 }
-.moka_view button:focus {
+.moka_view.mk_button:focus {
   outline: 0;
 }
-.moka_view button:focus {
-  border-color: #08c;
+.moka_view.mk_button.default {
+  background: #9ec4eb;
+  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #9ec4eb), color-stop(1, #deeaf8));
+  background: -ms-linear-gradient(bottom, #9ec4eb, #deeaf8);
+  background: -moz-linear-gradient(center bottom, #9ec4eb 0%, #deeaf8 100%);
+  background: -o-linear-gradient(#deeaf8, #9ec4eb);
+  border-color: #9d9d9d;
+}
+.moka_view.mk_button.default:active {
+  background: #9ec4eb;
+  border-color: #4a90d9;
 }
-.moka_view button:active {
-  background: #ccc;
+.moka_view.mk_button:focus {
+  border-color: #4a90d9;
+}
+.moka_view.mk_button:active {
+  background: #dddddd;
   -webkit-box-shadow: inset 0 0 3px 0 #888888;
   -moz-box-shadow: inset 0 0 3px 0 #888888;
   box-shadow: inset 0 0 3px 0 #888888;
-  border-color: #999;
+  border-color: #947c7c;
 }
-.moka_view input,
-.moka_view textarea {
+.moka_view.mk_input,
+.moka_view.mk_textarea {
   font-size: 12px;
   font-family: "Open Sans";
-  color: #555;
+  line-height: 1.5em;
+  color: #444444;
   text-shadow: 0 1px 0 white;
-  margin: 4px;
-  padding: 3px 10px;
+  padding: 0;
+  margin: 0;
+  position: absolute;
+  display: block;
+  overflow: hidden;
   -webkit-border-radius: 3px;
   -moz-border-radius: 3px;
   border-radius: 3px;
-  border-top: solid 1px #999999;
-  border-left: solid 1px #999999;
-  border-right: solid 1px #999999;
-  border-bottom: solid 1px #999999;
-  -webkit-box-shadow: 0 0 3px 0 #cccccc;
-  -moz-box-shadow: 0 0 3px 0 #cccccc;
-  box-shadow: 0 0 3px 0 #cccccc;
-  background: white;
+  border: 1px solid #aaaaaa;
+  -webkit-box-shadow: inset 0 0 3px 0 #c3c3c3;
+  -moz-box-shadow: inset 0 0 3px 0 #c3c3c3;
+  box-shadow: inset 0 0 3px 0 #c3c3c3;
+  background-color: white;
+  background: -webkit-linear-gradient(top, #eee 0%, white 6px);
+  background: -moz-linear-gradient(top, #eee 0%, white 6px);
+  background: -ms-linear-gradient(top, #eee 0%, white 6px);
+  background: -o-linear-gradient(top, #eee 0%, white 6px);
+  background: linear-gradient(top, #eee 0%, white 6px);
+  resize: none;
+  padding: 0 4px;
   text-shadow: 0 0 0;
 }
-.moka_view input:focus,
-.moka_view textarea:focus {
+.moka_view.mk_input:focus,
+.moka_view.mk_textarea:focus {
   outline: 0;
 }
-.moka_view input:focus,
-.moka_view textarea:focus {
-  -webkit-box-shadow: inset 0 0 3px 0 #999999;
-  -moz-box-shadow: inset 0 0 3px 0 #999999;
-  box-shadow: inset 0 0 3px 0 #999999;
-  border-color: #08c;
-}
-.moka_view textarea {
-  width: 200px;
-  height: 100px;
-}
-.moka_view input[type="checkbox"] {
-  position: absolute;
-  left: -999999px;
+.moka_view.mk_input:focus,
+.moka_view.mk_textarea:focus {
+  -webkit-box-shadow: inset 0 0 3px 0 #888888;
+  -moz-box-shadow: inset 0 0 3px 0 #888888;
+  box-shadow: inset 0 0 3px 0 #888888;
+  border-color: #4a90d9;
 }
-.moka_view .mk_checkbox + label {
+.moka_view.mk_checkbox {
   -webkit-touch-callout: none;
   -webkit-user-select: none;
   -khtml-user-select: none;
   -moz-user-select: none;
   -ms-user-select: none;
   user-select: none;
-  padding: 0 6px;
-  margin: 4px;
   background: url('../images/moka/check.png') 50% 50% no-repeat;
   height: 16px;
   width: 16px;
 }
-.moka_view .mk_checkbox:focus + label {
-  background-image: url('../images/moka/check-focus.png');
-  -webkit-box-shadow: 0 0 2px #0088cc;
-  -moz-box-shadow: 0 0 2px #0088cc;
-  box-shadow: 0 0 2px #0088cc;
+.moka_view.mk_checkbox:focus {
+  outline: 0;
 }
-.moka_view .mk_checkbox:checked + label {
+.moka_view.mk_checkbox.checked {
   background-image: url('../images/moka/check-active.png');
 }
-.moka_view .mk_switch + label {
+.moka_view.mk_switch {
   -webkit-touch-callout: none;
   -webkit-user-select: none;
   -khtml-user-select: none;
@@ -170,21 +279,208 @@ body {
   -webkit-border-radius: 20px;
   -moz-border-radius: 20px;
   border-radius: 20px;
-  margin: 4px;
   vertical-align: middle;
   display: inline-block;
   height: 20px;
-  width: 59px;
-  border: 1px solid #999;
+  width: 39px;
+  border: 1px solid #888888;
   background: url('../images/moka/switch.png') 100% 50% no-repeat;
-  -webkit-transition: background 0.3s ease-out;
-  -moz-transition: background 0.3s ease-out;
-  -o-transition: background 0.3s ease-out;
-  transition: background 0.3s ease-out;
+  -webkit-transition: background 0.2s ease-out;
+  -moz-transition: background 0.2s ease-out;
+  -o-transition: background 0.2s ease-out;
+  transition: background 0.2s ease-out;
+}
+.moka_view.mk_switch:focus {
+  border-color: #256ab1;
+}
+.moka_view.mk_switch.checked {
+  background: url('../images/moka/switch.png') 0% 50% no-repeat;
+  border-color: #3583d5;
+}
+.moka_view.mk_list {
+  cursor: default;
+  -webkit-touch-callout: none;
+  -webkit-user-select: none;
+  -khtml-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+  user-select: none;
+  font-size: 12px;
+  font-family: "Open Sans";
+  line-height: 1.5em;
+  color: #444444;
+  text-shadow: 0 1px 0 white;
+  margin: 0;
+  position: absolute;
+  display: block;
+  overflow: hidden;
+  -webkit-border-radius: 3px;
+  -moz-border-radius: 3px;
+  border-radius: 3px;
+  border: 1px solid #aaaaaa;
+  -webkit-box-shadow: inset 0 0 3px 0 #c3c3c3;
+  -moz-box-shadow: inset 0 0 3px 0 #c3c3c3;
+  box-shadow: inset 0 0 3px 0 #c3c3c3;
+  background-color: white;
+  background: -webkit-linear-gradient(top, #eee 0%, white 6px);
+  background: -moz-linear-gradient(top, #eee 0%, white 6px);
+  background: -ms-linear-gradient(top, #eee 0%, white 6px);
+  background: -o-linear-gradient(top, #eee 0%, white 6px);
+  background: linear-gradient(top, #eee 0%, white 6px);
+  padding: 0;
+  overflow: auto;
+  background: white;
+}
+.moka_view.mk_list:focus {
+  outline: 0;
+}
+.moka_view.mk_list:focus {
+  outline: 0;
+  border-color: #4a90d9;
+}
+.moka_view.mk_list:focus li.selected {
+  background: #74aae2;
+  color: white;
+}
+.moka_view.mk_list li {
+  line-height: 2em;
+  padding: 0 4px;
+  text-shadow: 0 0 0;
+}
+.moka_view.mk_list li.selected {
+  background: #dddddd;
+}
+.moka_view.mk_list.mk_sourcelist {
+  background: transparent;
+  border: 0;
+  -webkit-border-radius: 0;
+  -moz-border-radius: 0;
+  border-radius: 0;
+  -webkit-box-shadow: 0 0 0;
+  -moz-box-shadow: 0 0 0;
+  box-shadow: 0 0 0;
+}
+.moka_view.mk_list.mk_sourcelist li {
+  border-top: 1px solid transparent;
+  border-bottom: 1px solid transparent;
+  padding: 0 14px;
+}
+.moka_view.mk_list.mk_sourcelist:focus li.selected,
+.moka_view.mk_list.mk_sourcelist li.selected {
+  text-shadow: 0 1px 0 #333333;
+  background: #74aae2;
+  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #74aae2), color-stop(1, #9ec4eb));
+  background: -ms-linear-gradient(bottom, #74aae2, #9ec4eb);
+  background: -moz-linear-gradient(center bottom, #74aae2 0%, #9ec4eb 100%);
+  background: -o-linear-gradient(#9ec4eb, #74aae2);
+  border-top: 1px solid #4a90d9;
+  border-bottom: 1px solid #4a90d9;
+  color: white;
+  font-weight: bold;
+}
+.moka_view.mk_dropdown {
+  font-size: 12px;
+  font-family: "Open Sans";
+  line-height: 1.5em;
+  color: #444444;
+  text-shadow: 0 1px 0 white;
+  padding: 0;
+  margin: 0;
+  position: absolute;
+  display: block;
+  overflow: hidden;
+  -webkit-border-radius: 3px;
+  -moz-border-radius: 3px;
+  border-radius: 3px;
+  border: 1px solid #aaaaaa;
+  -webkit-box-shadow: inset 0 0 3px 0 #c3c3c3;
+  -moz-box-shadow: inset 0 0 3px 0 #c3c3c3;
+  box-shadow: inset 0 0 3px 0 #c3c3c3;
+  background-color: white;
+  background: -webkit-linear-gradient(top, #eee 0%, white 6px);
+  background: -moz-linear-gradient(top, #eee 0%, white 6px);
+  background: -ms-linear-gradient(top, #eee 0%, white 6px);
+  background: -o-linear-gradient(top, #eee 0%, white 6px);
+  background: linear-gradient(top, #eee 0%, white 6px);
+  -webkit-touch-callout: none;
+  -webkit-user-select: none;
+  -khtml-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+  user-select: none;
+  -webkit-box-shadow: 0 1px 1px 0 #d8d8d8;
+  -moz-box-shadow: 0 1px 1px 0 #d8d8d8;
+  box-shadow: 0 1px 1px 0 #d8d8d8;
+  background: #fafafa;
+  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #dedede), color-stop(1, #ffffff));
+  background: -ms-linear-gradient(bottom, #dedede, #ffffff);
+  background: -moz-linear-gradient(center bottom, #dedede 0%, #ffffff 100%);
+  background: -o-linear-gradient(#ffffff, #dedede);
+  text-align: left;
+  padding: 0 8px;
+}
+.moka_view.mk_dropdown:focus {
+  outline: 0;
+}
+.moka_view.mk_dropdown.default {
+  background: #9ec4eb;
+  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #9ec4eb), color-stop(1, #deeaf8));
+  background: -ms-linear-gradient(bottom, #9ec4eb, #deeaf8);
+  background: -moz-linear-gradient(center bottom, #9ec4eb 0%, #deeaf8 100%);
+  background: -o-linear-gradient(#deeaf8, #9ec4eb);
+  border-color: #9d9d9d;
+}
+.moka_view.mk_dropdown.default:active {
+  background: #9ec4eb;
+  border-color: #4a90d9;
+}
+.moka_view.mk_dropdown:focus {
+  border-color: #4a90d9;
+}
+.moka_view.mk_dropdown:active {
+  background: #dddddd;
+  -webkit-box-shadow: inset 0 0 3px 0 #888888;
+  -moz-box-shadow: inset 0 0 3px 0 #888888;
+  box-shadow: inset 0 0 3px 0 #888888;
+  border-color: #947c7c;
+}
+.moka_view.mk_dropdown .mk_dropdown_arrows {
+  position: absolute;
+  right: 0;
+  height: 100%;
+  width: 24px;
+  top: 0;
+  background-image: url(/images/moka/dropdown_arrows.png);
+  background-position: center;
+  background-repeat: no-repeat;
+  border-left: 1px solid #aaaaaa;
+}
+.moka_view.mk_dropdown_pane {
+  padding: 6px;
+  margin-left: -6px;
+  margin-top: -6px;
+}
+.moka_view.mk_dropdown_pane .mk_dropdown_list {
+  position: relative;
+  display: inline-block;
+  border: 0;
+  background: white;
+  -webkit-box-shadow: 0 0 6px #555555;
+  -moz-box-shadow: 0 0 6px #555555;
+  box-shadow: 0 0 6px #555555;
+  -webkit-border-radius: 0;
+  -moz-border-radius: 0;
+  border-radius: 0;
+  min-width: 120px;
+  max-height: 400px;
+}
+.moka_view.mk_dropdown_pane .mk_dropdown_list li {
+  padding: 0 6px;
 }
-.moka_view .mk_switch:focus + label {
-  border-color: #08c;
+.moka_view.mk_dropdown_pane .mk_dropdown_list li.selected {
+  background: #4a90d9;
+  color: white;
 }
-.moka_view .mk_switch:checked + label {
-  background-position: 0% 50%;
+.moka_view.mk_dropdown_pane .mk_dropdown_list:focus {
+  border: 0;
 }

+ 398 - 170
css/moka.less

@@ -1,183 +1,411 @@
 @import "reset.css";
-@import url(http://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800&subset=latin,latin-ext);
-
-
-	    // Mixins
-	    .gradient(@color: #F5F5F5, @start: #EEE, @stop: #FFF) {
-		background: @color;
-		background: -webkit-gradient(linear,
-					     left bottom,
-					     left top,
-					     color-stop(0, @start),
-					     color-stop(1, @stop));
-		background: -ms-linear-gradient(bottom,
-						@start,
-						@stop);
-		background: -moz-linear-gradient(center bottom,
-						 @start 0%,
-						 @stop 100%);
-		background: -o-linear-gradient(@stop,
-					       @start);
-		filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",@stop,@start));
+@import url("http://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800&subset=latin,latin-ext");
+
+// Mixins
+.gradient(@color: #F5F5F5, @start: #EEE, @stop: #FFF) {
+    background: @color;
+    background: -webkit-gradient(linear,
+				 left bottom,
+				 left top,
+				 color-stop(0, @start),
+				 color-stop(1, @stop));
+    background: -ms-linear-gradient(bottom,
+				    @start,
+				    @stop);
+    background: -moz-linear-gradient(center bottom,
+				     @start 0%,
+				     @stop 100%);
+    background: -o-linear-gradient(@stop,
+				   @start);
+}
+.vertical-gradient(@color: #F5F5F5, @start: #EEE, @stop: #FFF) {
+    background: @color;
+    background: -webkit-gradient(linear,
+				 left top,
+				 right top,
+				 color-stop(0, @start),
+				 color-stop(1, @stop));
+    background: -ms-linear-gradient(left,
+				    @start,
+				    @stop);
+    background: -moz-linear-gradient(right,
+				     @start 0%,
+				     @stop 100%);
+}
+.linear-gradient(@arguments) {
+    background: -webkit-linear-gradient(@arguments);
+    background: -moz-linear-gradient(@arguments);
+    background: -ms-linear-gradient(@arguments);
+    background: -o-linear-gradient(@arguments);
+    background: linear-gradient(@arguments);
+}
+.bordered(@top-color: #EEE, @right-color: #EEE, @bottom-color: #EEE, @left-color: #EEE) {
+    border-top: solid 1px @top-color;
+    border-left: solid 1px @left-color;
+    border-right: solid 1px @right-color;
+    border-bottom: solid 1px @bottom-color;
+}
+.drop-shadow(@x-axis: 0, @y-axis: 1px, @blur: 2px, @alpha: 0.1) {
+    -webkit-box-shadow: @x-axis @y-axis @blur rgba(0, 0, 0, @alpha);
+    -moz-box-shadow: @x-axis @y-axis @blur rgba(0, 0, 0, @alpha);
+    box-shadow: @x-axis @y-axis @blur rgba(0, 0, 0, @alpha);
+}
+.rounded(@radius: 3px) {
+    -webkit-border-radius: @radius;
+    -moz-border-radius: @radius;
+    border-radius: @radius;
+}
+.inner-shadow(@horizontal:0, @vertical:1px, @blur:2px, @alpha: 0.4) {
+    -webkit-box-shadow: inset @horizontal @vertical @blur rgba(0, 0, 0, @alpha);
+    -moz-box-shadow: inset @horizontal @vertical @blur rgba(0, 0, 0, @alpha);
+    box-shadow: inset @horizontal @vertical @blur rgba(0, 0, 0, @alpha);
+}
+.box-shadow(@arguments) {
+    -webkit-box-shadow: @arguments;
+    -moz-box-shadow: @arguments;
+    box-shadow: @arguments;
+}
+.transition(@property: all, @duration:0.2s, @ease:ease-out) {
+    -webkit-transition: @property @duration @ease;
+    -moz-transition: @property @duration @ease;
+    -o-transition: @property @duration @ease;
+    transition: @property @duration @ease;
+}
+.no-select {
+    -webkit-touch-callout: none;
+    -webkit-user-select: none;
+    -khtml-user-select: none;
+    -moz-user-select: none;
+    -ms-user-select: none;
+    user-select: none;
+}
+
+// Moka definitions
+
+// Variables
+
+@blue: #4a90d9;
+@lightblue: #E9ECFA;
+@lighter: #f1f1f1;
+@light: #eee;
+@grey: #aaa;
+@dark: #888;
+@darker: #444;
+@verydark: #333;
+
+
+// scrollbars
+
+::-webkit-scrollbar {
+    width: 8px; 
+    height: 8px;
+}
+::-webkit-scrollbar-button {
+    height: 0; 
+    width: 0;
+}
+::-webkit-resizer {
+    background-color: @light;
+}
+::-webkit-scrollbar-track {
+    background-color: @light;
+}
+::-webkit-scrollbar-track-piece {
+    background-color: @light;
+}
+::-webkit-scrollbar-corner {
+    background-color: @light
+}
+::-webkit-scrollbar-thumb {
+    .vertical-gradient(darken(@light, 5%), darken(@light, 5%), darken(@light, 12%));
+    border: 1px solid darken(@light, 35%);
+    .rounded(8px);
+    
+    &:hover {
+	.vertical-gradient(lighten(@grey, 10%), lighten(@grey, 10%), @grey);
+	border: 1px solid darken(@grey, 10%);
+    }
+}
+
+
+// mixins
+
+.mk_default {
+    // Generic fonts
+    font-size: 12px;
+    font-family: "Open Sans";
+    line-height: 1.5em;
+    color: @darker;
+    text-shadow: 0 1px 0 white;
+    
+    // no padding or margin
+    padding: 0;
+    margin: 0;
+}
+
+.mk_absolute {
+    position: absolute;
+    display: block;
+    overflow: hidden;
+}
+ 
+.mk_overlay {
+    position: fixed;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    zindex: 1000;
+    background: transparent;
+}
+
+.moka_view {    
+    .mk_absolute;
+
+    // Labels & headings
+
+    &.mk_label {
+	.mk_default;
+	color: @verydark;
+	padding: 4px;
+
+	&.mk_heading {
+	    font-weight: bold;
+
+	    &.level1 {
+		font-size: 2em;
 	    }
-	    .bordered(@top-color: #EEE, @right-color: #EEE, @bottom-color: #EEE, @left-color: #EEE) {
-		border-top: solid 1px @top-color;
-		border-left: solid 1px @left-color;
-		border-right: solid 1px @right-color;
-		border-bottom: solid 1px @bottom-color;
+	    &.level2 {
+		font-size: 1.8em;
 	    }
-	    .drop-shadow(@x-axis: 0, @y-axis: 1px, @blur: 2px, @alpha: 0.1) {
-		-webkit-box-shadow: @x-axis @y-axis @blur rgba(0, 0, 0, @alpha);
-		-moz-box-shadow: @x-axis @y-axis @blur rgba(0, 0, 0, @alpha);
-		box-shadow: @x-axis @y-axis @blur rgba(0, 0, 0, @alpha);
+	    &.level3 {
+		font-size: 1.6em;
 	    }
-	    .rounded(@radius: 3px) {
-		-webkit-border-radius: @radius;
-		-moz-border-radius: @radius;
-		border-radius: @radius;
+	    &.level4 {
+		font-size: 1.4em;
 	    }
-	    .inner-shadow(@horizontal:0, @vertical:1px, @blur:2px, @alpha: 0.4) {
-		-webkit-box-shadow: inset @horizontal @vertical @blur rgba(0, 0, 0, @alpha);
-		-moz-box-shadow: inset @horizontal @vertical @blur rgba(0, 0, 0, @alpha);
-		box-shadow: inset @horizontal @vertical @blur rgba(0, 0, 0, @alpha);
+	    &.level5 {
+		font-size: 1.2em;
+	    }
+	}
+    }
+
+    // Panes
+    
+    &.mk_pane {
+
+	&.mk_panel {
+	    background: @light;
+	    border-color: @dark;
+	    border-style: solid;
+	    overflow: auto;
+	}
+
+	&.mk_modal {
+	    z-index: 1001;
+	    background: transparent;
+	    border: 0 none;
+
+	    &:focus {
+		outline: 0 none;
 	    }
-	    .box-shadow(@arguments) {
-		-webkit-box-shadow: @arguments;
-		-moz-box-shadow: @arguments;
-		box-shadow: @arguments;
+	}
+    }
+
+    // Controls
+    
+    .mk_control, .mk_control:active, .mk_control:focus {
+	.mk_default;
+	.mk_absolute;
+	.rounded();
+	border: 1px solid @grey;
+	.box-shadow(inset 0 0 3px 0 lighten(@grey, 10%));
+	background-color: white;
+	// see http://stackoverflow.com/questions/14768780/how-can-i-pass-mixin-arguments-along-literally-in-less-css
+	.linear-gradient(~"top, #eee 0%, white 6px");
+
+	&:focus {
+	    outline: 0;
+	}
+    }
+
+    &.mk_button {
+	.mk_control;
+	.no-select;
+	.box-shadow(0 1px 1px 0 lighten(@grey, 18%));
+	.gradient(#fafafa, #dedede, white);
+
+	&.default {
+	    .gradient(lighten(@blue, 20%), lighten(@blue, 20%), lighten(@blue, 35%));
+	    border-color: darken(@grey, 5%);
+
+	    &:active {
+	    	background: lighten(@blue, 20%);
+	    	border-color: @blue;
 	    }
-	    .transition(@property: all, @duration:0.2s, @ease:ease-out) {
-		-webkit-transition: @property @duration @ease;
-		-moz-transition: @property @duration @ease;
-		-o-transition: @property @duration @ease;
-		transition: @property @duration @ease;
+	}
+
+	&:focus {
+	    border-color: @blue;
+	}
+
+	&:active {
+	    background: lighten(@grey, 20%);
+	    .box-shadow(inset 0 0 3px 0 @dark);
+	    border-color: saturate(@dark, 10%);
+	}
+    }
+    
+    &.mk_input, &.mk_textarea {
+	.mk_control;
+	resize: none;
+	padding: 0 4px;
+	text-shadow: 0 0 0;
+
+	&:focus {
+	    .box-shadow(inset 0 0 3px 0 @dark);
+	    border-color: @blue;
+	}
+    }
+
+    &.mk_checkbox {
+	.no-select;
+	background: url('../images/moka/check.png') 50% 50% no-repeat;
+	height: 16px;
+	width: 16px;
+
+	&:focus {
+	    outline: 0;
+	}
+
+	&.checked {
+	    background-image: url('../images/moka/check-active.png');
+	}
+    }
+
+    &.mk_switch {
+	.no-select;
+	.rounded(20px);
+	vertical-align: middle;
+	display: inline-block;
+	height: 20px;
+	width: 39px;
+	border: 1px solid @dark;
+	background: url('../images/moka/switch.png') 100% 50% no-repeat;
+	.transition(background, .2s);
+
+	&:focus {
+	    border-color: darken(@blue, 15%);
+	}
+
+	&.checked {
+	    background: url('../images/moka/switch.png') 0% 50% no-repeat;
+	    border-color: darken(@blue, 5%);
+	}
+    }
+
+
+    // Lists
+    
+    &.mk_list {
+	cursor: default;
+	.mk_default;
+	.no-select;
+	.mk_control;
+	padding: 0;
+	overflow: auto;
+	background: white;
+
+	&:focus {
+	    outline: 0;
+	    border-color: @blue;
+
+	    li.selected {
+		background: lighten(@blue, 10%);
+		color: white;
 	    }
-	    .no-select {
-		-webkit-touch-callout: none;
-		-webkit-user-select: none;
-		-khtml-user-select: none;
-		-moz-user-select: none;
-		-ms-user-select: none;
-		user-select: none;
+	}
+
+	li {
+	    line-height: 2em;
+	    padding: 0 4px;
+	    text-shadow: 0 0 0;
+	    
+	    &.selected {
+		background: lighten(@grey, 20%);
 	    }
+	}
+
+	&.mk_sourcelist {
+	    background: transparent;
+	    border: 0;
+	    .rounded(0);
+	    .box-shadow(0 0 0);
 
-	    // Moka definitions
+	    li {
+		border-top: 1px solid transparent;
+		border-bottom: 1px solid transparent;
+		padding: 0 14px;
+	    }
 
-	    // TEMP
-	    body {
-		background: #f1f1f1;
+	    &:focus li.selected, li.selected {
+		text-shadow: 0 1px 0 @verydark;
+		.gradient(lighten(@blue, 10%), lighten(@blue, 10%), lighten(@blue, 20%));
+		border-top: 1px solid @blue;
+		border-bottom: 1px solid @blue;
+		color: white;
+		font-weight: bold;
 	    }
+	}
+    }
+
+// Dropdowns
+
+    &.mk_dropdown {
+	.mk_button;
+	text-align: left;
+	padding: 0 8px;
 
-	    .moka_view {    
-
-		display: inline-block;
-
-		.mk_default {
-		    // Generic fonts
-		    font-size: 12px;
-		    font-family: "Open Sans";
-		    color: #555;
-		    text-shadow: 0 1px 0 white;
-
-		}
-
-		// Labels
-
-		span {
-		    .mk_default;
-		    color: #333;
-		    padding: 4px;
-		}
-
-		// Controls
-		
-		.mk_control, .mk_control:active, .mk_control:focus {
-		    .mk_default;
-
-		    margin: 4px;
-		    padding: 3px 10px;
-		    .rounded();
-		    .bordered(#999, #999, #999, #999);
-		    .box-shadow(0 0 3px 0 #ccc);
-		    background: white;
-
-		    &:focus {
-			outline: 0;
-		    }
-		}
-
-		button {
-		    .mk_control;
-		    .no-select;
-		    .gradient(#fafafa, #dedede, white);
-
-		    &:focus {
-			border-color: #08c;
-		    }
-
-		    &:active {
-			background: #ccc;
-			.box-shadow(inset 0 0 3px 0 #888);
-			border-color: #999;
-		    }
-		}
-		
-		input, textarea {
-		    .mk_control;
-		    text-shadow: 0 0 0;
-
-		    &:focus {
-			.box-shadow(inset 0 0 3px 0 #999);
-			border-color: #08c;
-		    }
-		}
-		
-		textarea {
-		    width: 200px;
-		    height: 100px;
-		}
-
-		input[type="checkbox"] {
-		    position: absolute;
-		    left: -999999px;
-		}
-
-		.mk_checkbox + label {
-		    .no-select;
-		    padding: 0 6px;
-		    margin: 4px;
-		    background: url('../images/moka/check.png') 50% 50% no-repeat;
-		    height: 16px;
-		    width: 16px;
-		}
-
-		.mk_checkbox:focus + label {
-		    background-image: url('../images/moka/check-focus.png');
-		    .box-shadow(0 0 2px #08c);
-		}
-
-		.mk_checkbox:checked + label {
-		    background-image: url('../images/moka/check-active.png');
-		}
-
-		.mk_switch + label {
-		    .no-select;
-		    .rounded(20px);
-		    margin: 4px;
-		    vertical-align: middle;
-		    display: inline-block;
-		    height: 20px;
-		    width: 59px;
-		    border: 1px solid #999;
-		    background: url('../images/moka/switch.png') 100% 50% no-repeat;
-		    .transition(background, .3s);
-		}
-
-		.mk_switch:focus + label {
-		    border-color: #08c;
-		}
-
-		.mk_switch:checked + label {
-		    background-position: 0% 50%;
-		}
-	    }
+	.mk_dropdown_arrows {
+	    position: absolute;
+	    right: 0;
+	    height: 100%;
+	    width: 24px;
+	    top: 0;
+	    background-image: url(/images/moka/dropdown_arrows.png);
+	    background-position: center;
+	    background-repeat: no-repeat;
+	    border-left: 1px solid @grey;
+	}
+    }
+
+    &.mk_dropdown_pane {
+	padding: 6px;
+	margin-left: -6px;
+	margin-top: -6px;
+
+	.mk_dropdown_list {
+	    position: relative;
+	    display: inline-block;
+	    border: 0;
+	    background: white;
+	    .box-shadow(0 0 6px darken(@dark, 20%));
+	    .rounded(0);
+	    min-width: 120px;
+	    max-height: 400px;
+
+	    li {
+		padding: 0 6px;
+
+		&.selected {
+		    background: @blue;
+		    color: white;
+		};
+	    }
+	    
+	    &:focus {
+		border: 0;
+	    }
+	}
+    }
+}

BIN
images/moka/dropdown_arrows.png


+ 122 - 0
images/moka/dropdown_arrows.svg

@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="32"
+   height="32"
+   id="svg2985"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="dropdown_arrows.svg"
+   inkscape:export-filename="/home/nico/work/smalltalk/amber/images/moka/dropdown_arrows.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90">
+  <defs
+     id="defs2987">
+    <linearGradient
+       id="linearGradient2996">
+      <stop
+         style="stop-color:#e5eff9;stop-opacity:1;"
+         offset="0"
+         id="stop2998" />
+      <stop
+         style="stop-color:#74aae2;stop-opacity:1;"
+         offset="1"
+         id="stop3000" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2996"
+       id="linearGradient3002"
+       x1="8"
+       y1="0"
+       x2="8"
+       y2="17"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.9827986,0,0,1.8960321,0,-15.886898)" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="8"
+     inkscape:cx="-3.9935118"
+     inkscape:cy="7.5364876"
+     inkscape:current-layer="g3796"
+     showgrid="true"
+     inkscape:grid-bbox="true"
+     inkscape:document-units="px"
+     inkscape:window-width="1280"
+     inkscape:window-height="734"
+     inkscape:window-x="0"
+     inkscape:window-y="27"
+     inkscape:window-maximized="1">
+    <inkscape:grid
+       type="xygrid"
+       id="grid3020"
+       empspacing="5"
+       visible="true"
+       enabled="true"
+       snapvisiblegridlinesonly="true" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata2990">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     transform="translate(0,16)">
+    <g
+       id="g3796"
+       transform="translate(0,0.011898)">
+      <rect
+         style="fill:url(#linearGradient3002);fill-opacity:1;stroke:none"
+         id="rect2994"
+         width="32.022972"
+         height="31.906855"
+         x="0"
+         y="-15.886898"
+         rx="0"
+         ry="20.856354"
+         inkscape:export-xdpi="90"
+         inkscape:export-ydpi="90" />
+      <g
+         id="g3772"
+         transform="translate(7.9999998,-8)">
+        <path
+           style="fill:#555555;fill-opacity:1;stroke:none"
+           d="M 10.56996,7.0079637 8.0000003,2.724697 5.4300403,7.0079637 z"
+           id="path3022"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cccc" />
+        <path
+           sodipodi:nodetypes="cccc"
+           inkscape:connector-curvature="0"
+           id="path3794"
+           d="M 10.569959,8.9682399 8.0000006,13.251507 5.4300406,8.9682399 z"
+           style="fill:#555555;fill-opacity:1;stroke:none" />
+      </g>
+    </g>
+  </g>
+</svg>

BIN
images/moka/switch.png


+ 623 - 0
images/moka/switch.svg

@@ -0,0 +1,623 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="48"
+   height="26"
+   id="svg3482"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="switch-off.svg">
+  <defs
+     id="defs3484">
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4125"
+       id="linearGradient4207"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.958336,0,0,1.2500004,-360.37115,-41.099883)"
+       x1="428.21423"
+       y1="548.57648"
+       x2="428.21423"
+       y2="541.57648" />
+    <linearGradient
+       id="linearGradient4125">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0.48627451;"
+         offset="0"
+         id="stop4127" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0;"
+         offset="1"
+         id="stop4129" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4133"
+       id="linearGradient4214"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.7916673,0,0,1.049997,-288.41783,-1196.4744)"
+       x1="428.21423"
+       y1="548.57648"
+       x2="428.21423"
+       y2="541.57648" />
+    <linearGradient
+       id="linearGradient4133">
+      <stop
+         style="stop-color:#000000;stop-opacity:0.1254902;"
+         offset="0"
+         id="stop4135" />
+      <stop
+         style="stop-color:#000000;stop-opacity:0.0627451;"
+         offset="1"
+         id="stop4137" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4064"
+       id="radialGradient4216"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.2051902,0,0,1.2051887,416.57522,654.34706)"
+       cx="66"
+       cy="-19"
+       fx="66"
+       fy="-19"
+       r="7" />
+    <linearGradient
+       id="linearGradient4064">
+      <stop
+         id="stop4066"
+         offset="0"
+         style="stop-color:#4a79a5;stop-opacity:0.50980395;" />
+      <stop
+         id="stop4068"
+         offset="1"
+         style="stop-color:#4a79a5;stop-opacity:0;" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3965"
+       id="radialGradient4218"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.2051902,0,0,1.2051887,416.57522,654.34706)"
+       cx="66"
+       cy="-19"
+       fx="66"
+       fy="-19"
+       r="7" />
+    <linearGradient
+       id="linearGradient3965">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0.39285713;"
+         offset="0"
+         id="stop3967" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0;"
+         offset="1"
+         id="stop3969" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4064"
+       id="radialGradient4220"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-1.0358675,0.32475847,0.33853201,1.2979227,570.91702,634.67523)"
+       cx="66"
+       cy="-19"
+       fx="66"
+       fy="-19"
+       r="7" />
+    <linearGradient
+       id="linearGradient3459">
+      <stop
+         id="stop3461"
+         offset="0"
+         style="stop-color:#4a79a5;stop-opacity:0.50980395;" />
+      <stop
+         id="stop3463"
+         offset="1"
+         style="stop-color:#4a79a5;stop-opacity:0;" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3965"
+       id="radialGradient4222"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.077388,0,0,1.0773891,1.365723,83.513995)"
+       cx="459.21423"
+       cy="508.57648"
+       fx="459.21423"
+       fy="508.57648"
+       r="7.8299899" />
+    <linearGradient
+       id="linearGradient3466">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0.39285713;"
+         offset="0"
+         id="stop3468" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0;"
+         offset="1"
+         id="stop3470" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3986"
+       id="linearGradient4454"
+       gradientUnits="userSpaceOnUse"
+       x1="67.50013"
+       y1="-13.499995"
+       x2="67.50013"
+       y2="-29.500275" />
+    <linearGradient
+       id="linearGradient3986">
+      <stop
+         style="stop-color:#878787;stop-opacity:1;"
+         offset="0"
+         id="stop3988" />
+      <stop
+         style="stop-color:#4b4b4b;stop-opacity:1;"
+         offset="1"
+         id="stop3990" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3953"
+       id="radialGradient4450"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-1.0358675,0.32475847,0.33853201,1.2979227,456.76009,559.90988)"
+       cx="66"
+       cy="-19"
+       fx="66"
+       fy="-19"
+       r="7" />
+    <linearGradient
+       id="linearGradient3953">
+      <stop
+         style="stop-color:#828282;stop-opacity:0.68627453;"
+         offset="0"
+         id="stop3955" />
+      <stop
+         style="stop-color:#828282;stop-opacity:0;"
+         offset="1"
+         id="stop3957" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3965-6"
+       id="radialGradient4452"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.077388,0,0,1.0773891,-112.7912,8.7486417)"
+       cx="459.21423"
+       cy="508.57648"
+       fx="459.21423"
+       fy="508.57648"
+       r="7.8299899" />
+    <linearGradient
+       id="linearGradient3965-6">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0.39285713;"
+         offset="0"
+         id="stop3967-3" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0;"
+         offset="1"
+         id="stop3969-2" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3953"
+       id="radialGradient4446"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.2051902,0,0,1.2051887,302.4183,579.58171)"
+       cx="66"
+       cy="-19"
+       fx="66"
+       fy="-19"
+       r="7" />
+    <linearGradient
+       id="linearGradient3668">
+      <stop
+         style="stop-color:#828282;stop-opacity:0.68627453;"
+         offset="0"
+         id="stop3670" />
+      <stop
+         style="stop-color:#828282;stop-opacity:0;"
+         offset="1"
+         id="stop3672" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3965-6"
+       id="radialGradient4448"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.2051902,0,0,1.2051887,302.4183,579.58171)"
+       cx="66"
+       cy="-19"
+       fx="66"
+       fy="-19"
+       r="7" />
+    <linearGradient
+       id="linearGradient3675">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0.39285713;"
+         offset="0"
+         id="stop3677" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0;"
+         offset="1"
+         id="stop3679" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4133-1"
+       id="linearGradient4034"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.7916673,0,0,1.049997,-380.57475,-1121.7091)"
+       x1="428.21423"
+       y1="548.57648"
+       x2="428.21423"
+       y2="541.57648" />
+    <linearGradient
+       id="linearGradient4133-1">
+      <stop
+         style="stop-color:#000000;stop-opacity:0.1254902;"
+         offset="0"
+         id="stop4135-3" />
+      <stop
+         style="stop-color:#000000;stop-opacity:0.0627451;"
+         offset="1"
+         id="stop4137-6" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4198"
+       id="linearGradient4030"
+       x1="482.21423"
+       y1="526.57648"
+       x2="482.21423"
+       y2="546.57648"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.1578947,0,0,1.1,-165.43988,-33.503598)" />
+    <linearGradient
+       id="linearGradient4198">
+      <stop
+         style="stop-color:#c0c0c0;stop-opacity:1;"
+         offset="0"
+         id="stop4200" />
+      <stop
+         style="stop-color:#d1d1d1;stop-opacity:1;"
+         offset="1"
+         id="stop4202" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3942"
+       id="linearGradient4020"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.8750093,0,0,1.150008,-416.55472,-62.061548)"
+       x1="428.21423"
+       y1="548.57648"
+       x2="428.21423"
+       y2="541.57648" />
+    <linearGradient
+       id="linearGradient3942">
+      <stop
+         id="stop3944"
+         offset="0"
+         style="stop-color:#878787;stop-opacity:1;" />
+      <stop
+         id="stop3946"
+         offset="1"
+         style="stop-color:#828282;stop-opacity:1;" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4125-9"
+       id="linearGradient3245"
+       gradientUnits="userSpaceOnUse"
+       x1="428.21423"
+       y1="548.57648"
+       x2="428.21423"
+       y2="541.57648"
+       gradientTransform="matrix(1.958336,0,0,1.2500004,-360.37115,-69.099883)" />
+    <linearGradient
+       id="linearGradient4125-9">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0.48627451;"
+         offset="0"
+         id="stop4127-6" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0;"
+         offset="1"
+         id="stop4129-9" />
+    </linearGradient>
+    <linearGradient
+       y2="541.57648"
+       x2="428.21423"
+       y1="548.57648"
+       x1="428.21423"
+       gradientTransform="matrix(1.958336,0,0,1.2500004,-452.52807,-115.86523)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient3706"
+       xlink:href="#linearGradient4125-9"
+       inkscape:collect="always" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4125-9"
+       id="linearGradient3816"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.958336,0,0,1.2500004,-452.52807,-115.86523)"
+       x1="428.21423"
+       y1="548.57648"
+       x2="428.21423"
+       y2="541.57648" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3942"
+       id="linearGradient3818"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.8750093,0,0,1.150008,-416.55472,-62.061548)"
+       x1="428.21423"
+       y1="548.57648"
+       x2="428.21423"
+       y2="541.57648" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4198"
+       id="linearGradient3820"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.1578947,0,0,1.1,-165.43988,-33.503598)"
+       x1="482.21423"
+       y1="526.57648"
+       x2="482.21423"
+       y2="546.57648" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4133-1"
+       id="linearGradient3822"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.7916673,0,0,1.049997,-380.57475,-1121.7091)"
+       x1="428.21423"
+       y1="548.57648"
+       x2="428.21423"
+       y2="541.57648" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3953"
+       id="radialGradient3824"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.2051902,0,0,1.2051887,302.4183,579.58171)"
+       cx="66"
+       cy="-19"
+       fx="66"
+       fy="-19"
+       r="7" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3965-6"
+       id="radialGradient3826"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.2051902,0,0,1.2051887,302.4183,579.58171)"
+       cx="66"
+       cy="-19"
+       fx="66"
+       fy="-19"
+       r="7" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3953"
+       id="radialGradient3828"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-1.0358675,0.32475847,0.33853201,1.2979227,456.76009,559.90988)"
+       cx="66"
+       cy="-19"
+       fx="66"
+       fy="-19"
+       r="7" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3965-6"
+       id="radialGradient3830"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.077388,0,0,1.0773891,-112.7912,8.7486417)"
+       cx="459.21423"
+       cy="508.57648"
+       fx="459.21423"
+       fy="508.57648"
+       r="7.8299899" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3986"
+       id="linearGradient3832"
+       gradientUnits="userSpaceOnUse"
+       x1="67.306625"
+       y1="-19.305044"
+       x2="67.50013"
+       y2="-29.500275" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3953"
+       id="radialGradient3065"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-1.0358675,0.32475847,0.33853201,1.2979227,438.83875,535.54566)"
+       cx="66"
+       cy="-19"
+       fx="66"
+       fy="-19"
+       r="7" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3965-6"
+       id="radialGradient3067"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.077388,0,0,1.0773891,-130.71254,-15.61558)"
+       cx="459.21423"
+       cy="508.57648"
+       fx="459.21423"
+       fy="508.57648"
+       r="7.8299899" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3953"
+       id="radialGradient3070"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.2051902,0,0,1.2051887,284.49696,555.21749)"
+       cx="66"
+       cy="-19"
+       fx="66"
+       fy="-19"
+       r="7" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3965-6"
+       id="radialGradient3072"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.2051902,0,0,1.2051887,284.49696,555.21749)"
+       cx="66"
+       cy="-19"
+       fx="66"
+       fy="-19"
+       r="7" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4133-1"
+       id="linearGradient3076"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.7916673,0,0,1.049997,-398.49609,-1097.3449)"
+       x1="428.21423"
+       y1="548.57648"
+       x2="428.21423"
+       y2="541.57648" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4198"
+       id="linearGradient3079"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.1578947,0,0,1.1,-183.36122,-57.86782)"
+       x1="482.21423"
+       y1="526.57648"
+       x2="482.21423"
+       y2="546.57648" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3942"
+       id="linearGradient3082"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.8750093,0,0,1.150008,-434.47606,-86.42577)"
+       x1="428.21423"
+       y1="548.57648"
+       x2="428.21423"
+       y2="541.57648" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4125-9"
+       id="linearGradient3085"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.958336,0,0,1.2500004,-470.44941,-140.22945)"
+       x1="428.21423"
+       y1="548.57648"
+       x2="428.21423"
+       y2="541.57648" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="12.239653"
+     inkscape:cx="5.6816455"
+     inkscape:cy="18.888161"
+     inkscape:document-units="px"
+     inkscape:current-layer="g3855"
+     showgrid="false"
+     fit-margin-top="0"
+     fit-margin-left="0"
+     fit-margin-right="0"
+     fit-margin-bottom="0"
+     inkscape:window-width="1280"
+     inkscape:window-height="734"
+     inkscape:window-x="0"
+     inkscape:window-y="27"
+     inkscape:window-maximized="1" />
+  <metadata
+     id="metadata3487">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-350.99212,-519.36632)">
+    <g
+       id="g3855">
+      <rect
+         ry="12.499951"
+         rx="13.35611"
+         y="519.86639"
+         x="351.49216"
+         height="24.999901"
+         width="46.999901"
+         id="rect3204"
+         style="fill:none;stroke:url(#linearGradient3085);stroke-width:1.00010014;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+      <path
+         sodipodi:type="arc"
+         style="fill:#ececec;fill-opacity:1;stroke:none"
+         id="path4436"
+         sodipodi:cx="66"
+         sodipodi:cy="-19.5"
+         sodipodi:rx="6"
+         sodipodi:ry="6.5"
+         d="m 72,-19.5 c 0,3.589851 -2.686292,6.5 -6,6.5 -3.313708,0 -6,-2.910149 -6,-6.5 0,-3.589851 2.686292,-6.5 6,-6.5 3.313708,0 6,2.910149 6,6.5 z"
+         transform="matrix(1.5,0,0,1.3846154,265.03944,559.31897)" />
+      <path
+         style="fill:url(#radialGradient3070);fill-opacity:1;stroke:url(#radialGradient3072);stroke-width:1.12735164px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+         d="m 364.03946,532.31898 -8.43633,4.21817 6.02595,4.21815 4.82076,-16.87265 6.02594,4.21815 -8.43632,4.21818 z"
+         id="path4438"
+         inkscape:connector-curvature="0" />
+      <path
+         inkscape:connector-curvature="0"
+         id="path4440"
+         d="m 364.03945,532.31897 8.43596,2.26944 -3.99451,6.16651 -8.88292,-16.8719 -3.99448,6.1665 8.43595,2.26945 z"
+         style="fill:url(#radialGradient3065);fill-opacity:1;stroke:url(#radialGradient3067);stroke-width:1.12810218" />
+      <path
+         transform="matrix(1.13333,0,0,-1.13333,287.53967,507.95238)"
+         d="m 75,-21.5 c 0,4.142136 -3.357864,7.5 -7.5,7.5 -4.142136,0 -7.5,-3.357864 -7.5,-7.5 0,-4.142136 3.357864,-7.5 7.5,-7.5 4.142136,0 7.5,3.357864 7.5,7.5 z"
+         sodipodi:ry="7.5"
+         sodipodi:rx="7.5"
+         sodipodi:cy="-21.5"
+         sodipodi:cx="67.5"
+         id="path4442"
+         style="fill:none;stroke:#ffffff;stroke-width:0.88239956;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:0.54901961;stroke-dasharray:none"
+         sodipodi:type="arc" />
+      <path
+         sodipodi:type="arc"
+         style="fill:none;stroke:url(#linearGradient3832);stroke-width:0.78928715000000005;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+         id="path4444"
+         sodipodi:cx="67.5"
+         sodipodi:cy="-21.5"
+         sodipodi:rx="7.5"
+         sodipodi:ry="7.5"
+         d="m 75,-21.5 c 0,4.142136 -3.357864,7.5 -7.5,7.5 -4.142136,0 -7.5,-3.357864 -7.5,-7.5 0,-4.142136 3.357864,-7.5 7.5,-7.5 4.142136,0 7.5,3.357864 7.5,7.5 z"
+         transform="matrix(1.2666816,0,0,-1.2666816,278.49109,505.13266)" />
+    </g>
+  </g>
+</svg>

+ 1 - 1
index.html

@@ -13,7 +13,7 @@
 <body>
 <script type='text/javascript'>
     require(
-        ["amber/devel", "amber_core/Moka-Core", "amber_core/Moka-Controllers", "amber_core/Moka-Views", "amber_core/Moka-Examples"],
+        ["amber/devel", "amber_core/Moka-Core", "amber_core/Moka-Controllers", "amber_core/Moka-Views", "amber_core/Moka-Layouts", "amber_core/Moka-Examples"],
         function (smalltalk) {
             smalltalk.defaultAmdNamespace = "amber_core";
             smalltalk.initialize();

+ 727 - 29
js/Moka-Controllers.js

@@ -1,8 +1,8 @@
-define("amber_core/Moka-Controllers", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_core/Moka-Core"], function(smalltalk,nil,_st){
+define("amber_core/Moka-Controllers", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_core/Moka-Core", "amber_core/Kernel-Objects"], function(smalltalk,nil,_st){
 smalltalk.addPackage('Moka-Controllers');
 smalltalk.packages["Moka-Controllers"].transport = {"type":"amd","amdNamespace":"amber_core"};
 
-smalltalk.addClass('MKAnyKeyInputController', smalltalk.MKAspectController, ['lastValue'], 'Moka-Controllers');
+smalltalk.addClass('MKAnyKeyInputController', smalltalk.MKSingleAspectController, ['lastValue'], 'Moka-Controllers');
 smalltalk.MKAnyKeyInputController.comment="I am the default controller for `MKTextAreaView`. Actions are performed on any key press if the view's value changes.";
 smalltalk.addMethod(
 smalltalk.method({
@@ -24,10 +24,26 @@ smalltalk.MKAnyKeyInputController);
 
 smalltalk.addMethod(
 smalltalk.method({
-selector: "onKeyPressed:",
+selector: "onKeyUp:",
 category: 'actions',
 fn: function (anEvent){
 var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._setNewValue();
+return self}, function($ctx1) {$ctx1.fill(self,"onKeyUp:",{anEvent:anEvent},smalltalk.MKAnyKeyInputController)})},
+args: ["anEvent"],
+source: "onKeyUp: anEvent\x0a\x09self setNewValue",
+messageSends: ["setNewValue"],
+referencedClasses: []
+}),
+smalltalk.MKAnyKeyInputController);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "setNewValue",
+category: 'actions',
+fn: function (){
+var self=this;
 var newValue;
 return smalltalk.withContext(function($ctx1) { 
 var $1;
@@ -37,11 +53,11 @@ if(smalltalk.assert($1)){
 return self;
 };
 self["@lastValue"]=newValue;
-self._performActionWith_(newValue);
-return self}, function($ctx1) {$ctx1.fill(self,"onKeyPressed:",{anEvent:anEvent,newValue:newValue},smalltalk.MKAnyKeyInputController)})},
-args: ["anEvent"],
-source: "onKeyPressed: anEvent\x0a\x09| newValue |\x0a\x09\x0a\x09newValue := self inputText.\x0a\x09newValue = lastValue ifTrue: [ ^ self ].\x0a\x09\x0a\x09lastValue := newValue.\x0a\x09self performActionWith: newValue",
-messageSends: ["inputText", "ifTrue:", "=", "performActionWith:"],
+self._performAspectActionWith_(newValue);
+return self}, function($ctx1) {$ctx1.fill(self,"setNewValue",{newValue:newValue},smalltalk.MKAnyKeyInputController)})},
+args: [],
+source: "setNewValue\x0a\x09| newValue |\x0a\x09\x0a\x09newValue := self inputText.\x0a\x09newValue = lastValue ifTrue: [ ^ self ].\x0a\x09\x0a\x09lastValue := newValue.\x0a\x09self performAspectActionWith: newValue",
+messageSends: ["inputText", "ifTrue:", "=", "performAspectActionWith:"],
 referencedClasses: []
 }),
 smalltalk.MKAnyKeyInputController);
@@ -52,7 +68,7 @@ smalltalk.addClass('MKEnterInputController', smalltalk.MKAnyKeyInputController,
 smalltalk.MKEnterInputController.comment="I am the default controller for `MKInputView`. \x0aActions are performed on 'enter' key press.";
 smalltalk.addMethod(
 smalltalk.method({
-selector: "onKeyPressed:",
+selector: "onKeyDown:",
 category: 'actions',
 fn: function (anEvent){
 var self=this;
@@ -61,55 +77,737 @@ return smalltalk.withContext(function($ctx1) {
 var $1;
 $1=_st(_st(anEvent)._keyCode()).__eq(_st(_st($String())._cr())._asciiValue());
 if(smalltalk.assert($1)){
-smalltalk.MKEnterInputController.superclass.fn.prototype._onKeyPressed_.apply(_st(self), [anEvent]);
+self._setNewValue();
 };
-return self}, function($ctx1) {$ctx1.fill(self,"onKeyPressed:",{anEvent:anEvent},smalltalk.MKEnterInputController)})},
+return self}, function($ctx1) {$ctx1.fill(self,"onKeyDown:",{anEvent:anEvent},smalltalk.MKEnterInputController)})},
 args: ["anEvent"],
-source: "onKeyPressed: anEvent\x0a\x09anEvent keyCode = String cr asciiValue ifTrue: [\x0a\x09\x09super onKeyPressed: anEvent ]",
-messageSends: ["ifTrue:", "=", "keyCode", "asciiValue", "cr", "onKeyPressed:"],
+source: "onKeyDown: anEvent\x0a\x09anEvent keyCode = String cr asciiValue ifTrue: [\x0a\x09\x09self setNewValue ]",
+messageSends: ["ifTrue:", "=", "keyCode", "asciiValue", "cr", "setNewValue"],
 referencedClasses: ["String"]
 }),
 smalltalk.MKEnterInputController);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "onKeyUp:",
+category: 'actions',
+fn: function (anEvent){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return self}, function($ctx1) {$ctx1.fill(self,"onKeyUp:",{anEvent:anEvent},smalltalk.MKEnterInputController)})},
+args: ["anEvent"],
+source: "onKeyUp: anEvent",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.MKEnterInputController);
+
 
 
-smalltalk.addClass('MKButtonController', smalltalk.MKAspectController, [], 'Moka-Controllers');
+smalltalk.addClass('MKButtonController', smalltalk.MKSingleAspectController, [], 'Moka-Controllers');
 smalltalk.MKButtonController.comment="I am the default controller for `MKButtonView`.";
 smalltalk.addMethod(
 smalltalk.method({
-selector: "onPressed",
+selector: "onClick:",
 category: 'actions',
-fn: function (){
+fn: function (anEvent){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-self._performAction();
-return self}, function($ctx1) {$ctx1.fill(self,"onPressed",{},smalltalk.MKButtonController)})},
-args: [],
-source: "onPressed\x0a\x09self performAction",
-messageSends: ["performAction"],
+self._performAspectAction();
+return self}, function($ctx1) {$ctx1.fill(self,"onClick:",{anEvent:anEvent},smalltalk.MKButtonController)})},
+args: ["anEvent"],
+source: "onClick: anEvent\x0a\x09self performAspectAction",
+messageSends: ["performAspectAction"],
 referencedClasses: []
 }),
 smalltalk.MKButtonController);
 
 
 
-smalltalk.addClass('MKCheckboxController', smalltalk.MKAspectController, [], 'Moka-Controllers');
+smalltalk.addClass('MKCheckboxController', smalltalk.MKSingleAspectController, [], 'Moka-Controllers');
 smalltalk.MKCheckboxController.comment="I am the default controller for `MKCheckboxView`.";
 smalltalk.addMethod(
 smalltalk.method({
-selector: "onToggled:",
+selector: "onClick:",
+category: 'actions',
+fn: function (anEvent){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._toggle();
+return self}, function($ctx1) {$ctx1.fill(self,"onClick:",{anEvent:anEvent},smalltalk.MKCheckboxController)})},
+args: ["anEvent"],
+source: "onClick: anEvent\x0a\x09self toggle",
+messageSends: ["toggle"],
+referencedClasses: []
+}),
+smalltalk.MKCheckboxController);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "onKeyDown:",
+category: 'actions',
+fn: function (anEvent){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(anEvent)._stopPropagation();
+return self}, function($ctx1) {$ctx1.fill(self,"onKeyDown:",{anEvent:anEvent},smalltalk.MKCheckboxController)})},
+args: ["anEvent"],
+source: "onKeyDown: anEvent\x0a\x09\x22Avoid scrolling in scrollable views\x22\x0a\x09\x0a\x09anEvent stopPropagation",
+messageSends: ["stopPropagation"],
+referencedClasses: []
+}),
+smalltalk.MKCheckboxController);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "onKeyPress:",
+category: 'actions',
+fn: function (anEvent){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1,$2;
+$1=_st(_st(anEvent)._charCode()).__eq(" "._asciiValue());
+if(smalltalk.assert($1)){
+self._toggle();
+_st(anEvent)._stopPropagation();
+$2=_st(anEvent)._preventDefault();
+$2;
+};
+return self}, function($ctx1) {$ctx1.fill(self,"onKeyPress:",{anEvent:anEvent},smalltalk.MKCheckboxController)})},
+args: ["anEvent"],
+source: "onKeyPress: anEvent\x0a\x09anEvent charCode = ' ' asciiValue ifTrue: [ \x0a\x09\x09self toggle.\x0a\x09\x09anEvent stopPropagation; preventDefault ]",
+messageSends: ["ifTrue:", "=", "charCode", "asciiValue", "toggle", "stopPropagation", "preventDefault"],
+referencedClasses: []
+}),
+smalltalk.MKCheckboxController);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "toggle",
 category: 'actions',
-fn: function (aBoolean){
+fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-self._performActionWith_(aBoolean);
-return self}, function($ctx1) {$ctx1.fill(self,"onToggled:",{aBoolean:aBoolean},smalltalk.MKCheckboxController)})},
-args: ["aBoolean"],
-source: "onToggled: aBoolean\x0a\x09self performActionWith: aBoolean",
-messageSends: ["performActionWith:"],
+self._performAspectActionWith_(_st(_st(self._view())._checked())._not());
+return self}, function($ctx1) {$ctx1.fill(self,"toggle",{},smalltalk.MKCheckboxController)})},
+args: [],
+source: "toggle\x0a\x09self performAspectActionWith: self view checked not",
+messageSends: ["performAspectActionWith:", "not", "checked", "view"],
 referencedClasses: []
 }),
 smalltalk.MKCheckboxController);
 
 
+
+smalltalk.addClass('MKDropdownController', smalltalk.MKAspectsController, [], 'Moka-Controllers');
+smalltalk.addMethod(
+smalltalk.method({
+selector: "onClick:",
+category: 'actions',
+fn: function (anEvent){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self._view())._popupList();
+return self}, function($ctx1) {$ctx1.fill(self,"onClick:",{anEvent:anEvent},smalltalk.MKDropdownController)})},
+args: ["anEvent"],
+source: "onClick: anEvent\x0a\x09self view popupList",
+messageSends: ["popupList", "view"],
+referencedClasses: []
+}),
+smalltalk.MKDropdownController);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "onKeyDown:",
+category: 'actions',
+fn: function (anEvent){
+var self=this;
+function $String(){return smalltalk.String||(typeof String=="undefined"?nil:String)}
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(_st(anEvent)._keyCode()).__eq(_st(_st($String())._cr())._asciiValue());
+if(smalltalk.assert($1)){
+_st(self._view())._popupList();
+};
+return self}, function($ctx1) {$ctx1.fill(self,"onKeyDown:",{anEvent:anEvent},smalltalk.MKDropdownController)})},
+args: ["anEvent"],
+source: "onKeyDown: anEvent\x0a\x09anEvent keyCode = String cr asciiValue ifTrue: [\x0a\x09\x09self view popupList ]",
+messageSends: ["ifTrue:", "=", "keyCode", "asciiValue", "cr", "popupList", "view"],
+referencedClasses: ["String"]
+}),
+smalltalk.MKDropdownController);
+
+
+
+smalltalk.addClass('MKListController', smalltalk.MKAspectsController, ['downRepeater', 'upRepeater'], 'Moka-Controllers');
+smalltalk.addMethod(
+smalltalk.method({
+selector: "activateItem:",
+category: 'actions',
+fn: function (anItem){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._selectItem_(anItem);
+return self}, function($ctx1) {$ctx1.fill(self,"activateItem:",{anItem:anItem},smalltalk.MKListController)})},
+args: ["anItem"],
+source: "activateItem: anItem\x0a\x09\x22On item activation, change the model selection\x22\x0a\x09\x0a\x09self selectItem: anItem",
+messageSends: ["selectItem:"],
+referencedClasses: []
+}),
+smalltalk.MKListController);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "activeItem",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(self._view())._activeItem();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"activeItem",{},smalltalk.MKListController)})},
+args: [],
+source: "activeItem\x0a\x09^ self view activeItem",
+messageSends: ["activeItem", "view"],
+referencedClasses: []
+}),
+smalltalk.MKListController);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "collection",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(self._view())._collection();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"collection",{},smalltalk.MKListController)})},
+args: [],
+source: "collection\x0a\x09^ self view collection",
+messageSends: ["collection", "view"],
+referencedClasses: []
+}),
+smalltalk.MKListController);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "downRepeater",
+category: 'accessing',
+fn: function (){
+var self=this;
+function $MKRepeater(){return smalltalk.MKRepeater||(typeof MKRepeater=="undefined"?nil:MKRepeater)}
+return smalltalk.withContext(function($ctx1) { 
+var $2,$1;
+$2=self["@downRepeater"];
+if(($receiver = $2) == nil || $receiver == null){
+self["@downRepeater"]=_st($MKRepeater())._new();
+$1=self["@downRepeater"];
+} else {
+$1=$2;
+};
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"downRepeater",{},smalltalk.MKListController)})},
+args: [],
+source: "downRepeater\x0a\x09^ downRepeater ifNil: [ downRepeater := MKRepeater new ]",
+messageSends: ["ifNil:", "new"],
+referencedClasses: ["MKRepeater"]
+}),
+smalltalk.MKListController);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "itemForTarget:",
+category: 'private',
+fn: function (aDOMElement){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(self._view())._findItemFor_(aDOMElement);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"itemForTarget:",{aDOMElement:aDOMElement},smalltalk.MKListController)})},
+args: ["aDOMElement"],
+source: "itemForTarget: aDOMElement\x0a\x09^ self view findItemFor: aDOMElement",
+messageSends: ["findItemFor:", "view"],
+referencedClasses: []
+}),
+smalltalk.MKListController);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "nextItem",
+category: 'private',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$5,$4,$3,$1;
+$2=self._collection();
+$ctx1.sendIdx["collection"]=1;
+$5=self._collection();
+$ctx1.sendIdx["collection"]=2;
+$4=_st($5)._indexOf_(self._activeItem());
+$3=_st($4).__plus((1));
+$1=_st($2)._at_ifAbsent_($3,(function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(self._collection())._last();
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"nextItem",{},smalltalk.MKListController)})},
+args: [],
+source: "nextItem\x0a\x09^ self collection \x0a\x09\x09at: (self collection indexOf: self activeItem) + 1\x0a\x09\x09ifAbsent: [ self collection last ]",
+messageSends: ["at:ifAbsent:", "collection", "+", "indexOf:", "activeItem", "last"],
+referencedClasses: []
+}),
+smalltalk.MKListController);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "onClick:",
+category: 'actions',
+fn: function (anEvent){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._selectItem_(self._itemForTarget_(_st(anEvent)._target()));
+return self}, function($ctx1) {$ctx1.fill(self,"onClick:",{anEvent:anEvent},smalltalk.MKListController)})},
+args: ["anEvent"],
+source: "onClick: anEvent\x0a\x09self selectItem: (self itemForTarget: anEvent target)",
+messageSends: ["selectItem:", "itemForTarget:", "target"],
+referencedClasses: []
+}),
+smalltalk.MKListController);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "onKeyDown:",
+category: 'actions',
+fn: function (anEvent){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$1,$3,$4,$5,$6,$7;
+$2=_st(anEvent)._keyCode();
+$ctx1.sendIdx["keyCode"]=1;
+$1=_st($2).__eq((40));
+$ctx1.sendIdx["="]=1;
+if(smalltalk.assert($1)){
+_st(anEvent)._preventDefault();
+$ctx1.sendIdx["preventDefault"]=1;
+$3=_st(anEvent)._stopPropagation();
+$ctx1.sendIdx["stopPropagation"]=1;
+$3;
+$4=self._upRepeater();
+$ctx1.sendIdx["upRepeater"]=1;
+_st($4)._stopRepeating();
+$ctx1.sendIdx["stopRepeating"]=1;
+$5=self._downRepeater();
+$ctx1.sendIdx["downRepeater"]=1;
+_st($5)._repeat_((function(){
+return smalltalk.withContext(function($ctx2) {
+return self._activateItem_(self._nextItem());
+$ctx2.sendIdx["activateItem:"]=1;
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}));
+$ctx1.sendIdx["repeat:"]=1;
+};
+$6=_st(_st(anEvent)._keyCode()).__eq((38));
+if(smalltalk.assert($6)){
+_st(anEvent)._preventDefault();
+$7=_st(anEvent)._stopPropagation();
+$7;
+_st(self._downRepeater())._stopRepeating();
+_st(self._upRepeater())._repeat_((function(){
+return smalltalk.withContext(function($ctx2) {
+return self._activateItem_(self._previousItem());
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,4)})}));
+};
+return self}, function($ctx1) {$ctx1.fill(self,"onKeyDown:",{anEvent:anEvent},smalltalk.MKListController)})},
+args: ["anEvent"],
+source: "onKeyDown: anEvent\x0a\x09\x22Down\x22\x0a\x09anEvent keyCode = 40 ifTrue: [ \x0a\x09\x09anEvent preventDefault; stopPropagation.\x0a\x09\x09self upRepeater stopRepeating.\x0a\x09\x09self downRepeater repeat: [ \x0a\x09\x09\x09self activateItem: self nextItem ] ].\x0a\x09\x22Up\x22\x0a\x09anEvent keyCode = 38 ifTrue: [ \x0a\x09\x09anEvent preventDefault; stopPropagation.\x0a\x09\x09self downRepeater stopRepeating.\x0a\x09\x09self upRepeater repeat: [ \x0a\x09\x09\x09self activateItem: self previousItem ] ].",
+messageSends: ["ifTrue:", "=", "keyCode", "preventDefault", "stopPropagation", "stopRepeating", "upRepeater", "repeat:", "downRepeater", "activateItem:", "nextItem", "previousItem"],
+referencedClasses: []
+}),
+smalltalk.MKListController);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "onKeyUp:",
+category: 'actions',
+fn: function (anEvent){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self._downRepeater())._stopRepeating();
+$ctx1.sendIdx["stopRepeating"]=1;
+_st(self._upRepeater())._stopRepeating();
+return self}, function($ctx1) {$ctx1.fill(self,"onKeyUp:",{anEvent:anEvent},smalltalk.MKListController)})},
+args: ["anEvent"],
+source: "onKeyUp: anEvent\x0a\x09self downRepeater stopRepeating.\x0a\x09self upRepeater stopRepeating",
+messageSends: ["stopRepeating", "downRepeater", "upRepeater"],
+referencedClasses: []
+}),
+smalltalk.MKListController);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "previousItem",
+category: 'private',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $3,$2,$7,$6,$5,$4,$1;
+$3=self._view();
+$ctx1.sendIdx["view"]=1;
+$2=_st($3)._collection();
+$ctx1.sendIdx["collection"]=1;
+$7=self._view();
+$ctx1.sendIdx["view"]=2;
+$6=_st($7)._collection();
+$ctx1.sendIdx["collection"]=2;
+$5=_st($6)._indexOf_(self._activeItem());
+$4=_st($5).__minus((1));
+$1=_st($2)._at_ifAbsent_($4,(function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(_st(self._view())._collection())._first();
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"previousItem",{},smalltalk.MKListController)})},
+args: [],
+source: "previousItem\x0a\x09^ self view collection \x0a\x09\x09at: (self view collection indexOf: self activeItem) - 1\x0a\x09\x09ifAbsent: [ self view collection first ]",
+messageSends: ["at:ifAbsent:", "collection", "view", "-", "indexOf:", "activeItem", "first"],
+referencedClasses: []
+}),
+smalltalk.MKListController);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "selectItem:",
+category: 'actions',
+fn: function (anItem){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._performAspectAction_with_(_st(self._view())._selectionAspect(),anItem);
+return self}, function($ctx1) {$ctx1.fill(self,"selectItem:",{anItem:anItem},smalltalk.MKListController)})},
+args: ["anItem"],
+source: "selectItem: anItem\x0a\x09self \x0a\x09\x09performAspectAction: self view selectionAspect \x0a\x09\x09with: anItem",
+messageSends: ["performAspectAction:with:", "selectionAspect", "view"],
+referencedClasses: []
+}),
+smalltalk.MKListController);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "upRepeater",
+category: 'accessing',
+fn: function (){
+var self=this;
+function $MKRepeater(){return smalltalk.MKRepeater||(typeof MKRepeater=="undefined"?nil:MKRepeater)}
+return smalltalk.withContext(function($ctx1) { 
+var $2,$1;
+$2=self["@upRepeater"];
+if(($receiver = $2) == nil || $receiver == null){
+self["@upRepeater"]=_st($MKRepeater())._new();
+$1=self["@upRepeater"];
+} else {
+$1=$2;
+};
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"upRepeater",{},smalltalk.MKListController)})},
+args: [],
+source: "upRepeater\x0a\x09^ upRepeater ifNil: [ upRepeater := MKRepeater new ]",
+messageSends: ["ifNil:", "new"],
+referencedClasses: ["MKRepeater"]
+}),
+smalltalk.MKListController);
+
+
+
+smalltalk.addClass('MKDropdownListController', smalltalk.MKListController, [], 'Moka-Controllers');
+smalltalk.addMethod(
+smalltalk.method({
+selector: "activateItem:",
+category: 'actions',
+fn: function (anItem){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self._view())._activateItem_(anItem);
+return self}, function($ctx1) {$ctx1.fill(self,"activateItem:",{anItem:anItem},smalltalk.MKDropdownListController)})},
+args: ["anItem"],
+source: "activateItem: anItem\x0a\x09\x22Select the list item in the view.\x0a\x09No change is done to the model\x22\x0a\x09\x0a\x09self view activateItem: anItem",
+messageSends: ["activateItem:", "view"],
+referencedClasses: []
+}),
+smalltalk.MKDropdownListController);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "onKeyDown:",
+category: 'actions',
+fn: function (anEvent){
+var self=this;
+function $String(){return smalltalk.String||(typeof String=="undefined"?nil:String)}
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+smalltalk.MKDropdownListController.superclass.fn.prototype._onKeyDown_.apply(_st(self), [anEvent]);
+$1=_st(_st(anEvent)._keyCode()).__eq(_st(_st($String())._cr())._asciiValue());
+if(smalltalk.assert($1)){
+self._selectItem_(self._itemForTarget_(_st(anEvent)._target()));
+};
+return self}, function($ctx1) {$ctx1.fill(self,"onKeyDown:",{anEvent:anEvent},smalltalk.MKDropdownListController)})},
+args: ["anEvent"],
+source: "onKeyDown: anEvent\x0a\x09super onKeyDown: anEvent.\x0a\x09\x0a\x09anEvent keyCode = String cr asciiValue ifTrue: [\x0a\x09\x09self selectItem: (self itemForTarget: anEvent target) ]",
+messageSends: ["onKeyDown:", "ifTrue:", "=", "keyCode", "asciiValue", "cr", "selectItem:", "itemForTarget:", "target"],
+referencedClasses: ["String"]
+}),
+smalltalk.MKDropdownListController);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "onMouseMove:",
+category: 'actions',
+fn: function (anEvent){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$1;
+$2=_st(self._upRepeater())._isRepeating();
+$ctx1.sendIdx["isRepeating"]=1;
+$1=_st($2)._or_((function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(self._downRepeater())._isRepeating();
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+if(smalltalk.assert($1)){
+return self;
+};
+self._activateItem_(self._itemForTarget_(_st(anEvent)._target()));
+return self}, function($ctx1) {$ctx1.fill(self,"onMouseMove:",{anEvent:anEvent},smalltalk.MKDropdownListController)})},
+args: ["anEvent"],
+source: "onMouseMove: anEvent\x0a\x09(self upRepeater isRepeating or: [ self downRepeater isRepeating ])\x0a\x09\x09ifTrue: [ ^ self ].\x0a\x09\x09\x0a\x09self activateItem: (self itemForTarget: anEvent target)",
+messageSends: ["ifTrue:", "or:", "isRepeating", "upRepeater", "downRepeater", "activateItem:", "itemForTarget:", "target"],
+referencedClasses: []
+}),
+smalltalk.MKDropdownListController);
+
+
+
+smalltalk.addClass('MKModalPaneController', smalltalk.MKSingleAspectController, [], 'Moka-Controllers');
+smalltalk.addMethod(
+smalltalk.method({
+selector: "onClick:",
+category: 'actions',
+fn: function (anEvent){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(self._view())._closeOnClick();
+if(smalltalk.assert($1)){
+self._removeView();
+};
+return self}, function($ctx1) {$ctx1.fill(self,"onClick:",{anEvent:anEvent},smalltalk.MKModalPaneController)})},
+args: ["anEvent"],
+source: "onClick: anEvent\x0a\x09self view closeOnClick ifTrue: [ self removeView ]",
+messageSends: ["ifTrue:", "closeOnClick", "view", "removeView"],
+referencedClasses: []
+}),
+smalltalk.MKModalPaneController);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "onKeyDown:",
+category: 'actions',
+fn: function (anEvent){
+var self=this;
+function $String(){return smalltalk.String||(typeof String=="undefined"?nil:String)}
+return smalltalk.withContext(function($ctx1) { 
+var $2,$1,$3,$4;
+$2=_st(anEvent)._keyCode();
+$ctx1.sendIdx["keyCode"]=1;
+$1=_st($2).__eq((27));
+$ctx1.sendIdx["="]=1;
+if(smalltalk.assert($1)){
+self._removeView();
+$ctx1.sendIdx["removeView"]=1;
+};
+$3=_st(self._view())._closeOnEnter();
+if(smalltalk.assert($3)){
+$4=_st(_st(anEvent)._keyCode()).__eq(_st(_st($String())._cr())._asciiValue());
+if(smalltalk.assert($4)){
+self._removeView();
+};
+};
+return self}, function($ctx1) {$ctx1.fill(self,"onKeyDown:",{anEvent:anEvent},smalltalk.MKModalPaneController)})},
+args: ["anEvent"],
+source: "onKeyDown: anEvent\x0a\x09\x22ESC\x22\x0a\x09anEvent keyCode = 27 ifTrue: [\x0a\x09\x09self removeView ].\x0a\x09\x09\x0a\x09self view closeOnEnter ifTrue: [\x0a\x09\x09anEvent keyCode = String cr asciiValue ifTrue: [ \x0a\x09\x09\x09self removeView ] ]",
+messageSends: ["ifTrue:", "=", "keyCode", "removeView", "closeOnEnter", "view", "asciiValue", "cr"],
+referencedClasses: ["String"]
+}),
+smalltalk.MKModalPaneController);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "removeView",
+category: 'actions',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(_st(self._view())._overlay())._remove();
+return self}, function($ctx1) {$ctx1.fill(self,"removeView",{},smalltalk.MKModalPaneController)})},
+args: [],
+source: "removeView\x0a\x09self view overlay remove",
+messageSends: ["remove", "overlay", "view"],
+referencedClasses: []
+}),
+smalltalk.MKModalPaneController);
+
+
+
+smalltalk.addClass('MKOverlayController', smalltalk.MKSingleAspectController, [], 'Moka-Controllers');
+smalltalk.MKOverlayController.comment="I am the default controller for `MKOverlayView`.\x0a\x0aOn a click to the overlay, it is removed together with it's content view.";
+smalltalk.addMethod(
+smalltalk.method({
+selector: "onClick:",
+category: 'actions',
+fn: function (anEvent){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self._view())._remove();
+return self}, function($ctx1) {$ctx1.fill(self,"onClick:",{anEvent:anEvent},smalltalk.MKOverlayController)})},
+args: ["anEvent"],
+source: "onClick: anEvent\x0a\x09self view remove",
+messageSends: ["remove", "view"],
+referencedClasses: []
+}),
+smalltalk.MKOverlayController);
+
+
+
+smalltalk.addClass('MKRepeater', smalltalk.Object, ['repeatInterval', 'interval', 'delay'], 'Moka-Controllers');
+smalltalk.MKRepeater.comment="I am an internal class used by controllers to repeat block actions after a `delay` and with an `interval`.";
+smalltalk.addMethod(
+smalltalk.method({
+selector: "defaultRepeatInterval",
+category: 'defaults',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return (70);
+}, function($ctx1) {$ctx1.fill(self,"defaultRepeatInterval",{},smalltalk.MKRepeater)})},
+args: [],
+source: "defaultRepeatInterval\x0a\x09^ 70",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.MKRepeater);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "isRepeating",
+category: 'testing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(self["@delay"])._notNil();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"isRepeating",{},smalltalk.MKRepeater)})},
+args: [],
+source: "isRepeating\x0a\x09^ delay notNil",
+messageSends: ["notNil"],
+referencedClasses: []
+}),
+smalltalk.MKRepeater);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "repeat:",
+category: 'actions',
+fn: function (aBlock){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=self._isRepeating();
+if(smalltalk.assert($1)){
+return self;
+};
+_st(aBlock)._value();
+self["@delay"]=_st((function(){
+return smalltalk.withContext(function($ctx2) {
+self["@interval"]=_st(aBlock)._valueWithInterval_(self._repeatInterval());
+return self["@interval"];
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}))._valueWithTimeout_((300));
+return self}, function($ctx1) {$ctx1.fill(self,"repeat:",{aBlock:aBlock},smalltalk.MKRepeater)})},
+args: ["aBlock"],
+source: "repeat: aBlock\x0a\x09self isRepeating ifTrue: [ ^ self ].\x0a\x09aBlock value.\x0a\x09delay := [ interval := aBlock valueWithInterval: self repeatInterval ] \x0a\x09\x09valueWithTimeout: 300",
+messageSends: ["ifTrue:", "isRepeating", "value", "valueWithTimeout:", "valueWithInterval:", "repeatInterval"],
+referencedClasses: []
+}),
+smalltalk.MKRepeater);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "repeatInterval",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$1;
+$2=self["@repeatInterval"];
+if(($receiver = $2) == nil || $receiver == null){
+$1=self._defaultRepeatInterval();
+} else {
+$1=$2;
+};
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"repeatInterval",{},smalltalk.MKRepeater)})},
+args: [],
+source: "repeatInterval\x0a\x09^ repeatInterval ifNil: [ self defaultRepeatInterval ]",
+messageSends: ["ifNil:", "defaultRepeatInterval"],
+referencedClasses: []
+}),
+smalltalk.MKRepeater);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "repeatInterval:",
+category: 'accessing',
+fn: function (aNumber){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self["@repeatInterval"]=aNumber;
+return self}, function($ctx1) {$ctx1.fill(self,"repeatInterval:",{aNumber:aNumber},smalltalk.MKRepeater)})},
+args: ["aNumber"],
+source: "repeatInterval: aNumber\x0a\x09repeatInterval := aNumber",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.MKRepeater);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "stopRepeating",
+category: 'actions',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1,$2;
+$1=self["@interval"];
+if(($receiver = $1) == nil || $receiver == null){
+$1;
+} else {
+_st(self["@interval"])._clearInterval();
+};
+$2=self["@delay"];
+if(($receiver = $2) == nil || $receiver == null){
+$2;
+} else {
+_st(self["@delay"])._clearTimeout();
+};
+self["@delay"]=nil;
+self["@interval"]=self["@delay"];
+return self}, function($ctx1) {$ctx1.fill(self,"stopRepeating",{},smalltalk.MKRepeater)})},
+args: [],
+source: "stopRepeating\x0a\x09interval ifNotNil: [ interval clearInterval ].\x0a\x09delay ifNotNil: [ delay clearTimeout ].\x0a\x09interval := delay := nil",
+messageSends: ["ifNotNil:", "clearInterval", "clearTimeout"],
+referencedClasses: []
+}),
+smalltalk.MKRepeater);
+
+
 });

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 753 - 116
js/Moka-Core.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 328 - 40
js/Moka-Examples.js


+ 784 - 0
js/Moka-Layouts.js

@@ -0,0 +1,784 @@
+define("amber_core/Moka-Layouts", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_core/Kernel-Objects", "amber_core/Kernel-Collections"], function(smalltalk,nil,_st){
+smalltalk.addPackage('Moka-Layouts');
+smalltalk.packages["Moka-Layouts"].transport = {"type":"amd","amdNamespace":"amber_core"};
+
+smalltalk.addClass('MKLayout', smalltalk.Object, ['properties'], 'Moka-Layouts');
+smalltalk.addMethod(
+smalltalk.method({
+selector: "asCssString",
+category: 'converting',
+fn: function (){
+var self=this;
+function $String(){return smalltalk.String||(typeof String=="undefined"?nil:String)}
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st($String())._streamContents_((function(stream){
+return smalltalk.withContext(function($ctx2) {
+return _st(self["@properties"])._valuesDo_((function(each){
+return smalltalk.withContext(function($ctx3) {
+_st(each)._printCssOn_(stream);
+return _st(stream).__lt_lt(";");
+}, function($ctx3) {$ctx3.fillBlock({each:each},$ctx2,2)})}));
+}, function($ctx2) {$ctx2.fillBlock({stream:stream},$ctx1,1)})}));
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"asCssString",{},smalltalk.MKLayout)})},
+args: [],
+source: "asCssString\x0a\x09^ String streamContents: [ :stream |\x0a\x09\x09properties valuesDo: [ :each | \x0a\x09\x09\x09each printCssOn: stream.\x0a\x09\x09\x09stream << ';' ] ]",
+messageSends: ["streamContents:", "valuesDo:", "printCssOn:", "<<"],
+referencedClasses: ["String"]
+}),
+smalltalk.MKLayout);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "bottom:",
+category: 'accessing',
+fn: function (aNumber){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+_st(self["@properties"])._at_put_("bottom",self._propertyLabelled_value_("bottom",aNumber));
+$1=self._hasProperty_("top");
+if(smalltalk.assert($1)){
+self._removeProperty_("height");
+$ctx1.sendIdx["removeProperty:"]=1;
+};
+self._removeProperty_("centerY");
+return self}, function($ctx1) {$ctx1.fill(self,"bottom:",{aNumber:aNumber},smalltalk.MKLayout)})},
+args: ["aNumber"],
+source: "bottom: aNumber\x0a\x09properties \x0a\x09\x09at: 'bottom' \x0a\x09\x09put: (self propertyLabelled: 'bottom' value: aNumber).\x0a\x09\x0a\x09(self hasProperty: 'top') ifTrue: [\x0a\x09\x09self removeProperty: 'height' ].\x0a\x09self removeProperty: 'centerY'",
+messageSends: ["at:put:", "propertyLabelled:value:", "ifTrue:", "hasProperty:", "removeProperty:"],
+referencedClasses: []
+}),
+smalltalk.MKLayout);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "centerX:",
+category: 'accessing',
+fn: function (aNumber){
+var self=this;
+function $MKHorizontalCenteringLayoutProperty(){return smalltalk.MKHorizontalCenteringLayoutProperty||(typeof MKHorizontalCenteringLayoutProperty=="undefined"?nil:MKHorizontalCenteringLayoutProperty)}
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+_st(self["@properties"])._at_put_("centerX",_st($MKHorizontalCenteringLayoutProperty())._layout_value_(self,aNumber));
+self._removeProperty_("left");
+$ctx1.sendIdx["removeProperty:"]=1;
+$1=self._removeProperty_("right");
+return self}, function($ctx1) {$ctx1.fill(self,"centerX:",{aNumber:aNumber},smalltalk.MKLayout)})},
+args: ["aNumber"],
+source: "centerX: aNumber\x0a\x09properties\x0a\x09\x09at: 'centerX'\x0a\x09\x09put: (MKHorizontalCenteringLayoutProperty layout: self value: aNumber).\x0a\x09\x0a\x09self \x0a\x09\x09removeProperty: 'left';\x0a\x09\x09removeProperty: 'right'",
+messageSends: ["at:put:", "layout:value:", "removeProperty:"],
+referencedClasses: ["MKHorizontalCenteringLayoutProperty"]
+}),
+smalltalk.MKLayout);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "centerY:",
+category: 'accessing',
+fn: function (aNumber){
+var self=this;
+function $MKVerticalCenteringLayoutProperty(){return smalltalk.MKVerticalCenteringLayoutProperty||(typeof MKVerticalCenteringLayoutProperty=="undefined"?nil:MKVerticalCenteringLayoutProperty)}
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+_st(self["@properties"])._at_put_("centerY",_st($MKVerticalCenteringLayoutProperty())._layout_value_(self,aNumber));
+self._removeProperty_("top");
+$ctx1.sendIdx["removeProperty:"]=1;
+$1=self._removeProperty_("bottom");
+return self}, function($ctx1) {$ctx1.fill(self,"centerY:",{aNumber:aNumber},smalltalk.MKLayout)})},
+args: ["aNumber"],
+source: "centerY: aNumber\x0a\x09properties\x0a\x09\x09at: 'centerY'\x0a\x09\x09put: (MKVerticalCenteringLayoutProperty layout: self value: aNumber).\x0a\x09\x09\x0a\x09self \x0a\x09\x09removeProperty: 'top';\x0a\x09\x09removeProperty: 'bottom'",
+messageSends: ["at:put:", "layout:value:", "removeProperty:"],
+referencedClasses: ["MKVerticalCenteringLayoutProperty"]
+}),
+smalltalk.MKLayout);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "hasProperty:",
+category: 'private',
+fn: function (aString){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(self["@properties"])._includesKey_(aString);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"hasProperty:",{aString:aString},smalltalk.MKLayout)})},
+args: ["aString"],
+source: "hasProperty: aString\x0a\x09^ properties includesKey: aString",
+messageSends: ["includesKey:"],
+referencedClasses: []
+}),
+smalltalk.MKLayout);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "height",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(self["@properties"])._at_ifPresent_ifAbsent_("height",(function(property){
+return smalltalk.withContext(function($ctx2) {
+return _st(property)._value();
+}, function($ctx2) {$ctx2.fillBlock({property:property},$ctx1,1)})}),(function(){
+return smalltalk.withContext(function($ctx2) {
+return (1);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}));
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"height",{},smalltalk.MKLayout)})},
+args: [],
+source: "height\x0a\x09^ properties \x0a\x09\x09at: 'height' \x0a\x09\x09ifPresent: [ :property | property value ]\x0a\x09\x09ifAbsent: [ 1 ]",
+messageSends: ["at:ifPresent:ifAbsent:", "value"],
+referencedClasses: []
+}),
+smalltalk.MKLayout);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "height:",
+category: 'accessing',
+fn: function (aNumber){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+_st(self["@properties"])._at_put_("height",self._propertyLabelled_value_("height",aNumber));
+$1=self._hasProperty_("top");
+if(smalltalk.assert($1)){
+self._removeProperty_("bottom");
+};
+return self}, function($ctx1) {$ctx1.fill(self,"height:",{aNumber:aNumber},smalltalk.MKLayout)})},
+args: ["aNumber"],
+source: "height: aNumber\x0a\x09properties \x0a\x09\x09at: 'height' \x0a\x09\x09put: (self propertyLabelled: 'height' value: aNumber).\x0a\x09\x0a\x09(self hasProperty: 'top') ifTrue: [\x0a\x09\x09self removeProperty: 'bottom' ]",
+messageSends: ["at:put:", "propertyLabelled:value:", "ifTrue:", "hasProperty:", "removeProperty:"],
+referencedClasses: []
+}),
+smalltalk.MKLayout);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "initialize",
+category: 'initialization',
+fn: function (){
+var self=this;
+function $Dictionary(){return smalltalk.Dictionary||(typeof Dictionary=="undefined"?nil:Dictionary)}
+return smalltalk.withContext(function($ctx1) { 
+smalltalk.MKLayout.superclass.fn.prototype._initialize.apply(_st(self), []);
+self["@properties"]=_st($Dictionary())._new();
+return self}, function($ctx1) {$ctx1.fill(self,"initialize",{},smalltalk.MKLayout)})},
+args: [],
+source: "initialize\x0a\x09super initialize.\x0a\x09properties := Dictionary new",
+messageSends: ["initialize", "new"],
+referencedClasses: ["Dictionary"]
+}),
+smalltalk.MKLayout);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "left:",
+category: 'accessing',
+fn: function (aNumber){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+_st(self["@properties"])._at_put_("left",self._propertyLabelled_value_("left",aNumber));
+$1=self._hasProperty_("width");
+if(smalltalk.assert($1)){
+self._removeProperty_("right");
+$ctx1.sendIdx["removeProperty:"]=1;
+};
+self._removeProperty_("centerX");
+return self}, function($ctx1) {$ctx1.fill(self,"left:",{aNumber:aNumber},smalltalk.MKLayout)})},
+args: ["aNumber"],
+source: "left: aNumber\x0a\x09properties \x0a\x09\x09at: 'left' \x0a\x09\x09put: (self propertyLabelled: 'left' value: aNumber).\x0a\x09\x0a\x09(self hasProperty: 'width') ifTrue: [\x0a\x09\x09self removeProperty: 'right' ].\x0a\x09self removeProperty: 'centerX'",
+messageSends: ["at:put:", "propertyLabelled:value:", "ifTrue:", "hasProperty:", "removeProperty:"],
+referencedClasses: []
+}),
+smalltalk.MKLayout);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "propertyLabelled:value:",
+category: 'factory',
+fn: function (aString,aValue){
+var self=this;
+function $MKLabelledLayoutProperty(){return smalltalk.MKLabelledLayoutProperty||(typeof MKLabelledLayoutProperty=="undefined"?nil:MKLabelledLayoutProperty)}
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st($MKLabelledLayoutProperty())._layout_label_value_(self,aString,aValue);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"propertyLabelled:value:",{aString:aString,aValue:aValue},smalltalk.MKLayout)})},
+args: ["aString", "aValue"],
+source: "propertyLabelled: aString value: aValue\x0a\x09^ MKLabelledLayoutProperty layout: self label: aString value: aValue",
+messageSends: ["layout:label:value:"],
+referencedClasses: ["MKLabelledLayoutProperty"]
+}),
+smalltalk.MKLayout);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "removeProperty:",
+category: 'private',
+fn: function (aString){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self["@properties"])._remove_ifAbsent_(aString,(function(){
+return smalltalk.withContext(function($ctx2) {
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+return self}, function($ctx1) {$ctx1.fill(self,"removeProperty:",{aString:aString},smalltalk.MKLayout)})},
+args: ["aString"],
+source: "removeProperty: aString\x0a\x09properties remove: aString ifAbsent: []",
+messageSends: ["remove:ifAbsent:"],
+referencedClasses: []
+}),
+smalltalk.MKLayout);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "right:",
+category: 'accessing',
+fn: function (aNumber){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+_st(self["@properties"])._at_put_("right",self._propertyLabelled_value_("right",aNumber));
+$1=self._hasProperty_("width");
+if(smalltalk.assert($1)){
+self._removeProperty_("left");
+$ctx1.sendIdx["removeProperty:"]=1;
+};
+self._removeProperty_("centerX");
+return self}, function($ctx1) {$ctx1.fill(self,"right:",{aNumber:aNumber},smalltalk.MKLayout)})},
+args: ["aNumber"],
+source: "right: aNumber\x0a\x09properties \x0a\x09\x09at: 'right' \x0a\x09\x09put: (self propertyLabelled: 'right' value: aNumber).\x0a\x09\x0a\x09(self hasProperty: 'width') ifTrue: [\x0a\x09\x09self removeProperty: 'left' ].\x0a\x09self removeProperty: 'centerX'",
+messageSends: ["at:put:", "propertyLabelled:value:", "ifTrue:", "hasProperty:", "removeProperty:"],
+referencedClasses: []
+}),
+smalltalk.MKLayout);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "top:",
+category: 'accessing',
+fn: function (aNumber){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+_st(self["@properties"])._at_put_("top",self._propertyLabelled_value_("top",aNumber));
+$1=self._hasProperty_("height");
+if(smalltalk.assert($1)){
+self._removeProperty_("bottom");
+$ctx1.sendIdx["removeProperty:"]=1;
+};
+self._removeProperty_("centerY");
+return self}, function($ctx1) {$ctx1.fill(self,"top:",{aNumber:aNumber},smalltalk.MKLayout)})},
+args: ["aNumber"],
+source: "top: aNumber\x0a\x09properties \x0a\x09\x09at: 'top' \x0a\x09\x09put: (self propertyLabelled: 'top' value: aNumber).\x0a\x09\x0a\x09(self hasProperty: 'height') ifTrue: [\x0a\x09\x09self removeProperty: 'bottom' ].\x0a\x09self removeProperty: 'centerY'",
+messageSends: ["at:put:", "propertyLabelled:value:", "ifTrue:", "hasProperty:", "removeProperty:"],
+referencedClasses: []
+}),
+smalltalk.MKLayout);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "width",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(self["@properties"])._at_ifPresent_ifAbsent_("width",(function(property){
+return smalltalk.withContext(function($ctx2) {
+return _st(property)._value();
+}, function($ctx2) {$ctx2.fillBlock({property:property},$ctx1,1)})}),(function(){
+return smalltalk.withContext(function($ctx2) {
+return (1);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}));
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"width",{},smalltalk.MKLayout)})},
+args: [],
+source: "width\x0a\x09^ properties \x0a\x09\x09at: 'width' \x0a\x09\x09ifPresent: [ :property | property value ]\x0a\x09\x09ifAbsent: [ 1 ]",
+messageSends: ["at:ifPresent:ifAbsent:", "value"],
+referencedClasses: []
+}),
+smalltalk.MKLayout);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "width:",
+category: 'accessing',
+fn: function (aNumber){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+_st(self["@properties"])._at_put_("width",self._propertyLabelled_value_("width",aNumber));
+$1=self._hasProperty_("left");
+if(smalltalk.assert($1)){
+self._removeProperty_("right");
+};
+return self}, function($ctx1) {$ctx1.fill(self,"width:",{aNumber:aNumber},smalltalk.MKLayout)})},
+args: ["aNumber"],
+source: "width: aNumber\x0a\x09properties \x0a\x09\x09at: 'width' \x0a\x09\x09put: (self propertyLabelled: 'width' value: aNumber).\x0a\x09\x0a\x09(self hasProperty: 'left') ifTrue: [\x0a\x09\x09self removeProperty: 'right' ]",
+messageSends: ["at:put:", "propertyLabelled:value:", "ifTrue:", "hasProperty:", "removeProperty:"],
+referencedClasses: []
+}),
+smalltalk.MKLayout);
+
+
+
+smalltalk.addClass('MKLabelLayout', smalltalk.MKLayout, [], 'Moka-Layouts');
+smalltalk.MKLabelLayout.comment="I am a specialized layout for label views. I can set a `textAlign` property, taking a string argument, `'left'`, `'center'` or `'right'`.";
+smalltalk.addMethod(
+smalltalk.method({
+selector: "textAlign:",
+category: 'accessing',
+fn: function (aString){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self["@properties"])._at_put_("text-align",self._propertyLabelled_value_("text-align",aString));
+return self}, function($ctx1) {$ctx1.fill(self,"textAlign:",{aString:aString},smalltalk.MKLabelLayout)})},
+args: ["aString"],
+source: "textAlign: aString\x0a\x09\x22Map to CSS' text-align property. Possible values are `'left'`, `'center'` and `'right'`\x22\x0a\x09\x0a\x09properties \x0a\x09\x09at: 'text-align' \x0a\x09\x09put: (self propertyLabelled: 'text-align' value: aString)",
+messageSends: ["at:put:", "propertyLabelled:value:"],
+referencedClasses: []
+}),
+smalltalk.MKLabelLayout);
+
+
+
+smalltalk.addClass('MKPaneLayout', smalltalk.MKLayout, [], 'Moka-Layouts');
+smalltalk.MKPaneLayout.comment="I am a specialized layout for pane views. I can set border widths to my views.";
+smalltalk.addMethod(
+smalltalk.method({
+selector: "borderBottom:",
+category: 'accessing',
+fn: function (aNumber){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self["@properties"])._at_put_("border-bottom",self._propertyLabelled_value_("border-bottom-width",_st(aNumber)._asMokaPixelString()));
+return self}, function($ctx1) {$ctx1.fill(self,"borderBottom:",{aNumber:aNumber},smalltalk.MKPaneLayout)})},
+args: ["aNumber"],
+source: "borderBottom: aNumber\x0a\x09properties \x0a\x09\x09at: 'border-bottom' \x0a\x09\x09put: (self propertyLabelled: 'border-bottom-width' value: aNumber asMokaPixelString)",
+messageSends: ["at:put:", "propertyLabelled:value:", "asMokaPixelString"],
+referencedClasses: []
+}),
+smalltalk.MKPaneLayout);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "borderLeft:",
+category: 'accessing',
+fn: function (aNumber){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self["@properties"])._at_put_("border-left",self._propertyLabelled_value_("border-left-width",_st(aNumber)._asMokaPixelString()));
+return self}, function($ctx1) {$ctx1.fill(self,"borderLeft:",{aNumber:aNumber},smalltalk.MKPaneLayout)})},
+args: ["aNumber"],
+source: "borderLeft: aNumber\x0a\x09properties \x0a\x09\x09at: 'border-left' \x0a\x09\x09put: (self propertyLabelled: 'border-left-width' value: aNumber asMokaPixelString)",
+messageSends: ["at:put:", "propertyLabelled:value:", "asMokaPixelString"],
+referencedClasses: []
+}),
+smalltalk.MKPaneLayout);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "borderRight:",
+category: 'accessing',
+fn: function (aNumber){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self["@properties"])._at_put_("border-right",self._propertyLabelled_value_("border-right-width",_st(aNumber)._asMokaPixelString()));
+return self}, function($ctx1) {$ctx1.fill(self,"borderRight:",{aNumber:aNumber},smalltalk.MKPaneLayout)})},
+args: ["aNumber"],
+source: "borderRight: aNumber\x0a\x09properties \x0a\x09\x09at: 'border-right' \x0a\x09\x09put: (self propertyLabelled: 'border-right-width' value: aNumber asMokaPixelString)",
+messageSends: ["at:put:", "propertyLabelled:value:", "asMokaPixelString"],
+referencedClasses: []
+}),
+smalltalk.MKPaneLayout);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "borderTop:",
+category: 'accessing',
+fn: function (aNumber){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self["@properties"])._at_put_("border-top",self._propertyLabelled_value_("border-top-width",_st(aNumber)._asMokaPixelString()));
+return self}, function($ctx1) {$ctx1.fill(self,"borderTop:",{aNumber:aNumber},smalltalk.MKPaneLayout)})},
+args: ["aNumber"],
+source: "borderTop: aNumber\x0a\x09properties \x0a\x09\x09at: 'border-top' \x0a\x09\x09put: (self propertyLabelled: 'border-top-width' value: aNumber asMokaPixelString)",
+messageSends: ["at:put:", "propertyLabelled:value:", "asMokaPixelString"],
+referencedClasses: []
+}),
+smalltalk.MKPaneLayout);
+
+
+
+smalltalk.addClass('MKLayoutProperty', smalltalk.Object, ['layout', 'value'], 'Moka-Layouts');
+smalltalk.addMethod(
+smalltalk.method({
+selector: "asCssString",
+category: 'converting',
+fn: function (){
+var self=this;
+function $String(){return smalltalk.String||(typeof String=="undefined"?nil:String)}
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st($String())._streamContents_((function(stream){
+return smalltalk.withContext(function($ctx2) {
+return self._printCssOn_(stream);
+}, function($ctx2) {$ctx2.fillBlock({stream:stream},$ctx1,1)})}));
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"asCssString",{},smalltalk.MKLayoutProperty)})},
+args: [],
+source: "asCssString\x0a\x09^ String streamContents: [ :stream | \x0a\x09\x09self printCssOn: stream ]",
+messageSends: ["streamContents:", "printCssOn:"],
+referencedClasses: ["String"]
+}),
+smalltalk.MKLayoutProperty);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "layout",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=self["@layout"];
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"layout",{},smalltalk.MKLayoutProperty)})},
+args: [],
+source: "layout\x0a\x09^ layout",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.MKLayoutProperty);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "layout:",
+category: 'accessing',
+fn: function (aLayout){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self["@layout"]=aLayout;
+return self}, function($ctx1) {$ctx1.fill(self,"layout:",{aLayout:aLayout},smalltalk.MKLayoutProperty)})},
+args: ["aLayout"],
+source: "layout: aLayout\x0a\x09layout := aLayout",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.MKLayoutProperty);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "printCssOn:",
+category: 'printing',
+fn: function (aStream){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._subclassResponsibility();
+return self}, function($ctx1) {$ctx1.fill(self,"printCssOn:",{aStream:aStream},smalltalk.MKLayoutProperty)})},
+args: ["aStream"],
+source: "printCssOn: aStream\x0a\x09self subclassResponsibility",
+messageSends: ["subclassResponsibility"],
+referencedClasses: []
+}),
+smalltalk.MKLayoutProperty);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "value",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=self["@value"];
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"value",{},smalltalk.MKLayoutProperty)})},
+args: [],
+source: "value\x0a\x09^ value",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.MKLayoutProperty);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "value:",
+category: 'accessing',
+fn: function (aValue){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self["@value"]=aValue;
+return self}, function($ctx1) {$ctx1.fill(self,"value:",{aValue:aValue},smalltalk.MKLayoutProperty)})},
+args: ["aValue"],
+source: "value: aValue\x0a\x09value := aValue",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.MKLayoutProperty);
+
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "layout:value:",
+category: 'instance creation',
+fn: function (aLayout,aValue){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$3,$1;
+$2=self._new();
+_st($2)._layout_(aLayout);
+_st($2)._value_(aValue);
+$3=_st($2)._yourself();
+$1=$3;
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"layout:value:",{aLayout:aLayout,aValue:aValue},smalltalk.MKLayoutProperty.klass)})},
+args: ["aLayout", "aValue"],
+source: "layout: aLayout value: aValue\x0a\x09^ self new\x0a\x09\x09layout: aLayout;\x0a\x09\x09value: aValue;\x0a\x09\x09yourself",
+messageSends: ["layout:", "new", "value:", "yourself"],
+referencedClasses: []
+}),
+smalltalk.MKLayoutProperty.klass);
+
+
+smalltalk.addClass('MKHorizontalCenteringLayoutProperty', smalltalk.MKLayoutProperty, [], 'Moka-Layouts');
+smalltalk.addMethod(
+smalltalk.method({
+selector: "marginLeft",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=(0).__minus(_st(_st(_st(self._layout())._width()).__slash((2))).__plus(self._value()));
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"marginLeft",{},smalltalk.MKHorizontalCenteringLayoutProperty)})},
+args: [],
+source: "marginLeft\x0a\x09^ 0 - ((self layout width / 2) + self value)",
+messageSends: ["-", "+", "/", "width", "layout", "value"],
+referencedClasses: []
+}),
+smalltalk.MKHorizontalCenteringLayoutProperty);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "printCssOn:",
+category: 'printing',
+fn: function (aStream){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(aStream).__lt_lt("left:50%;");
+$ctx1.sendIdx["<<"]=1;
+_st(_st(aStream).__lt_lt("margin-left:")).__lt_lt(_st(self._marginLeft())._asMokaCssString());
+$ctx1.sendIdx["<<"]=2;
+return self}, function($ctx1) {$ctx1.fill(self,"printCssOn:",{aStream:aStream},smalltalk.MKHorizontalCenteringLayoutProperty)})},
+args: ["aStream"],
+source: "printCssOn: aStream\x0a\x09aStream << 'left:50%;'.\x0a\x09aStream << 'margin-left:' << self marginLeft asMokaCssString",
+messageSends: ["<<", "asMokaCssString", "marginLeft"],
+referencedClasses: []
+}),
+smalltalk.MKHorizontalCenteringLayoutProperty);
+
+
+
+smalltalk.addClass('MKLabelledLayoutProperty', smalltalk.MKLayoutProperty, ['label'], 'Moka-Layouts');
+smalltalk.addMethod(
+smalltalk.method({
+selector: "label",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=self["@label"];
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"label",{},smalltalk.MKLabelledLayoutProperty)})},
+args: [],
+source: "label\x0a\x09^ label",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.MKLabelledLayoutProperty);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "label:",
+category: 'accessing',
+fn: function (aString){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self["@label"]=aString;
+return self}, function($ctx1) {$ctx1.fill(self,"label:",{aString:aString},smalltalk.MKLabelledLayoutProperty)})},
+args: ["aString"],
+source: "label: aString\x0a\x09label := aString",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.MKLabelledLayoutProperty);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "printCssOn:",
+category: 'printing',
+fn: function (aStream){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(_st(aStream).__lt_lt(self._label())).__lt_lt(":");
+$ctx1.sendIdx["<<"]=2;
+_st($1).__lt_lt(_st(self._value())._asMokaCssString());
+$ctx1.sendIdx["<<"]=1;
+return self}, function($ctx1) {$ctx1.fill(self,"printCssOn:",{aStream:aStream},smalltalk.MKLabelledLayoutProperty)})},
+args: ["aStream"],
+source: "printCssOn: aStream\x0a\x09aStream << self label << ':' << self value asMokaCssString",
+messageSends: ["<<", "label", "asMokaCssString", "value"],
+referencedClasses: []
+}),
+smalltalk.MKLabelledLayoutProperty);
+
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "layout:label:value:",
+category: 'instance creation',
+fn: function (aLayout,aString,aValue){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$3,$1;
+$2=self._new();
+_st($2)._layout_(aLayout);
+_st($2)._label_(aString);
+_st($2)._value_(aValue);
+$3=_st($2)._yourself();
+$1=$3;
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"layout:label:value:",{aLayout:aLayout,aString:aString,aValue:aValue},smalltalk.MKLabelledLayoutProperty.klass)})},
+args: ["aLayout", "aString", "aValue"],
+source: "layout: aLayout label: aString value: aValue\x0a\x09^ self new\x0a\x09\x09layout: aLayout;\x0a\x09\x09label: aString;\x0a\x09\x09value: aValue;\x0a\x09\x09yourself",
+messageSends: ["layout:", "new", "label:", "value:", "yourself"],
+referencedClasses: []
+}),
+smalltalk.MKLabelledLayoutProperty.klass);
+
+
+smalltalk.addClass('MKVerticalCenteringLayoutProperty', smalltalk.MKLayoutProperty, [], 'Moka-Layouts');
+smalltalk.addMethod(
+smalltalk.method({
+selector: "marginTop",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=(0).__minus(_st(_st(_st(self._layout())._height()).__slash((2))).__plus(self._value()));
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"marginTop",{},smalltalk.MKVerticalCenteringLayoutProperty)})},
+args: [],
+source: "marginTop\x0a\x09^ 0 - ((self layout height / 2) + self value)",
+messageSends: ["-", "+", "/", "height", "layout", "value"],
+referencedClasses: []
+}),
+smalltalk.MKVerticalCenteringLayoutProperty);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "printCssOn:",
+category: 'printing',
+fn: function (aStream){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(aStream).__lt_lt("top:50%;");
+$ctx1.sendIdx["<<"]=1;
+_st(_st(aStream).__lt_lt("margin-top:")).__lt_lt(_st(self._marginTop())._asMokaCssString());
+$ctx1.sendIdx["<<"]=2;
+return self}, function($ctx1) {$ctx1.fill(self,"printCssOn:",{aStream:aStream},smalltalk.MKVerticalCenteringLayoutProperty)})},
+args: ["aStream"],
+source: "printCssOn: aStream\x0a\x09aStream << 'top:50%;'.\x0a\x09aStream << 'margin-top:' << self marginTop asMokaCssString",
+messageSends: ["<<", "asMokaCssString", "marginTop"],
+referencedClasses: []
+}),
+smalltalk.MKVerticalCenteringLayoutProperty);
+
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "asMokaCssString",
+category: '*Moka-Layouts',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$1;
+$2=_st(self._abs()).__gt((1));
+if(smalltalk.assert($2)){
+$1=self._asMokaPixelString();
+} else {
+$1=self._asMokaPercentString();
+};
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"asMokaCssString",{},smalltalk.Number)})},
+args: [],
+source: "asMokaCssString\x0a\x09^ self abs > 1 \x09\x0a\x09\x09ifTrue: [ self asMokaPixelString ]\x0a\x09\x09ifFalse: [ self asMokaPercentString ]",
+messageSends: ["ifTrue:ifFalse:", ">", "abs", "asMokaPixelString", "asMokaPercentString"],
+referencedClasses: []
+}),
+smalltalk.Number);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "asMokaPercentString",
+category: '*Moka-Layouts',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(_st(self.__star((100)))._asString()).__comma("%");
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"asMokaPercentString",{},smalltalk.Number)})},
+args: [],
+source: "asMokaPercentString\x0a\x09^ (self * 100) asString, '%'",
+messageSends: [",", "asString", "*"],
+referencedClasses: []
+}),
+smalltalk.Number);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "asMokaPixelString",
+category: '*Moka-Layouts',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(self._asString()).__comma("px");
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"asMokaPixelString",{},smalltalk.Number)})},
+args: [],
+source: "asMokaPixelString\x0a\x09^ self asString, 'px'",
+messageSends: [",", "asString"],
+referencedClasses: []
+}),
+smalltalk.Number);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "asMokaCssString",
+category: '*Moka-Layouts',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return self;
+}, function($ctx1) {$ctx1.fill(self,"asMokaCssString",{},smalltalk.String)})},
+args: [],
+source: "asMokaCssString\x0a\x09^ self",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.String);
+
+});

+ 3 - 3
js/Moka-Views.deploy.js

@@ -1,7 +1,7 @@
 (function(smalltalk,nil,_st){
 smalltalk.addPackage('Moka-Views');
 
-smalltalk.addClass('MKButtonView', smalltalk.MKAspectView, ['default', 'label'], 'Moka-Views');
+smalltalk.addClass('MKButtonView', smalltalk.MKAspectsView, ['default', 'label'], 'Moka-Views');
 smalltalk.addMethod(
 smalltalk.method({
 selector: "cssClass",
@@ -145,7 +145,7 @@ smalltalk.MKButtonView);
 
 
 
-smalltalk.addClass('MKCheckboxView', smalltalk.MKAspectView, ['label'], 'Moka-Views');
+smalltalk.addClass('MKCheckboxView', smalltalk.MKAspectsView, ['label'], 'Moka-Views');
 smalltalk.addMethod(
 smalltalk.method({
 selector: "checked",
@@ -225,7 +225,7 @@ smalltalk.MKCheckboxView);
 
 
 
-smalltalk.addClass('MKInputView', smalltalk.MKAspectView, ['input'], 'Moka-Views');
+smalltalk.addClass('MKInputView', smalltalk.MKAspectsView, ['input'], 'Moka-Views');
 smalltalk.addMethod(
 smalltalk.method({
 selector: "enterPressed",

+ 1914 - 182
js/Moka-Views.js

@@ -2,7 +2,7 @@ define("amber_core/Moka-Views", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm
 smalltalk.addPackage('Moka-Views');
 smalltalk.packages["Moka-Views"].transport = {"type":"amd","amdNamespace":"amber_core"};
 
-smalltalk.addClass('MKButtonView', smalltalk.MKAspectView, ['default', 'label'], 'Moka-Views');
+smalltalk.addClass('MKButtonView', smalltalk.MKSingleAspectView, ['default', 'label'], 'Moka-Views');
 smalltalk.MKButtonView.comment="I am a push button view. My default controller is `MKButtonController`.\x0a\x0aMy controller must answer to `#onPressed`.\x0a\x0a## API\x0a\x0a- Instances can be set a `default` button\x0a- Use `#label:` to set the label string";
 smalltalk.addMethod(
 smalltalk.method({
@@ -10,20 +10,26 @@ selector: "cssClass",
 category: 'accessing',
 fn: function (){
 var self=this;
+function $String(){return smalltalk.String||(typeof String=="undefined"?nil:String)}
 return smalltalk.withContext(function($ctx1) { 
-var $2,$1;
-$2=self._isDefault();
-if(smalltalk.assert($2)){
-$1="default";
-} else {
-$1="";
+var $2,$3,$1;
+$1=_st($String())._streamContents_((function(stream){
+return smalltalk.withContext(function($ctx2) {
+$2=_st(stream).__lt_lt(smalltalk.MKButtonView.superclass.fn.prototype._cssClass.apply(_st(self), []));
+$ctx2.sendIdx["<<"]=2;
+_st($2).__lt_lt(" mk_button");
+$ctx2.sendIdx["<<"]=1;
+$3=self._isDefault();
+if(smalltalk.assert($3)){
+return _st(stream).__lt_lt(" default");
 };
+}, function($ctx2) {$ctx2.fillBlock({stream:stream},$ctx1,1)})}));
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"cssClass",{},smalltalk.MKButtonView)})},
 args: [],
-source: "cssClass\x0a\x09^ self isDefault \x0a\x09\x09ifTrue: [ 'default' ]\x0a\x09\x09ifFalse: [ '' ]",
-messageSends: ["ifTrue:ifFalse:", "isDefault"],
-referencedClasses: []
+source: "cssClass\x0a\x09^ String streamContents: [ :stream |\x0a\x09\x09stream << super cssClass << ' mk_button'.\x0a\x09\x09self isDefault \x0a\x09\x09\x09ifTrue: [ stream << ' default' ] ]",
+messageSends: ["streamContents:", "<<", "cssClass", "ifTrue:", "isDefault"],
+referencedClasses: ["String"]
 }),
 smalltalk.MKButtonView);
 
@@ -69,9 +75,7 @@ fn: function (){
 var self=this;
 function $MKButtonController(){return smalltalk.MKButtonController||(typeof MKButtonController=="undefined"?nil:MKButtonController)}
 return smalltalk.withContext(function($ctx1) { 
-var $1;
-$1=$MKButtonController();
-return $1;
+return $MKButtonController();
 }, function($ctx1) {$ctx1.fill(self,"defaultControllerClass",{},smalltalk.MKButtonView)})},
 args: [],
 source: "defaultControllerClass\x0a\x09^ MKButtonController",
@@ -96,6 +100,28 @@ referencedClasses: []
 }),
 smalltalk.MKButtonView);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "defaultLayout",
+category: 'defaults',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$3,$1;
+$2=smalltalk.MKButtonView.superclass.fn.prototype._defaultLayout.apply(_st(self), []);
+_st($2)._width_((80));
+_st($2)._height_((24));
+$3=_st($2)._yourself();
+$1=$3;
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"defaultLayout",{},smalltalk.MKButtonView)})},
+args: [],
+source: "defaultLayout\x0a\x09^ super defaultLayout\x0a\x09\x09width: 80;\x0a\x09\x09height: 24;\x0a\x09\x09yourself",
+messageSends: ["width:", "defaultLayout", "height:", "yourself"],
+referencedClasses: []
+}),
+smalltalk.MKButtonView);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "isDefault",
@@ -160,46 +186,39 @@ smalltalk.MKButtonView);
 
 smalltalk.addMethod(
 smalltalk.method({
-selector: "pressed",
-category: 'events',
-fn: function (){
+selector: "renderContentOn:",
+category: 'rendering',
+fn: function (html){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-_st(self._controller())._onPressed();
-return self}, function($ctx1) {$ctx1.fill(self,"pressed",{},smalltalk.MKButtonView)})},
-args: [],
-source: "pressed\x0a\x09self controller onPressed",
-messageSends: ["onPressed", "controller"],
+_st(html)._with_(self._label());
+return self}, function($ctx1) {$ctx1.fill(self,"renderContentOn:",{html:html},smalltalk.MKButtonView)})},
+args: ["html"],
+source: "renderContentOn: html\x0a\x09html with: self label",
+messageSends: ["with:", "label"],
 referencedClasses: []
 }),
 smalltalk.MKButtonView);
 
 smalltalk.addMethod(
 smalltalk.method({
-selector: "renderContentOn:",
-category: 'rendering',
-fn: function (html){
+selector: "tag",
+category: 'accessing',
+fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-var $1,$2;
-$1=_st(html)._button();
-_st($1)._class_(self._cssClass());
-_st($1)._with_(self._label());
-$2=_st($1)._onClick_((function(){
-return smalltalk.withContext(function($ctx2) {
-return self._pressed();
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
-return self}, function($ctx1) {$ctx1.fill(self,"renderContentOn:",{html:html},smalltalk.MKButtonView)})},
-args: ["html"],
-source: "renderContentOn: html\x0a\x09html button\x0a\x09\x09class: self cssClass;\x0a\x09\x09with: self label;\x0a\x09\x09onClick: [ self pressed ]",
-messageSends: ["class:", "button", "cssClass", "with:", "label", "onClick:", "pressed"],
+return "button";
+}, function($ctx1) {$ctx1.fill(self,"tag",{},smalltalk.MKButtonView)})},
+args: [],
+source: "tag\x0a\x09^ 'button'",
+messageSends: [],
 referencedClasses: []
 }),
 smalltalk.MKButtonView);
 
 
 
-smalltalk.addClass('MKCheckboxView', smalltalk.MKAspectView, ['id'], 'Moka-Views');
+smalltalk.addClass('MKCheckboxView', smalltalk.MKSingleAspectView, ['id'], 'Moka-Views');
 smalltalk.MKCheckboxView.comment="I am a checkbox view. My default controller is `MKCheckboxController`.\x0a\x0aMy controller must answer to `#onToggled:`.\x0a\x0a##API\x0a\x0a- If no `aspect` is provided, the ckeckbox state will always be off.\x0a- use `#label:` to set the label string.";
 smalltalk.addMethod(
 smalltalk.method({
@@ -231,11 +250,13 @@ category: 'accessing',
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-return "mk_checkbox";
+var $1;
+$1=_st(smalltalk.MKCheckboxView.superclass.fn.prototype._cssClass.apply(_st(self), [])).__comma(" mk_checkbox");
+return $1;
 }, function($ctx1) {$ctx1.fill(self,"cssClass",{},smalltalk.MKCheckboxView)})},
 args: [],
-source: "cssClass\x0a\x09^ 'mk_checkbox'",
-messageSends: [],
+source: "cssClass\x0a\x09^ super cssClass, ' mk_checkbox'",
+messageSends: [",", "cssClass"],
 referencedClasses: []
 }),
 smalltalk.MKCheckboxView);
@@ -257,6 +278,28 @@ referencedClasses: ["MKCheckboxController"]
 }),
 smalltalk.MKCheckboxView);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "defaultLayout",
+category: 'defaults',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$3,$1;
+$2=smalltalk.MKCheckboxView.superclass.fn.prototype._defaultLayout.apply(_st(self), []);
+_st($2)._width_((16));
+_st($2)._height_((16));
+$3=_st($2)._yourself();
+$1=$3;
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"defaultLayout",{},smalltalk.MKCheckboxView)})},
+args: [],
+source: "defaultLayout\x0a\x09^ super defaultLayout\x0a\x09\x09width: 16;\x0a\x09\x09height: 16;\x0a\x09\x09yourself",
+messageSends: ["width:", "defaultLayout", "height:", "yourself"],
+referencedClasses: []
+}),
+smalltalk.MKCheckboxView);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "id",
@@ -281,57 +324,23 @@ referencedClasses: []
 }),
 smalltalk.MKCheckboxView);
 
-smalltalk.addMethod(
-smalltalk.method({
-selector: "pressed",
-category: 'events',
-fn: function (){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-_st(self._controller())._onToggled_(_st(self._checked())._not());
-return self}, function($ctx1) {$ctx1.fill(self,"pressed",{},smalltalk.MKCheckboxView)})},
-args: [],
-source: "pressed\x0a\x09self controller onToggled: self checked not",
-messageSends: ["onToggled:", "controller", "not", "checked"],
-referencedClasses: []
-}),
-smalltalk.MKCheckboxView);
-
 smalltalk.addMethod(
 smalltalk.method({
 selector: "renderContentOn:",
 category: 'rendering',
 fn: function (html){
 var self=this;
-var checkbox;
-return smalltalk.withContext(function($ctx1) { 
-var $1,$2,$3,$4,$5,$6,$7;
-$1=_st(html)._input();
-_st($1)._type_("checkbox");
-_st($1)._class_(self._cssClass());
-$2=$1;
-$3=self._id();
-$ctx1.sendIdx["id"]=1;
-_st($2)._id_($3);
-$4=_st($1)._onClick_((function(){
-return smalltalk.withContext(function($ctx2) {
-return self._pressed();
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
-checkbox=$4;
-$5=self._checked();
-if(smalltalk.assert($5)){
-_st(checkbox)._at_put_("checked","checked");
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=self._checked();
+if(smalltalk.assert($1)){
+_st(_st(self["@root"])._asJQuery())._addClass_("checked");
 };
-$6=_st(html)._label();
-_st($6)._for_(self._id());
-$7=_st($6)._with_((function(){
-return smalltalk.withContext(function($ctx2) {
-return _st(html)._entity_("nbsp");
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,3)})}));
-return self}, function($ctx1) {$ctx1.fill(self,"renderContentOn:",{html:html,checkbox:checkbox},smalltalk.MKCheckboxView)})},
+_st(self["@root"])._at_put_("tabindex","0");
+return self}, function($ctx1) {$ctx1.fill(self,"renderContentOn:",{html:html},smalltalk.MKCheckboxView)})},
 args: ["html"],
-source: "renderContentOn: html\x0a\x09| checkbox |\x0a\x09\x0a\x09checkbox := html input\x0a\x09\x09type: 'checkbox';\x0a\x09\x09class: self cssClass;\x0a\x09\x09id: self id;\x0a\x09\x09onClick: [ self pressed ].\x0a\x09\x09\x0a\x09self checked ifTrue: [ \x0a\x09\x09checkbox at: 'checked' put: 'checked' ].\x0a\x09\x09\x0a\x09html label\x0a\x09\x09for: self id;\x0a\x09\x09with: [ html entity: 'nbsp' ]",
-messageSends: ["type:", "input", "class:", "cssClass", "id:", "id", "onClick:", "pressed", "ifTrue:", "checked", "at:put:", "for:", "label", "with:", "entity:"],
+source: "renderContentOn: html\x09\x0a\x09self checked ifTrue: [ \x0a\x09\x09root asJQuery addClass: 'checked' ].\x0a\x09\x0a\x09root at: 'tabindex' put: '0'",
+messageSends: ["ifTrue:", "checked", "addClass:", "asJQuery", "at:put:"],
 referencedClasses: []
 }),
 smalltalk.MKCheckboxView);
@@ -342,20 +351,20 @@ selector: "update",
 category: 'events',
 fn: function (){
 var self=this;
-var checkbox;
 return smalltalk.withContext(function($ctx1) { 
-var $1;
-checkbox=_st("#".__comma(self._id()))._asJQuery();
+var $1,$2;
 $1=self._checked();
 if(smalltalk.assert($1)){
-_st(checkbox)._attr_put_("checked","checked");
+$2=_st(self["@root"])._asJQuery();
+$ctx1.sendIdx["asJQuery"]=1;
+_st($2)._addClass_("checked");
 } else {
-_st(checkbox)._removeAttr_("checked");
+_st(_st(self["@root"])._asJQuery())._removeClass_("checked");
 };
-return self}, function($ctx1) {$ctx1.fill(self,"update",{checkbox:checkbox},smalltalk.MKCheckboxView)})},
+return self}, function($ctx1) {$ctx1.fill(self,"update",{},smalltalk.MKCheckboxView)})},
 args: [],
-source: "update\x0a\x09| checkbox |\x0a\x09checkbox := ('#', self id) asJQuery.\x0a\x09\x0a\x09self checked\x0a\x09\x09ifTrue: [ checkbox attr: 'checked' put: 'checked' ]\x0a\x09\x09ifFalse: [ checkbox removeAttr: 'checked' ]",
-messageSends: ["asJQuery", ",", "id", "ifTrue:ifFalse:", "checked", "attr:put:", "removeAttr:"],
+source: "update\x0a\x09self checked\x0a\x09\x09ifTrue: [ root asJQuery addClass: 'checked' ]\x0a\x09\x09ifFalse: [ root asJQuery removeClass: 'checked' ]",
+messageSends: ["ifTrue:ifFalse:", "checked", "addClass:", "asJQuery", "removeClass:"],
 referencedClasses: []
 }),
 smalltalk.MKCheckboxView);
@@ -366,41 +375,98 @@ smalltalk.addClass('MKSwitchView', smalltalk.MKCheckboxView, [], 'Moka-Views');
 smalltalk.MKSwitchView.comment="I am a switch view, similar to a `MKCheckboxView` but displayed as a switch. \x0aMy default controller is `MKCheckboxController`.";
 smalltalk.addMethod(
 smalltalk.method({
-selector: "cssClass",
+selector: "checkboxCssClass",
 category: 'accessing',
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return "mk_switch";
-}, function($ctx1) {$ctx1.fill(self,"cssClass",{},smalltalk.MKSwitchView)})},
+}, function($ctx1) {$ctx1.fill(self,"checkboxCssClass",{},smalltalk.MKSwitchView)})},
 args: [],
-source: "cssClass\x0a\x09^ 'mk_switch'",
+source: "checkboxCssClass\x0a\x09^ 'mk_switch'",
 messageSends: [],
 referencedClasses: []
 }),
 smalltalk.MKSwitchView);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "cssClass",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(smalltalk.MKSwitchView.superclass.fn.prototype._cssClass.apply(_st(self), [])).__comma(" mk_switch");
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"cssClass",{},smalltalk.MKSwitchView)})},
+args: [],
+source: "cssClass\x0a\x09^ super cssClass, ' mk_switch'",
+messageSends: [",", "cssClass"],
+referencedClasses: []
+}),
+smalltalk.MKSwitchView);
 
-
-smalltalk.addClass('MKLabelView', smalltalk.MKAspectView, ['input'], 'Moka-Views');
-smalltalk.MKLabelView.comment="I am an label view. I display a `String`.";
 smalltalk.addMethod(
 smalltalk.method({
-selector: "defaultControllerClass",
+selector: "defaultLayout",
 category: 'defaults',
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
+var $2,$3,$1;
+$2=smalltalk.MKSwitchView.superclass.fn.prototype._defaultLayout.apply(_st(self), []);
+_st($2)._width_((48));
+_st($2)._height_((20));
+$3=_st($2)._yourself();
+$1=$3;
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"defaultLayout",{},smalltalk.MKSwitchView)})},
+args: [],
+source: "defaultLayout\x0a\x09^ super defaultLayout\x0a\x09\x09width: 48;\x0a\x09\x09height: 20;\x0a\x09\x09yourself",
+messageSends: ["width:", "defaultLayout", "height:", "yourself"],
+referencedClasses: []
+}),
+smalltalk.MKSwitchView);
+
+
+
+smalltalk.addClass('MKContainerView', smalltalk.MKView, ['childView'], 'Moka-Views');
+smalltalk.MKContainerView.comment="I display my single `childView`. \x0a\x0aI am used to switch between views.";
+smalltalk.addMethod(
+smalltalk.method({
+selector: "childView",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
 var $1;
-$1=smalltalk.MKLabelView.superclass.fn.prototype._defaultControllerClass.apply(_st(self), []);
+$1=self["@childView"];
 return $1;
-}, function($ctx1) {$ctx1.fill(self,"defaultControllerClass",{},smalltalk.MKLabelView)})},
+}, function($ctx1) {$ctx1.fill(self,"childView",{},smalltalk.MKContainerView)})},
 args: [],
-source: "defaultControllerClass\x0a\x09^ super defaultControllerClass",
-messageSends: ["defaultControllerClass"],
+source: "childView\x0a\x09^ childView",
+messageSends: [],
 referencedClasses: []
 }),
-smalltalk.MKLabelView);
+smalltalk.MKContainerView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "childView:",
+category: 'accessing',
+fn: function (aView){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self["@childView"]=aView;
+self._update();
+return self}, function($ctx1) {$ctx1.fill(self,"childView:",{aView:aView},smalltalk.MKContainerView)})},
+args: ["aView"],
+source: "childView: aView\x0a\x09childView := aView.\x0a\x09self update",
+messageSends: ["update"],
+referencedClasses: []
+}),
+smalltalk.MKContainerView);
 
 smalltalk.addMethod(
 smalltalk.method({
@@ -409,51 +475,101 @@ category: 'rendering',
 fn: function (html){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-_st(_st(html)._span())._with_(self._aspectValue());
-return self}, function($ctx1) {$ctx1.fill(self,"renderContentOn:",{html:html},smalltalk.MKLabelView)})},
+_st(html)._with_(self._childView());
+return self}, function($ctx1) {$ctx1.fill(self,"renderContentOn:",{html:html},smalltalk.MKContainerView)})},
 args: ["html"],
-source: "renderContentOn: html\x0a\x09html span with: self aspectValue",
-messageSends: ["with:", "span", "aspectValue"],
+source: "renderContentOn: html\x0a\x09html with: self childView",
+messageSends: ["with:", "childView"],
 referencedClasses: []
 }),
-smalltalk.MKLabelView);
+smalltalk.MKContainerView);
+
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "childView:",
+category: 'instance creation',
+fn: function (aView){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$3,$1;
+$2=self._new();
+_st($2)._childView_(aView);
+$3=_st($2)._yourself();
+$1=$3;
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"childView:",{aView:aView},smalltalk.MKContainerView.klass)})},
+args: ["aView"],
+source: "childView: aView\x0a\x09^ self new \x0a\x09\x09childView: aView;\x0a\x09\x09yourself",
+messageSends: ["childView:", "new", "yourself"],
+referencedClasses: []
+}),
+smalltalk.MKContainerView.klass);
 
 
+smalltalk.addClass('MKLabelView', smalltalk.MKSingleAspectView, [], 'Moka-Views');
+smalltalk.MKLabelView.comment="I am an label view. I display a `String`.";
+smalltalk.addMethod(
+smalltalk.method({
+selector: "cssClass",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(smalltalk.MKLabelView.superclass.fn.prototype._cssClass.apply(_st(self), [])).__comma(" mk_label");
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"cssClass",{},smalltalk.MKLabelView)})},
+args: [],
+source: "cssClass\x0a\x09^ super cssClass, ' mk_label'",
+messageSends: [",", "cssClass"],
+referencedClasses: []
+}),
+smalltalk.MKLabelView);
 
-smalltalk.addClass('MKTextAreaView', smalltalk.MKAspectView, ['input'], 'Moka-Views');
-smalltalk.MKTextAreaView.comment="I am an text area view. My default controller is `MKAnyKeyInputController`.\x0a\x0aMy controller must answer to `#onKeyPressed:`.";
 smalltalk.addMethod(
 smalltalk.method({
 selector: "defaultControllerClass",
 category: 'defaults',
 fn: function (){
 var self=this;
-function $MKAnyKeyInputController(){return smalltalk.MKAnyKeyInputController||(typeof MKAnyKeyInputController=="undefined"?nil:MKAnyKeyInputController)}
 return smalltalk.withContext(function($ctx1) { 
-return $MKAnyKeyInputController();
-}, function($ctx1) {$ctx1.fill(self,"defaultControllerClass",{},smalltalk.MKTextAreaView)})},
+var $1;
+$1=smalltalk.MKLabelView.superclass.fn.prototype._defaultControllerClass.apply(_st(self), []);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"defaultControllerClass",{},smalltalk.MKLabelView)})},
 args: [],
-source: "defaultControllerClass\x0a\x09^ MKAnyKeyInputController",
-messageSends: [],
-referencedClasses: ["MKAnyKeyInputController"]
+source: "defaultControllerClass\x0a\x09^ super defaultControllerClass",
+messageSends: ["defaultControllerClass"],
+referencedClasses: []
 }),
-smalltalk.MKTextAreaView);
+smalltalk.MKLabelView);
 
 smalltalk.addMethod(
 smalltalk.method({
-selector: "keyUp:",
-category: 'events',
-fn: function (anEvent){
+selector: "defaultLayout",
+category: 'defaults',
+fn: function (){
 var self=this;
+function $MKLabelLayout(){return smalltalk.MKLabelLayout||(typeof MKLabelLayout=="undefined"?nil:MKLabelLayout)}
 return smalltalk.withContext(function($ctx1) { 
-_st(self._controller())._onKeyPressed_(anEvent);
-return self}, function($ctx1) {$ctx1.fill(self,"keyUp:",{anEvent:anEvent},smalltalk.MKTextAreaView)})},
-args: ["anEvent"],
-source: "keyUp: anEvent\x0a\x09self controller onKeyPressed: anEvent",
-messageSends: ["onKeyPressed:", "controller"],
-referencedClasses: []
+var $2,$3,$1;
+$2=_st($MKLabelLayout())._new();
+_st($2)._height_((24));
+_st($2)._top_((0));
+_st($2)._left_((0));
+_st($2)._right_((0));
+_st($2)._textAlign_("left");
+$3=_st($2)._yourself();
+$1=$3;
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"defaultLayout",{},smalltalk.MKLabelView)})},
+args: [],
+source: "defaultLayout\x0a\x09^ MKLabelLayout new\x0a\x09\x09height: 24;\x0a\x09\x09top: 0;\x0a\x09\x09left:0;\x0a\x09\x09right: 0;\x0a\x09\x09textAlign: 'left';\x0a\x09\x09yourself",
+messageSends: ["height:", "new", "top:", "left:", "right:", "textAlign:", "yourself"],
+referencedClasses: ["MKLabelLayout"]
 }),
-smalltalk.MKTextAreaView);
+smalltalk.MKLabelView);
 
 smalltalk.addMethod(
 smalltalk.method({
@@ -462,103 +578,1719 @@ category: 'rendering',
 fn: function (html){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-var $1,$2;
-$1=_st(html)._textarea();
-_st($1)._with_(self._aspectValue());
-$2=_st($1)._onKeyUp_((function(event){
-return smalltalk.withContext(function($ctx2) {
-return self._keyUp_(event);
-}, function($ctx2) {$ctx2.fillBlock({event:event},$ctx1,1)})}));
-self["@input"]=$2;
-return self}, function($ctx1) {$ctx1.fill(self,"renderContentOn:",{html:html},smalltalk.MKTextAreaView)})},
+_st(html)._with_(self._aspectValue());
+return self}, function($ctx1) {$ctx1.fill(self,"renderContentOn:",{html:html},smalltalk.MKLabelView)})},
 args: ["html"],
-source: "renderContentOn: html\x0a\x09input := html textarea \x0a\x09\x09with: self aspectValue;\x0a\x09\x09onKeyUp: [ :event | self keyUp: event ]",
-messageSends: ["with:", "textarea", "aspectValue", "onKeyUp:", "keyUp:"],
+source: "renderContentOn: html\x0a\x09html with: self aspectValue",
+messageSends: ["with:", "aspectValue"],
 referencedClasses: []
 }),
-smalltalk.MKTextAreaView);
+smalltalk.MKLabelView);
 
 smalltalk.addMethod(
 smalltalk.method({
-selector: "update",
-category: 'updating',
+selector: "textAlign:",
+category: 'layout',
+fn: function (aString){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self._layout())._textAlign_(aString);
+return self}, function($ctx1) {$ctx1.fill(self,"textAlign:",{aString:aString},smalltalk.MKLabelView)})},
+args: ["aString"],
+source: "textAlign: aString\x0a\x09self layout textAlign: aString",
+messageSends: ["textAlign:", "layout"],
+referencedClasses: []
+}),
+smalltalk.MKLabelView);
+
+
+
+smalltalk.addClass('MKHeadingView', smalltalk.MKLabelView, ['level'], 'Moka-Views');
+smalltalk.MKHeadingView.comment="I display a heading, with a `level` from 1 to 6.";
+smalltalk.addMethod(
+smalltalk.method({
+selector: "cssClass",
+category: 'accessing',
 fn: function (){
 var self=this;
+function $String(){return smalltalk.String||(typeof String=="undefined"?nil:String)}
 return smalltalk.withContext(function($ctx1) { 
-var $1;
-$1=self["@input"];
-if(($receiver = $1) == nil || $receiver == null){
-$1;
+var $2,$1;
+$1=_st($String())._streamContents_((function(stream){
+return smalltalk.withContext(function($ctx2) {
+$2=_st(_st(stream).__lt_lt(smalltalk.MKHeadingView.superclass.fn.prototype._cssClass.apply(_st(self), []))).__lt_lt(" mk_heading level");
+$ctx2.sendIdx["<<"]=2;
+return _st($2).__lt_lt(_st(self._level())._asString());
+$ctx2.sendIdx["<<"]=1;
+}, function($ctx2) {$ctx2.fillBlock({stream:stream},$ctx1,1)})}));
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"cssClass",{},smalltalk.MKHeadingView)})},
+args: [],
+source: "cssClass\x0a\x09^ String streamContents: [ :stream |\x0a\x09\x09stream \x0a\x09\x09\x09<< super cssClass \x09\x0a\x09\x09\x09<< ' mk_heading level'\x0a\x09\x09\x09<< self level asString ]",
+messageSends: ["streamContents:", "<<", "cssClass", "asString", "level"],
+referencedClasses: ["String"]
+}),
+smalltalk.MKHeadingView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "level",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$1;
+$2=self["@level"];
+if(($receiver = $2) == nil || $receiver == null){
+$1=(1);
 } else {
-_st(_st(self["@input"])._asJQuery())._val_(self._aspectValue());
+$1=$2;
 };
-return self}, function($ctx1) {$ctx1.fill(self,"update",{},smalltalk.MKTextAreaView)})},
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"level",{},smalltalk.MKHeadingView)})},
 args: [],
-source: "update\x0a\x09input ifNotNil: [ input asJQuery val: self aspectValue ]",
-messageSends: ["ifNotNil:", "val:", "asJQuery", "aspectValue"],
+source: "level\x0a\x09^ level ifNil: [ 1 ]",
+messageSends: ["ifNil:"],
 referencedClasses: []
 }),
-smalltalk.MKTextAreaView);
+smalltalk.MKHeadingView);
 
 smalltalk.addMethod(
 smalltalk.method({
-selector: "value",
+selector: "level:",
+category: 'accessing',
+fn: function (aNumber){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self["@level"]=aNumber;
+return self}, function($ctx1) {$ctx1.fill(self,"level:",{aNumber:aNumber},smalltalk.MKHeadingView)})},
+args: ["aNumber"],
+source: "level: aNumber\x0a\x09level := aNumber",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.MKHeadingView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "tag",
 category: 'accessing',
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $1;
-$1=_st(_st(self["@input"])._asJQuery())._val();
+$1="h".__comma(_st(self._level())._asString());
 return $1;
-}, function($ctx1) {$ctx1.fill(self,"value",{},smalltalk.MKTextAreaView)})},
+}, function($ctx1) {$ctx1.fill(self,"tag",{},smalltalk.MKHeadingView)})},
 args: [],
-source: "value\x0a\x09^ input asJQuery val",
-messageSends: ["val", "asJQuery"],
+source: "tag\x0a\x09^ 'h', self level asString",
+messageSends: [",", "asString", "level"],
 referencedClasses: []
 }),
-smalltalk.MKTextAreaView);
+smalltalk.MKHeadingView);
 
 
 
-smalltalk.addClass('MKInputView', smalltalk.MKTextAreaView, [], 'Moka-Views');
-smalltalk.MKInputView.comment="I am an input view. My default controller is `MKEnterInputController`.\x0a\x0aMy controller must answer to `#onKeyPressed:`.";
+smalltalk.addClass('MKOverlayView', smalltalk.MKView, ['childView'], 'Moka-Views');
 smalltalk.addMethod(
 smalltalk.method({
-selector: "defaultControllerClass",
-category: 'defaults',
+selector: "childView",
+category: 'accessing',
 fn: function (){
 var self=this;
-function $MKEnterInputController(){return smalltalk.MKEnterInputController||(typeof MKEnterInputController=="undefined"?nil:MKEnterInputController)}
 return smalltalk.withContext(function($ctx1) { 
-return $MKEnterInputController();
-}, function($ctx1) {$ctx1.fill(self,"defaultControllerClass",{},smalltalk.MKInputView)})},
+var $1;
+$1=self["@childView"];
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"childView",{},smalltalk.MKOverlayView)})},
 args: [],
-source: "defaultControllerClass\x0a\x09^ MKEnterInputController",
+source: "childView\x0a\x09^ childView",
 messageSends: [],
-referencedClasses: ["MKEnterInputController"]
+referencedClasses: []
 }),
-smalltalk.MKInputView);
+smalltalk.MKOverlayView);
 
 smalltalk.addMethod(
 smalltalk.method({
-selector: "renderContentOn:",
-category: 'rendering',
-fn: function (html){
+selector: "childView:",
+category: 'accessing',
+fn: function (aView){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-var $1,$2;
-$1=_st(html)._input();
-_st($1)._value_(self._aspectValue());
-_st($1)._onKeyUp_((function(event){
-return smalltalk.withContext(function($ctx2) {
-return self._keyUp_(event);
-}, function($ctx2) {$ctx2.fillBlock({event:event},$ctx1,1)})}));
-$2=_st($1)._yourself();
-self["@input"]=$2;
-return self}, function($ctx1) {$ctx1.fill(self,"renderContentOn:",{html:html},smalltalk.MKInputView)})},
-args: ["html"],
-source: "renderContentOn: html\x0a\x09input := html input\x0a\x09\x09value: self aspectValue;\x0a\x09\x09onKeyUp: [ :event |\x0a\x09\x09\x09self keyUp: event ];\x0a\x09\x09yourself",
-messageSends: ["value:", "input", "aspectValue", "onKeyUp:", "keyUp:", "yourself"],
+self["@childView"]=aView;
+return self}, function($ctx1) {$ctx1.fill(self,"childView:",{aView:aView},smalltalk.MKOverlayView)})},
+args: ["aView"],
+source: "childView: aView\x0a\x09childView := aView",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.MKOverlayView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "cssClass",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(smalltalk.MKOverlayView.superclass.fn.prototype._cssClass.apply(_st(self), [])).__comma(" mk_overlay");
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"cssClass",{},smalltalk.MKOverlayView)})},
+args: [],
+source: "cssClass\x0a\x09^ super cssClass, ' mk_overlay'",
+messageSends: [",", "cssClass"],
+referencedClasses: []
+}),
+smalltalk.MKOverlayView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "defaultControllerClass",
+category: 'defaults',
+fn: function (){
+var self=this;
+function $MKOverlayController(){return smalltalk.MKOverlayController||(typeof MKOverlayController=="undefined"?nil:MKOverlayController)}
+return smalltalk.withContext(function($ctx1) { 
+return $MKOverlayController();
+}, function($ctx1) {$ctx1.fill(self,"defaultControllerClass",{},smalltalk.MKOverlayView)})},
+args: [],
+source: "defaultControllerClass\x0a\x09^ MKOverlayController",
+messageSends: [],
+referencedClasses: ["MKOverlayController"]
+}),
+smalltalk.MKOverlayView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "remove",
+category: 'actions',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+smalltalk.MKOverlayView.superclass.fn.prototype._remove.apply(_st(self), []);
+$ctx1.sendIdx["remove"]=1;
+_st(self._childView())._remove();
+return self}, function($ctx1) {$ctx1.fill(self,"remove",{},smalltalk.MKOverlayView)})},
+args: [],
+source: "remove\x0a\x09super remove.\x0a\x09self childView remove",
+messageSends: ["remove", "childView"],
+referencedClasses: []
+}),
+smalltalk.MKOverlayView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "renderContentOn:",
+category: 'defaults',
+fn: function (html){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return self}, function($ctx1) {$ctx1.fill(self,"renderContentOn:",{html:html},smalltalk.MKOverlayView)})},
+args: ["html"],
+source: "renderContentOn: html\x0a\x09\x22Left empty on purpose. \x0a\x09No Content is rendered, as the childView is actually displayed separately\x22",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.MKOverlayView);
+
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "childView:",
+category: 'instance creation',
+fn: function (aView){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$3,$1;
+$2=self._new();
+_st($2)._childView_(aView);
+$3=_st($2)._yourself();
+$1=$3;
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"childView:",{aView:aView},smalltalk.MKOverlayView.klass)})},
+args: ["aView"],
+source: "childView: aView\x0a\x09^ self new\x0a\x09\x09childView: aView;\x0a\x09\x09yourself",
+messageSends: ["childView:", "new", "yourself"],
+referencedClasses: []
+}),
+smalltalk.MKOverlayView.klass);
+
+
+smalltalk.addClass('MKPaneView', smalltalk.MKView, ['views'], 'Moka-Views');
+smalltalk.MKPaneView.comment="I am a view containing other views.\x0a\x0a## API\x0a\x0aUse `#addView:` to add a view to the pane.";
+smalltalk.addMethod(
+smalltalk.method({
+selector: "addView:",
+category: 'adding',
+fn: function (aView){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self._views())._add_(aView);
+return self}, function($ctx1) {$ctx1.fill(self,"addView:",{aView:aView},smalltalk.MKPaneView)})},
+args: ["aView"],
+source: "addView: aView\x0a\x09self views add: aView",
+messageSends: ["add:", "views"],
+referencedClasses: []
+}),
+smalltalk.MKPaneView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "borderBottom:",
+category: 'layout',
+fn: function (aNumber){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self._layout())._borderBottom_(aNumber);
+return self}, function($ctx1) {$ctx1.fill(self,"borderBottom:",{aNumber:aNumber},smalltalk.MKPaneView)})},
+args: ["aNumber"],
+source: "borderBottom: aNumber\x0a\x09self layout borderBottom: aNumber",
+messageSends: ["borderBottom:", "layout"],
+referencedClasses: []
+}),
+smalltalk.MKPaneView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "borderLeft:",
+category: 'layout',
+fn: function (aNumber){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self._layout())._borderLeft_(aNumber);
+return self}, function($ctx1) {$ctx1.fill(self,"borderLeft:",{aNumber:aNumber},smalltalk.MKPaneView)})},
+args: ["aNumber"],
+source: "borderLeft: aNumber\x0a\x09self layout borderLeft: aNumber",
+messageSends: ["borderLeft:", "layout"],
+referencedClasses: []
+}),
+smalltalk.MKPaneView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "borderRight:",
+category: 'layout',
+fn: function (aNumber){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self._layout())._borderRight_(aNumber);
+return self}, function($ctx1) {$ctx1.fill(self,"borderRight:",{aNumber:aNumber},smalltalk.MKPaneView)})},
+args: ["aNumber"],
+source: "borderRight: aNumber\x0a\x09self layout borderRight: aNumber",
+messageSends: ["borderRight:", "layout"],
+referencedClasses: []
+}),
+smalltalk.MKPaneView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "borderTop:",
+category: 'layout',
+fn: function (aNumber){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self._layout())._borderTop_(aNumber);
+return self}, function($ctx1) {$ctx1.fill(self,"borderTop:",{aNumber:aNumber},smalltalk.MKPaneView)})},
+args: ["aNumber"],
+source: "borderTop: aNumber\x0a\x09self layout borderTop: aNumber",
+messageSends: ["borderTop:", "layout"],
+referencedClasses: []
+}),
+smalltalk.MKPaneView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "cssClass",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(smalltalk.MKPaneView.superclass.fn.prototype._cssClass.apply(_st(self), [])).__comma(" mk_pane");
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"cssClass",{},smalltalk.MKPaneView)})},
+args: [],
+source: "cssClass\x0a\x09^ super cssClass, ' mk_pane'",
+messageSends: [",", "cssClass"],
+referencedClasses: []
+}),
+smalltalk.MKPaneView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "defaultLayout",
+category: 'defaults',
+fn: function (){
+var self=this;
+function $MKPaneLayout(){return smalltalk.MKPaneLayout||(typeof MKPaneLayout=="undefined"?nil:MKPaneLayout)}
+return smalltalk.withContext(function($ctx1) { 
+var $2,$3,$1;
+$2=_st($MKPaneLayout())._new();
+_st($2)._left_((0));
+_st($2)._top_((0));
+_st($2)._right_((0));
+_st($2)._bottom_((0));
+$3=_st($2)._yourself();
+$1=$3;
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"defaultLayout",{},smalltalk.MKPaneView)})},
+args: [],
+source: "defaultLayout\x0a\x09^ MKPaneLayout new\x0a\x09\x09left: 0;\x0a\x09\x09top: 0;\x0a\x09\x09right: 0;\x0a\x09\x09bottom: 0;\x0a\x09\x09yourself",
+messageSends: ["left:", "new", "top:", "right:", "bottom:", "yourself"],
+referencedClasses: ["MKPaneLayout"]
+}),
+smalltalk.MKPaneView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "renderContentOn:",
+category: 'rendering',
+fn: function (html){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self._views())._do_((function(each){
+return smalltalk.withContext(function($ctx2) {
+return _st(html)._with_(each);
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})}));
+return self}, function($ctx1) {$ctx1.fill(self,"renderContentOn:",{html:html},smalltalk.MKPaneView)})},
+args: ["html"],
+source: "renderContentOn: html\x0a\x09self views do: [ :each | \x0a\x09\x09html with: each ]",
+messageSends: ["do:", "views", "with:"],
+referencedClasses: []
+}),
+smalltalk.MKPaneView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "views",
+category: 'accessing',
+fn: function (){
+var self=this;
+function $OrderedCollection(){return smalltalk.OrderedCollection||(typeof OrderedCollection=="undefined"?nil:OrderedCollection)}
+return smalltalk.withContext(function($ctx1) { 
+var $2,$1;
+$2=self["@views"];
+if(($receiver = $2) == nil || $receiver == null){
+self["@views"]=_st($OrderedCollection())._new();
+$1=self["@views"];
+} else {
+$1=$2;
+};
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"views",{},smalltalk.MKPaneView)})},
+args: [],
+source: "views\x0a\x09^ views ifNil: [ views := OrderedCollection new ]",
+messageSends: ["ifNil:", "new"],
+referencedClasses: ["OrderedCollection"]
+}),
+smalltalk.MKPaneView);
+
+
+
+smalltalk.addClass('MKModalPaneView', smalltalk.MKPaneView, ['overlay', 'closeOnEnter', 'closeOnClick'], 'Moka-Views');
+smalltalk.addMethod(
+smalltalk.method({
+selector: "closeOnClick",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$1;
+$2=self["@closeOnClick"];
+if(($receiver = $2) == nil || $receiver == null){
+$1=false;
+} else {
+$1=$2;
+};
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"closeOnClick",{},smalltalk.MKModalPaneView)})},
+args: [],
+source: "closeOnClick\x0a\x09^ closeOnClick ifNil: [ false ]",
+messageSends: ["ifNil:"],
+referencedClasses: []
+}),
+smalltalk.MKModalPaneView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "closeOnClick:",
+category: 'accessing',
+fn: function (aBoolean){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self["@closeOnClick"]=aBoolean;
+return self}, function($ctx1) {$ctx1.fill(self,"closeOnClick:",{aBoolean:aBoolean},smalltalk.MKModalPaneView)})},
+args: ["aBoolean"],
+source: "closeOnClick: aBoolean\x0a\x09closeOnClick := aBoolean",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.MKModalPaneView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "closeOnEnter",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$1;
+$2=self["@closeOnEnter"];
+if(($receiver = $2) == nil || $receiver == null){
+$1=false;
+} else {
+$1=$2;
+};
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"closeOnEnter",{},smalltalk.MKModalPaneView)})},
+args: [],
+source: "closeOnEnter\x0a\x09^ closeOnEnter ifNil: [ false ]",
+messageSends: ["ifNil:"],
+referencedClasses: []
+}),
+smalltalk.MKModalPaneView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "closeOnEnter:",
+category: 'accessing',
+fn: function (aBoolean){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self["@closeOnEnter"]=aBoolean;
+return self}, function($ctx1) {$ctx1.fill(self,"closeOnEnter:",{aBoolean:aBoolean},smalltalk.MKModalPaneView)})},
+args: ["aBoolean"],
+source: "closeOnEnter: aBoolean\x0a\x09closeOnEnter := aBoolean",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.MKModalPaneView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "cssClass",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(smalltalk.MKModalPaneView.superclass.fn.prototype._cssClass.apply(_st(self), [])).__comma(" mk_modal");
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"cssClass",{},smalltalk.MKModalPaneView)})},
+args: [],
+source: "cssClass\x0a\x09^ super cssClass, ' mk_modal'",
+messageSends: [",", "cssClass"],
+referencedClasses: []
+}),
+smalltalk.MKModalPaneView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "defaultControllerClass",
+category: 'defaults',
+fn: function (){
+var self=this;
+function $MKModalPaneController(){return smalltalk.MKModalPaneController||(typeof MKModalPaneController=="undefined"?nil:MKModalPaneController)}
+return smalltalk.withContext(function($ctx1) { 
+return $MKModalPaneController();
+}, function($ctx1) {$ctx1.fill(self,"defaultControllerClass",{},smalltalk.MKModalPaneView)})},
+args: [],
+source: "defaultControllerClass\x0a\x09^ MKModalPaneController",
+messageSends: [],
+referencedClasses: ["MKModalPaneController"]
+}),
+smalltalk.MKModalPaneView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "defaultLayout",
+category: 'defaults',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$3,$1;
+$2=smalltalk.MKModalPaneView.superclass.fn.prototype._defaultLayout.apply(_st(self), []);
+_st($2)._centerY_((0));
+_st($2)._centerX_((0));
+_st($2)._width_((300));
+_st($2)._height_((200));
+$3=_st($2)._yourself();
+$1=$3;
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"defaultLayout",{},smalltalk.MKModalPaneView)})},
+args: [],
+source: "defaultLayout\x0a\x09^ super defaultLayout\x0a\x09\x09centerY: 0;\x0a\x09\x09centerX: 0;\x0a\x09\x09width: 300;\x0a\x09\x09height: 200;\x0a\x09\x09yourself",
+messageSends: ["centerY:", "defaultLayout", "centerX:", "width:", "height:", "yourself"],
+referencedClasses: []
+}),
+smalltalk.MKModalPaneView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "overlay",
+category: 'accessing',
+fn: function (){
+var self=this;
+function $MKOverlayView(){return smalltalk.MKOverlayView||(typeof MKOverlayView=="undefined"?nil:MKOverlayView)}
+return smalltalk.withContext(function($ctx1) { 
+var $2,$1;
+$2=self["@overlay"];
+if(($receiver = $2) == nil || $receiver == null){
+self["@overlay"]=_st($MKOverlayView())._childView_(self);
+$1=self["@overlay"];
+} else {
+$1=$2;
+};
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"overlay",{},smalltalk.MKModalPaneView)})},
+args: [],
+source: "overlay\x0a\x09^ overlay ifNil: [ overlay := MKOverlayView childView: self ]",
+messageSends: ["ifNil:", "childView:"],
+referencedClasses: ["MKOverlayView"]
+}),
+smalltalk.MKModalPaneView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "renderOn:",
+category: 'rendering',
+fn: function (html){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+smalltalk.MKModalPaneView.superclass.fn.prototype._renderOn_.apply(_st(self), [html]);
+_st(self["@root"])._at_put_("tabindex","0");
+_st(_st(self["@root"])._asJQuery())._focus();
+_st(html)._with_(self._overlay());
+return self}, function($ctx1) {$ctx1.fill(self,"renderOn:",{html:html},smalltalk.MKModalPaneView)})},
+args: ["html"],
+source: "renderOn: html\x0a\x09super renderOn: html.\x0a\x09root at: 'tabindex' put: '0'.\x0a\x09root asJQuery focus.\x0a\x09html with: self overlay",
+messageSends: ["renderOn:", "at:put:", "focus", "asJQuery", "with:", "overlay"],
+referencedClasses: []
+}),
+smalltalk.MKModalPaneView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "zindex",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return (1001);
+}, function($ctx1) {$ctx1.fill(self,"zindex",{},smalltalk.MKModalPaneView)})},
+args: [],
+source: "zindex\x0a\x09^ 1001",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.MKModalPaneView);
+
+
+
+smalltalk.addClass('MKPanelView', smalltalk.MKPaneView, [], 'Moka-Views');
+smalltalk.MKPanelView.comment="I am similar to a `MKPaneView` but I am scrollable and display a light background.";
+smalltalk.addMethod(
+smalltalk.method({
+selector: "cssClass",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(smalltalk.MKPanelView.superclass.fn.prototype._cssClass.apply(_st(self), [])).__comma(" mk_panel");
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"cssClass",{},smalltalk.MKPanelView)})},
+args: [],
+source: "cssClass\x0a\x09^ super cssClass, ' mk_panel'",
+messageSends: [",", "cssClass"],
+referencedClasses: []
+}),
+smalltalk.MKPanelView);
+
+
+
+smalltalk.addClass('MKSelectionView', smalltalk.MKAspectsView, ['selectionAspect', 'collectionAspect'], 'Moka-Views');
+smalltalk.MKSelectionView.comment="I an abstract selection view of a list of elements.";
+smalltalk.addMethod(
+smalltalk.method({
+selector: "collection",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=self._valueForAspect_(self._collectionAspect());
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"collection",{},smalltalk.MKSelectionView)})},
+args: [],
+source: "collection\x0a\x09^ self valueForAspect: self collectionAspect",
+messageSends: ["valueForAspect:", "collectionAspect"],
+referencedClasses: []
+}),
+smalltalk.MKSelectionView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "collectionAspect",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=self["@collectionAspect"];
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"collectionAspect",{},smalltalk.MKSelectionView)})},
+args: [],
+source: "collectionAspect\x0a\x09^ collectionAspect",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.MKSelectionView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "collectionAspect:",
+category: 'accessing',
+fn: function (aSelector){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self["@collectionAspect"]=aSelector;
+return self}, function($ctx1) {$ctx1.fill(self,"collectionAspect:",{aSelector:aSelector},smalltalk.MKSelectionView)})},
+args: ["aSelector"],
+source: "collectionAspect: aSelector\x0a\x09collectionAspect := aSelector",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.MKSelectionView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "defaultDisplayBlock",
+category: 'defaults',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=(function(item){
+return smalltalk.withContext(function($ctx2) {
+return _st(item)._asString();
+}, function($ctx2) {$ctx2.fillBlock({item:item},$ctx1,1)})});
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"defaultDisplayBlock",{},smalltalk.MKSelectionView)})},
+args: [],
+source: "defaultDisplayBlock\x0a\x09^ [ :item | item asString ]",
+messageSends: ["asString"],
+referencedClasses: []
+}),
+smalltalk.MKSelectionView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "selectedItem",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=self._valueForAspect_(self._selectionAspect());
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"selectedItem",{},smalltalk.MKSelectionView)})},
+args: [],
+source: "selectedItem\x0a\x09^ self valueForAspect: self selectionAspect",
+messageSends: ["valueForAspect:", "selectionAspect"],
+referencedClasses: []
+}),
+smalltalk.MKSelectionView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "selectionAspect",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=self["@selectionAspect"];
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"selectionAspect",{},smalltalk.MKSelectionView)})},
+args: [],
+source: "selectionAspect\x0a\x09^ selectionAspect",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.MKSelectionView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "selectionAspect:",
+category: 'accessing',
+fn: function (aSelector){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self["@selectionAspect"]=aSelector;
+return self}, function($ctx1) {$ctx1.fill(self,"selectionAspect:",{aSelector:aSelector},smalltalk.MKSelectionView)})},
+args: ["aSelector"],
+source: "selectionAspect: aSelector\x0a\x09selectionAspect := aSelector",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.MKSelectionView);
+
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "model:collectionAspect:selectionAspect:",
+category: 'instance creation',
+fn: function (aModel,collectionSelector,selectionSelector){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$3,$1;
+$2=self._model_(aModel);
+_st($2)._collectionAspect_(collectionSelector);
+_st($2)._selectionAspect_(selectionSelector);
+$3=_st($2)._yourself();
+$1=$3;
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"model:collectionAspect:selectionAspect:",{aModel:aModel,collectionSelector:collectionSelector,selectionSelector:selectionSelector},smalltalk.MKSelectionView.klass)})},
+args: ["aModel", "collectionSelector", "selectionSelector"],
+source: "model: aModel collectionAspect: collectionSelector selectionAspect: selectionSelector\x0a\x09^ (self model: aModel)\x0a\x09\x09collectionAspect: collectionSelector;\x0a\x09\x09selectionAspect: selectionSelector;\x0a\x09\x09yourself",
+messageSends: ["collectionAspect:", "model:", "selectionAspect:", "yourself"],
+referencedClasses: []
+}),
+smalltalk.MKSelectionView.klass);
+
+
+smalltalk.addClass('MKDropdownView', smalltalk.MKSelectionView, ['modalPaneView', 'listView'], 'Moka-Views');
+smalltalk.MKDropdownView.comment="I am a push button view. My default controller is `MKButtonController`.\x0a\x0aMy controller must answer to `#onPressed`.\x0a\x0a## API\x0a\x0a- Instances can be set a `default` button\x0a- Use `#label:` to set the label string";
+smalltalk.addMethod(
+smalltalk.method({
+selector: "cssClass",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(smalltalk.MKDropdownView.superclass.fn.prototype._cssClass.apply(_st(self), [])).__comma(" mk_dropdown");
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"cssClass",{},smalltalk.MKDropdownView)})},
+args: [],
+source: "cssClass\x0a\x09^ super cssClass, ' mk_dropdown'",
+messageSends: [",", "cssClass"],
+referencedClasses: []
+}),
+smalltalk.MKDropdownView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "defaultControllerClass",
+category: 'defaults',
+fn: function (){
+var self=this;
+function $MKDropdownController(){return smalltalk.MKDropdownController||(typeof MKDropdownController=="undefined"?nil:MKDropdownController)}
+return smalltalk.withContext(function($ctx1) { 
+return $MKDropdownController();
+}, function($ctx1) {$ctx1.fill(self,"defaultControllerClass",{},smalltalk.MKDropdownView)})},
+args: [],
+source: "defaultControllerClass\x0a\x09^ MKDropdownController",
+messageSends: [],
+referencedClasses: ["MKDropdownController"]
+}),
+smalltalk.MKDropdownView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "defaultLayout",
+category: 'defaults',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$3,$1;
+$2=smalltalk.MKDropdownView.superclass.fn.prototype._defaultLayout.apply(_st(self), []);
+_st($2)._width_((120));
+_st($2)._height_((24));
+$3=_st($2)._yourself();
+$1=$3;
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"defaultLayout",{},smalltalk.MKDropdownView)})},
+args: [],
+source: "defaultLayout\x0a\x09^ super defaultLayout\x0a\x09\x09width: 120;\x0a\x09\x09height: 24;\x0a\x09\x09yourself",
+messageSends: ["width:", "defaultLayout", "height:", "yourself"],
+referencedClasses: []
+}),
+smalltalk.MKDropdownView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "listView",
+category: 'views',
+fn: function (){
+var self=this;
+function $MKDropdownListView(){return smalltalk.MKDropdownListView||(typeof MKDropdownListView=="undefined"?nil:MKDropdownListView)}
+return smalltalk.withContext(function($ctx1) { 
+var $2,$3,$4,$1;
+$2=self["@listView"];
+if(($receiver = $2) == nil || $receiver == null){
+$3=_st($MKDropdownListView())._model_collectionAspect_selectionAspect_(self._model(),self._collectionAspect(),self._selectionAspect());
+_st($3)._width_("auto");
+_st($3)._height_("auto");
+$4=_st($3)._yourself();
+self["@listView"]=$4;
+$1=self["@listView"];
+} else {
+$1=$2;
+};
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"listView",{},smalltalk.MKDropdownView)})},
+args: [],
+source: "listView\x0a\x09^ listView ifNil: [\x0a\x09\x09listView := (MKDropdownListView \x09\x0a\x09\x09\x09model: self model\x0a\x09\x09\x09collectionAspect: self collectionAspect\x0a\x09\x09\x09selectionAspect: self selectionAspect)\x0a\x09\x09\x09\x09width: 'auto';\x0a\x09\x09\x09\x09height: 'auto';\x0a\x09\x09\x09\x09yourself ]",
+messageSends: ["ifNil:", "width:", "model:collectionAspect:selectionAspect:", "model", "collectionAspect", "selectionAspect", "height:", "yourself"],
+referencedClasses: ["MKDropdownListView"]
+}),
+smalltalk.MKDropdownView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "modalPaneView",
+category: 'views',
+fn: function (){
+var self=this;
+function $MKModalPaneView(){return smalltalk.MKModalPaneView||(typeof MKModalPaneView=="undefined"?nil:MKModalPaneView)}
+return smalltalk.withContext(function($ctx1) { 
+var $2,$3,$4,$6,$5,$7,$1;
+$2=self["@modalPaneView"];
+if(($receiver = $2) == nil || $receiver == null){
+$3=_st($MKModalPaneView())._new();
+_st($3)._extraCssClass_("mk_dropdown_pane");
+_st($3)._closeOnEnter_(true);
+_st($3)._closeOnClick_(true);
+_st($3)._addView_(self._listView());
+$4=$3;
+$6=self._position();
+$ctx1.sendIdx["position"]=1;
+$5=_st($6)._x();
+_st($4)._left_($5);
+_st($3)._top_(_st(self._position())._y());
+_st($3)._height_((400));
+$7=_st($3)._yourself();
+self["@modalPaneView"]=$7;
+$1=self["@modalPaneView"];
+} else {
+$1=$2;
+};
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"modalPaneView",{},smalltalk.MKDropdownView)})},
+args: [],
+source: "modalPaneView\x0a\x09^ modalPaneView ifNil: [\x0a\x09\x09modalPaneView := MKModalPaneView new\x0a\x09\x09\x09extraCssClass: 'mk_dropdown_pane';\x0a\x09\x09\x09closeOnEnter: true;\x0a\x09\x09\x09closeOnClick: true;\x0a\x09\x09\x09addView: self listView;\x0a\x09\x09\x09left: self position x;\x0a\x09\x09\x09top: self position y;\x0a\x09\x09\x09\x22Max height of the list\x22\x0a\x09\x09\x09height: 400;\x0a\x09\x09\x09yourself ]",
+messageSends: ["ifNil:", "extraCssClass:", "new", "closeOnEnter:", "closeOnClick:", "addView:", "listView", "left:", "x", "position", "top:", "y", "height:", "yourself"],
+referencedClasses: ["MKModalPaneView"]
+}),
+smalltalk.MKDropdownView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "popupList",
+category: 'actions',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self._modalPaneView())._render();
+_st(self._listView())._focus();
+return self}, function($ctx1) {$ctx1.fill(self,"popupList",{},smalltalk.MKDropdownView)})},
+args: [],
+source: "popupList\x0a\x09\x22Show a new list view inside a modal pane\x22\x0a\x09self modalPaneView render.\x0a\x09self listView focus",
+messageSends: ["render", "modalPaneView", "focus", "listView"],
+referencedClasses: []
+}),
+smalltalk.MKDropdownView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "renderContentOn:",
+category: 'rendering',
+fn: function (html){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(_st(html)._div())._class_("mk_dropdown_arrows");
+_st(html)._with_(self._selectedItem());
+return self}, function($ctx1) {$ctx1.fill(self,"renderContentOn:",{html:html},smalltalk.MKDropdownView)})},
+args: ["html"],
+source: "renderContentOn: html\x0a\x09html div class: 'mk_dropdown_arrows'.\x0a\x09html with: self selectedItem",
+messageSends: ["class:", "div", "with:", "selectedItem"],
+referencedClasses: []
+}),
+smalltalk.MKDropdownView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "selectedListItem",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(_st(_st(self["@root"])._asJQuery())._find_(":selected"))._text();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"selectedListItem",{},smalltalk.MKDropdownView)})},
+args: [],
+source: "selectedListItem\x0a\x09^ (root asJQuery find: ':selected') text",
+messageSends: ["text", "find:", "asJQuery"],
+referencedClasses: []
+}),
+smalltalk.MKDropdownView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "tag",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return "button";
+}, function($ctx1) {$ctx1.fill(self,"tag",{},smalltalk.MKDropdownView)})},
+args: [],
+source: "tag\x0a\x09^ 'button'",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.MKDropdownView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "update:",
+category: 'accessing',
+fn: function (anAnnouncement){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st([self._selectionAspect(),self._collectionAspect()])._includes_(_st(anAnnouncement)._aspect());
+if(smalltalk.assert($1)){
+self._update();
+};
+return self}, function($ctx1) {$ctx1.fill(self,"update:",{anAnnouncement:anAnnouncement},smalltalk.MKDropdownView)})},
+args: ["anAnnouncement"],
+source: "update: anAnnouncement\x0a\x09({self selectionAspect. self collectionAspect} \x0a\x09\x09includes: anAnnouncement aspect) ifTrue: [\x0a\x09\x09\x09self update ]",
+messageSends: ["ifTrue:", "includes:", "selectionAspect", "collectionAspect", "aspect", "update"],
+referencedClasses: []
+}),
+smalltalk.MKDropdownView);
+
+
+
+smalltalk.addClass('MKListView', smalltalk.MKSelectionView, ['displayBlock'], 'Moka-Views');
+smalltalk.MKListView.comment="I display a list of elements in a list control field.";
+smalltalk.addMethod(
+smalltalk.method({
+selector: "activateItem:",
+category: 'actions',
+fn: function (anObject){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._activateListItem_(self._findListItemFor_(anObject));
+return self}, function($ctx1) {$ctx1.fill(self,"activateItem:",{anObject:anObject},smalltalk.MKListView)})},
+args: ["anObject"],
+source: "activateItem: anObject\x0a\x09self activateListItem: (self findListItemFor: anObject)",
+messageSends: ["activateListItem:", "findListItemFor:"],
+referencedClasses: []
+}),
+smalltalk.MKListView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "activateListItem:",
+category: 'actions',
+fn: function (aListItem){
+var self=this;
+var item;
+return smalltalk.withContext(function($ctx1) { 
+var $1,$2,$3;
+$1=_st(aListItem)._get_((0));
+if(($receiver = $1) == nil || $receiver == null){
+return self;
+} else {
+$1;
+};
+$2=_st(_st(aListItem)._parent())._children();
+$3=self._selectedCssClass();
+$ctx1.sendIdx["selectedCssClass"]=1;
+_st($2)._removeClass_($3);
+_st(aListItem)._addClass_(self._selectedCssClass());
+self._ensureVisible_(aListItem);
+return self}, function($ctx1) {$ctx1.fill(self,"activateListItem:",{aListItem:aListItem,item:item},smalltalk.MKListView)})},
+args: ["aListItem"],
+source: "activateListItem: aListItem\x0a\x09| item |\x0a\x09\x0a\x09(aListItem get: 0) ifNil: [ ^ self ].\x0a\x09aListItem parent children removeClass: self selectedCssClass.\x0a\x09aListItem addClass: self selectedCssClass.\x0a    \x0a\x09self ensureVisible: aListItem",
+messageSends: ["ifNil:", "get:", "removeClass:", "children", "parent", "selectedCssClass", "addClass:", "ensureVisible:"],
+referencedClasses: []
+}),
+smalltalk.MKListView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "activeItem",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=self._findItemFor_(_st(_st(self["@root"])._asJQuery())._find_(".".__comma(self._selectedCssClass())));
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"activeItem",{},smalltalk.MKListView)})},
+args: [],
+source: "activeItem\x0a\x09^ self findItemFor: (root asJQuery find: '.', self selectedCssClass)",
+messageSends: ["findItemFor:", "find:", "asJQuery", ",", "selectedCssClass"],
+referencedClasses: []
+}),
+smalltalk.MKListView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "cssClass",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(smalltalk.MKListView.superclass.fn.prototype._cssClass.apply(_st(self), [])).__comma(" mk_list");
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"cssClass",{},smalltalk.MKListView)})},
+args: [],
+source: "cssClass\x0a\x09^ super cssClass, ' mk_list'",
+messageSends: [",", "cssClass"],
+referencedClasses: []
+}),
+smalltalk.MKListView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "defaultControllerClass",
+category: 'defaults',
+fn: function (){
+var self=this;
+function $MKListController(){return smalltalk.MKListController||(typeof MKListController=="undefined"?nil:MKListController)}
+return smalltalk.withContext(function($ctx1) { 
+return $MKListController();
+}, function($ctx1) {$ctx1.fill(self,"defaultControllerClass",{},smalltalk.MKListView)})},
+args: [],
+source: "defaultControllerClass\x0a\x09^ MKListController",
+messageSends: [],
+referencedClasses: ["MKListController"]
+}),
+smalltalk.MKListView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "defaultDisplayBlock",
+category: 'defaults',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=(function(item){
+return smalltalk.withContext(function($ctx2) {
+return _st(item)._asString();
+}, function($ctx2) {$ctx2.fillBlock({item:item},$ctx1,1)})});
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"defaultDisplayBlock",{},smalltalk.MKListView)})},
+args: [],
+source: "defaultDisplayBlock\x0a\x09^ [ :item | item asString ]",
+messageSends: ["asString"],
+referencedClasses: []
+}),
+smalltalk.MKListView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "displayBlock",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$1;
+$2=self["@displayBlock"];
+if(($receiver = $2) == nil || $receiver == null){
+$1=self._defaultDisplayBlock();
+} else {
+$1=$2;
+};
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"displayBlock",{},smalltalk.MKListView)})},
+args: [],
+source: "displayBlock\x0a\x09^ displayBlock ifNil: [ self defaultDisplayBlock ]",
+messageSends: ["ifNil:", "defaultDisplayBlock"],
+referencedClasses: []
+}),
+smalltalk.MKListView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "displayBlock:",
+category: 'accessing',
+fn: function (aBlock){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self["@displayBlock"]=aBlock;
+return self}, function($ctx1) {$ctx1.fill(self,"displayBlock:",{aBlock:aBlock},smalltalk.MKListView)})},
+args: ["aBlock"],
+source: "displayBlock: aBlock\x0a\x09displayBlock := aBlock",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.MKListView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "ensureVisible:",
+category: 'private',
+fn: function (aListItem){
+var self=this;
+var parent,position;
+return smalltalk.withContext(function($ctx1) { 
+var $1,$4,$3,$2,$5,$9,$8,$11,$10,$7,$6,$15,$14,$16,$13,$17,$12,$18,$22,$23,$21,$20,$19;
+$1=_st(aListItem)._get_((0));
+$ctx1.sendIdx["get:"]=1;
+if(($receiver = $1) == nil || $receiver == null){
+return self;
+} else {
+$1;
+};
+position=self._positionOf_(aListItem);
+parent=_st(aListItem)._parent();
+$4=_st(aListItem)._position();
+$ctx1.sendIdx["position"]=1;
+$3=_st($4)._top();
+$ctx1.sendIdx["top"]=1;
+$2=_st($3).__lt((0));
+if(smalltalk.assert($2)){
+$5=_st(parent)._get_((0));
+$ctx1.sendIdx["get:"]=2;
+$9=_st(parent)._get_((0));
+$ctx1.sendIdx["get:"]=3;
+$8=_st($9)._scrollTop();
+$ctx1.sendIdx["scrollTop"]=1;
+$11=_st(aListItem)._position();
+$ctx1.sendIdx["position"]=2;
+$10=_st($11)._top();
+$ctx1.sendIdx["top"]=2;
+$7=_st($8).__plus($10);
+$ctx1.sendIdx["+"]=1;
+$6=_st($7).__minus((10));
+$ctx1.sendIdx["-"]=1;
+_st($5)._scrollTop_($6);
+$ctx1.sendIdx["scrollTop:"]=1;
+};
+$15=_st(aListItem)._position();
+$ctx1.sendIdx["position"]=3;
+$14=_st($15)._top();
+$ctx1.sendIdx["top"]=3;
+$16=_st(aListItem)._height();
+$ctx1.sendIdx["height"]=1;
+$13=_st($14).__plus($16);
+$ctx1.sendIdx["+"]=2;
+$17=_st(parent)._height();
+$ctx1.sendIdx["height"]=2;
+$12=_st($13).__gt($17);
+if(smalltalk.assert($12)){
+$18=_st(parent)._get_((0));
+$ctx1.sendIdx["get:"]=4;
+$22=_st(_st(parent)._get_((0)))._scrollTop();
+$23=_st(aListItem)._height();
+$ctx1.sendIdx["height"]=3;
+$21=_st($22).__plus($23);
+$20=_st($21).__minus(_st(_st(parent)._height()).__minus(_st(_st(aListItem)._position())._top()));
+$ctx1.sendIdx["-"]=2;
+$19=_st($20).__plus((10));
+$ctx1.sendIdx["+"]=3;
+_st($18)._scrollTop_($19);
+};
+return self}, function($ctx1) {$ctx1.fill(self,"ensureVisible:",{aListItem:aListItem,parent:parent,position:position},smalltalk.MKListView)})},
+args: ["aListItem"],
+source: "ensureVisible: aListItem\x09\x0a\x09\x22Move the scrollbar to show the active element\x22\x0a\x09\x0a\x09| parent position |\x0a\x09(aListItem get: 0) ifNil: [ ^ self ].\x0a\x09position := self positionOf: aListItem.\x0a\x09parent := aListItem parent.\x0a\x09\x0a    aListItem position top < 0 ifTrue: [\x0a\x09\x09(parent get: 0) scrollTop: ((parent get: 0) scrollTop + aListItem position top - 10) ].\x0a    aListItem position top + aListItem height > parent height ifTrue: [ \x0a\x09\x09(parent get: 0) scrollTop: ((parent get: 0) scrollTop + aListItem height - (parent height - aListItem position top)) +10 ]",
+messageSends: ["ifNil:", "get:", "positionOf:", "parent", "ifTrue:", "<", "top", "position", "scrollTop:", "-", "+", "scrollTop", ">", "height"],
+referencedClasses: []
+}),
+smalltalk.MKListView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "findItemFor:",
+category: 'accessing',
+fn: function (aListItem){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(_st(_st(aListItem)._asJQuery())._data())._at_("item");
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"findItemFor:",{aListItem:aListItem},smalltalk.MKListView)})},
+args: ["aListItem"],
+source: "findItemFor: aListItem\x0a\x09^ aListItem asJQuery data at: 'item'",
+messageSends: ["at:", "data", "asJQuery"],
+referencedClasses: []
+}),
+smalltalk.MKListView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "findListItemFor:",
+category: 'accessing',
+fn: function (anObject){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $4,$3,$2,$1;
+$4=_st(self["@root"])._asJQuery();
+$ctx1.sendIdx["asJQuery"]=1;
+$3=_st($4)._find_("li");
+$2=_st($3)._filter_(_st((function(thisArg){
+return smalltalk.withContext(function($ctx2) {
+return _st(_st(_st(thisArg)._asJQuery())._data_("item")).__eq(anObject);
+}, function($ctx2) {$ctx2.fillBlock({thisArg:thisArg},$ctx1,1)})}))._currySelf());
+$1=_st($2)._eq_((0));
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"findListItemFor:",{anObject:anObject},smalltalk.MKListView)})},
+args: ["anObject"],
+source: "findListItemFor: anObject\x0a\x09^ (((root asJQuery find: 'li') \x0a\x09\x09filter: [ :thisArg | (thisArg asJQuery data: 'item') = anObject ] currySelf) eq: 0)",
+messageSends: ["eq:", "filter:", "find:", "asJQuery", "currySelf", "=", "data:"],
+referencedClasses: []
+}),
+smalltalk.MKListView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "positionOf:",
+category: 'private',
+fn: function (aListItem){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return aListItem.parent().children().get().indexOf(aListItem.get(0)) + 1;
+return self}, function($ctx1) {$ctx1.fill(self,"positionOf:",{aListItem:aListItem},smalltalk.MKListView)})},
+args: ["aListItem"],
+source: "positionOf: aListItem\x0a\x09\x22TODO: rewrite in smalltalk\x22\x0a\x09<return aListItem.parent().children().get().indexOf(aListItem.get(0)) + 1>",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.MKListView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "renderContentOn:",
+category: 'rendering',
+fn: function (html){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self._collection())._do_((function(each){
+return smalltalk.withContext(function($ctx2) {
+return self._renderItem_on_(each,html);
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})}));
+_st(self["@root"])._at_put_("tabindex","0");
+return self}, function($ctx1) {$ctx1.fill(self,"renderContentOn:",{html:html},smalltalk.MKListView)})},
+args: ["html"],
+source: "renderContentOn: html\x0a\x09self collection do: [ :each  | \x0a    \x09self renderItem: each  on: html ].\x0a\x09\x0a\x09\x22make the list focusable\x22\x0a\x09root at: 'tabindex' put: '0'",
+messageSends: ["do:", "collection", "renderItem:on:", "at:put:"],
+referencedClasses: []
+}),
+smalltalk.MKListView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "renderItem:on:",
+category: 'rendering',
+fn: function (anObject,html){
+var self=this;
+var li;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+li=_st(html)._li();
+_st(_st(li)._asJQuery())._data_put_("item",anObject);
+$1=_st(self._selectedItem()).__eq(anObject);
+if(smalltalk.assert($1)){
+_st(li)._class_(self._selectedCssClass());
+};
+_st(li)._with_(_st(self._displayBlock())._value_(anObject));
+return self}, function($ctx1) {$ctx1.fill(self,"renderItem:on:",{anObject:anObject,html:html,li:li},smalltalk.MKListView)})},
+args: ["anObject", "html"],
+source: "renderItem: anObject on: html\x0a\x09| li |\x0a\x09\x0a\x09li := html li.\x0a\x09li asJQuery data: 'item' put: anObject.\x0a\x09\x0a\x09self selectedItem = anObject ifTrue: [\x0a\x09\x09li class: self selectedCssClass ].\x09\x0a\x09li with: (self displayBlock value: anObject)",
+messageSends: ["li", "data:put:", "asJQuery", "ifTrue:", "=", "selectedItem", "class:", "selectedCssClass", "with:", "value:", "displayBlock"],
+referencedClasses: []
+}),
+smalltalk.MKListView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "selectedCssClass",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return "selected";
+}, function($ctx1) {$ctx1.fill(self,"selectedCssClass",{},smalltalk.MKListView)})},
+args: [],
+source: "selectedCssClass\x0a\x09^ 'selected'",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.MKListView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "tag",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return "ul";
+}, function($ctx1) {$ctx1.fill(self,"tag",{},smalltalk.MKListView)})},
+args: [],
+source: "tag\x0a\x09^ 'ul'",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.MKListView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "update:",
+category: 'updating',
+fn: function (anAnnouncement){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$1,$3;
+$2=_st(anAnnouncement)._aspect();
+$ctx1.sendIdx["aspect"]=1;
+$1=_st($2).__eq(self._selectionAspect());
+$ctx1.sendIdx["="]=1;
+if(smalltalk.assert($1)){
+self._updateSelectedItem();
+};
+$3=_st(_st(anAnnouncement)._aspect()).__eq(self._collectionAspect());
+if(smalltalk.assert($3)){
+self._update();
+};
+return self}, function($ctx1) {$ctx1.fill(self,"update:",{anAnnouncement:anAnnouncement},smalltalk.MKListView)})},
+args: ["anAnnouncement"],
+source: "update: anAnnouncement\x0a\x09anAnnouncement aspect = self selectionAspect ifTrue: [\x0a\x09\x09self updateSelectedItem ].\x0a\x09\x09\x0a\x09anAnnouncement aspect = self collectionAspect ifTrue: [\x0a\x09\x09self update ]",
+messageSends: ["ifTrue:", "=", "aspect", "selectionAspect", "updateSelectedItem", "collectionAspect", "update"],
+referencedClasses: []
+}),
+smalltalk.MKListView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "updateSelectedItem",
+category: 'updating',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._activateItem_(self._selectedItem());
+return self}, function($ctx1) {$ctx1.fill(self,"updateSelectedItem",{},smalltalk.MKListView)})},
+args: [],
+source: "updateSelectedItem\x0a\x09self activateItem: self selectedItem",
+messageSends: ["activateItem:", "selectedItem"],
+referencedClasses: []
+}),
+smalltalk.MKListView);
+
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "model:collectionAspect:selectionAspect:",
+category: 'instance creation',
+fn: function (aModel,collectionSelector,selectionSelector){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$3,$1;
+$2=self._model_(aModel);
+_st($2)._collectionAspect_(collectionSelector);
+_st($2)._selectionAspect_(selectionSelector);
+$3=_st($2)._yourself();
+$1=$3;
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"model:collectionAspect:selectionAspect:",{aModel:aModel,collectionSelector:collectionSelector,selectionSelector:selectionSelector},smalltalk.MKListView.klass)})},
+args: ["aModel", "collectionSelector", "selectionSelector"],
+source: "model: aModel collectionAspect: collectionSelector selectionAspect: selectionSelector\x0a\x09^ (self model: aModel)\x0a\x09\x09collectionAspect: collectionSelector;\x0a\x09\x09selectionAspect: selectionSelector;\x0a\x09\x09yourself",
+messageSends: ["collectionAspect:", "model:", "selectionAspect:", "yourself"],
+referencedClasses: []
+}),
+smalltalk.MKListView.klass);
+
+
+smalltalk.addClass('MKDropdownListView', smalltalk.MKListView, [], 'Moka-Views');
+smalltalk.MKDropdownListView.comment="I am similar to a `MKListView`, but inside a `MKDropdownView`.";
+smalltalk.addMethod(
+smalltalk.method({
+selector: "cssClass",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(smalltalk.MKDropdownListView.superclass.fn.prototype._cssClass.apply(_st(self), [])).__comma(" mk_dropdown_list");
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"cssClass",{},smalltalk.MKDropdownListView)})},
+args: [],
+source: "cssClass\x0a\x09^ super cssClass, ' mk_dropdown_list'",
+messageSends: [",", "cssClass"],
+referencedClasses: []
+}),
+smalltalk.MKDropdownListView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "defaultControllerClass",
+category: 'accessing',
+fn: function (){
+var self=this;
+function $MKDropdownListController(){return smalltalk.MKDropdownListController||(typeof MKDropdownListController=="undefined"?nil:MKDropdownListController)}
+return smalltalk.withContext(function($ctx1) { 
+return $MKDropdownListController();
+}, function($ctx1) {$ctx1.fill(self,"defaultControllerClass",{},smalltalk.MKDropdownListView)})},
+args: [],
+source: "defaultControllerClass\x0a\x09^ MKDropdownListController",
+messageSends: [],
+referencedClasses: ["MKDropdownListController"]
+}),
+smalltalk.MKDropdownListView);
+
+
+
+smalltalk.addClass('MKSourceListView', smalltalk.MKListView, [], 'Moka-Views');
+smalltalk.MKSourceListView.comment="I am similar to a `MKListView`, but displayed slightly differently, in a similar way as in the left-side the of Finder in OSX.";
+smalltalk.addMethod(
+smalltalk.method({
+selector: "cssClass",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(smalltalk.MKSourceListView.superclass.fn.prototype._cssClass.apply(_st(self), [])).__comma(" mk_sourcelist");
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"cssClass",{},smalltalk.MKSourceListView)})},
+args: [],
+source: "cssClass\x0a\x09^ super cssClass, ' mk_sourcelist'",
+messageSends: [",", "cssClass"],
+referencedClasses: []
+}),
+smalltalk.MKSourceListView);
+
+
+
+smalltalk.addClass('MKTextAreaView', smalltalk.MKSingleAspectView, [], 'Moka-Views');
+smalltalk.MKTextAreaView.comment="I am an text area view. My default controller is `MKAnyKeyInputController`.\x0a\x0aMy controller must answer to `#onKeyPressed:`.";
+smalltalk.addMethod(
+smalltalk.method({
+selector: "cssClass",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(smalltalk.MKTextAreaView.superclass.fn.prototype._cssClass.apply(_st(self), [])).__comma(" mk_textarea");
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"cssClass",{},smalltalk.MKTextAreaView)})},
+args: [],
+source: "cssClass\x0a\x09^ super cssClass, ' mk_textarea'",
+messageSends: [",", "cssClass"],
+referencedClasses: []
+}),
+smalltalk.MKTextAreaView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "defaultControllerClass",
+category: 'defaults',
+fn: function (){
+var self=this;
+function $MKAnyKeyInputController(){return smalltalk.MKAnyKeyInputController||(typeof MKAnyKeyInputController=="undefined"?nil:MKAnyKeyInputController)}
+return smalltalk.withContext(function($ctx1) { 
+return $MKAnyKeyInputController();
+}, function($ctx1) {$ctx1.fill(self,"defaultControllerClass",{},smalltalk.MKTextAreaView)})},
+args: [],
+source: "defaultControllerClass\x0a\x09^ MKAnyKeyInputController",
+messageSends: [],
+referencedClasses: ["MKAnyKeyInputController"]
+}),
+smalltalk.MKTextAreaView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "defaultLayout",
+category: 'defaults',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$3,$1;
+$2=smalltalk.MKTextAreaView.superclass.fn.prototype._defaultLayout.apply(_st(self), []);
+_st($2)._width_((160));
+_st($2)._height_((80));
+$3=_st($2)._yourself();
+$1=$3;
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"defaultLayout",{},smalltalk.MKTextAreaView)})},
+args: [],
+source: "defaultLayout\x0a\x09^ super defaultLayout\x0a\x09\x09width: 160;\x0a\x09\x09height: 80;\x0a\x09\x09yourself",
+messageSends: ["width:", "defaultLayout", "height:", "yourself"],
+referencedClasses: []
+}),
+smalltalk.MKTextAreaView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "renderContentOn:",
+category: 'rendering',
+fn: function (html){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self["@root"])._with_(self._aspectValue());
+return self}, function($ctx1) {$ctx1.fill(self,"renderContentOn:",{html:html},smalltalk.MKTextAreaView)})},
+args: ["html"],
+source: "renderContentOn: html\x0a\x09root with: self aspectValue",
+messageSends: ["with:", "aspectValue"],
+referencedClasses: []
+}),
+smalltalk.MKTextAreaView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "tag",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return "textarea";
+}, function($ctx1) {$ctx1.fill(self,"tag",{},smalltalk.MKTextAreaView)})},
+args: [],
+source: "tag\x0a\x09^ 'textarea'",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.MKTextAreaView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "update",
+category: 'updating',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=self["@root"];
+if(($receiver = $1) == nil || $receiver == null){
+$1;
+} else {
+_st(_st(self["@root"])._asJQuery())._val_(self._aspectValue());
+};
+return self}, function($ctx1) {$ctx1.fill(self,"update",{},smalltalk.MKTextAreaView)})},
+args: [],
+source: "update\x0a\x09root ifNotNil: [ root asJQuery val: self aspectValue ]",
+messageSends: ["ifNotNil:", "val:", "asJQuery", "aspectValue"],
+referencedClasses: []
+}),
+smalltalk.MKTextAreaView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "value",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(_st(self["@root"])._asJQuery())._val();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"value",{},smalltalk.MKTextAreaView)})},
+args: [],
+source: "value\x0a\x09^ root asJQuery val",
+messageSends: ["val", "asJQuery"],
+referencedClasses: []
+}),
+smalltalk.MKTextAreaView);
+
+
+
+smalltalk.addClass('MKInputView', smalltalk.MKTextAreaView, [], 'Moka-Views');
+smalltalk.MKInputView.comment="I am an input view. My default controller is `MKEnterInputController`.\x0a\x0aMy controller must answer to `#onKeyPressed:`.";
+smalltalk.addMethod(
+smalltalk.method({
+selector: "cssClass",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return "moka_view mk_input";
+}, function($ctx1) {$ctx1.fill(self,"cssClass",{},smalltalk.MKInputView)})},
+args: [],
+source: "cssClass\x0a\x09^ 'moka_view mk_input'",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.MKInputView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "defaultControllerClass",
+category: 'defaults',
+fn: function (){
+var self=this;
+function $MKEnterInputController(){return smalltalk.MKEnterInputController||(typeof MKEnterInputController=="undefined"?nil:MKEnterInputController)}
+return smalltalk.withContext(function($ctx1) { 
+return $MKEnterInputController();
+}, function($ctx1) {$ctx1.fill(self,"defaultControllerClass",{},smalltalk.MKInputView)})},
+args: [],
+source: "defaultControllerClass\x0a\x09^ MKEnterInputController",
+messageSends: [],
+referencedClasses: ["MKEnterInputController"]
+}),
+smalltalk.MKInputView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "defaultLayout",
+category: 'defaults',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$3,$1;
+$2=smalltalk.MKInputView.superclass.fn.prototype._defaultLayout.apply(_st(self), []);
+_st($2)._width_((160));
+_st($2)._height_((24));
+$3=_st($2)._yourself();
+$1=$3;
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"defaultLayout",{},smalltalk.MKInputView)})},
+args: [],
+source: "defaultLayout\x0a\x09^ super defaultLayout\x0a\x09\x09width: 160;\x0a\x09\x09height: 24;\x0a\x09\x09yourself",
+messageSends: ["width:", "defaultLayout", "height:", "yourself"],
+referencedClasses: []
+}),
+smalltalk.MKInputView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "renderContentOn:",
+category: 'rendering',
+fn: function (html){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self["@root"])._value_(self._aspectValue());
+return self}, function($ctx1) {$ctx1.fill(self,"renderContentOn:",{html:html},smalltalk.MKInputView)})},
+args: ["html"],
+source: "renderContentOn: html\x0a\x09root value: self aspectValue",
+messageSends: ["value:", "aspectValue"],
+referencedClasses: []
+}),
+smalltalk.MKInputView);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "tag",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return "input";
+}, function($ctx1) {$ctx1.fill(self,"tag",{},smalltalk.MKInputView)})},
+args: [],
+source: "tag\x0a\x09^ 'input'",
+messageSends: [],
 referencedClasses: []
 }),
 smalltalk.MKInputView);

+ 235 - 11
st/Moka-Controllers.st

@@ -1,5 +1,5 @@
 Smalltalk current createPackage: 'Moka-Controllers'!
-MKAspectController subclass: #MKAnyKeyInputController
+MKSingleAspectController subclass: #MKAnyKeyInputController
 	instanceVariableNames: 'lastValue'
 	package: 'Moka-Controllers'!
 !MKAnyKeyInputController commentStamp!
@@ -13,14 +13,18 @@ inputText
 
 !MKAnyKeyInputController methodsFor: 'actions'!
 
-onKeyPressed: anEvent
+onKeyUp: anEvent
+	self setNewValue
+!
+
+setNewValue
 	| newValue |
 	
 	newValue := self inputText.
 	newValue = lastValue ifTrue: [ ^ self ].
 	
 	lastValue := newValue.
-	self performActionWith: newValue
+	self performAspectActionWith: newValue
 ! !
 
 MKAnyKeyInputController subclass: #MKEnterInputController
@@ -32,12 +36,15 @@ Actions are performed on 'enter' key press.!
 
 !MKEnterInputController methodsFor: 'actions'!
 
-onKeyPressed: anEvent
+onKeyDown: anEvent
 	anEvent keyCode = String cr asciiValue ifTrue: [
-		super onKeyPressed: anEvent ]
+		self setNewValue ]
+!
+
+onKeyUp: anEvent
 ! !
 
-MKAspectController subclass: #MKButtonController
+MKSingleAspectController subclass: #MKButtonController
 	instanceVariableNames: ''
 	package: 'Moka-Controllers'!
 !MKButtonController commentStamp!
@@ -45,11 +52,11 @@ I am the default controller for `MKButtonView`.!
 
 !MKButtonController methodsFor: 'actions'!
 
-onPressed
-	self performAction
+onClick: anEvent
+	self performAspectAction
 ! !
 
-MKAspectController subclass: #MKCheckboxController
+MKSingleAspectController subclass: #MKCheckboxController
 	instanceVariableNames: ''
 	package: 'Moka-Controllers'!
 !MKCheckboxController commentStamp!
@@ -57,7 +64,224 @@ I am the default controller for `MKCheckboxView`.!
 
 !MKCheckboxController methodsFor: 'actions'!
 
-onToggled: aBoolean
-	self performActionWith: aBoolean
+onClick: anEvent
+	self toggle
+!
+
+onKeyDown: anEvent
+	"Avoid scrolling in scrollable views"
+	
+	anEvent stopPropagation
+!
+
+onKeyPress: anEvent
+	anEvent charCode = ' ' asciiValue ifTrue: [ 
+		self toggle.
+		anEvent stopPropagation; preventDefault ]
+!
+
+toggle
+	self performAspectActionWith: self view checked not
+! !
+
+MKAspectsController subclass: #MKDropdownController
+	instanceVariableNames: ''
+	package: 'Moka-Controllers'!
+
+!MKDropdownController methodsFor: 'actions'!
+
+onClick: anEvent
+	self view popupList
+!
+
+onKeyDown: anEvent
+	anEvent keyCode = String cr asciiValue ifTrue: [
+		self view popupList ]
+! !
+
+MKAspectsController subclass: #MKListController
+	instanceVariableNames: 'downRepeater upRepeater'
+	package: 'Moka-Controllers'!
+
+!MKListController methodsFor: 'accessing'!
+
+activeItem
+	^ self view activeItem
+!
+
+collection
+	^ self view collection
+!
+
+downRepeater
+	^ downRepeater ifNil: [ downRepeater := MKRepeater new ]
+!
+
+upRepeater
+	^ upRepeater ifNil: [ upRepeater := MKRepeater new ]
+! !
+
+!MKListController methodsFor: 'actions'!
+
+activateItem: anItem
+	"On item activation, change the model selection"
+	
+	self selectItem: anItem
+!
+
+onClick: anEvent
+	self selectItem: (self itemForTarget: anEvent target)
+!
+
+onKeyDown: anEvent
+	"Down"
+	anEvent keyCode = 40 ifTrue: [ 
+		anEvent preventDefault; stopPropagation.
+		self upRepeater stopRepeating.
+		self downRepeater repeat: [ 
+			self activateItem: self nextItem ] ].
+	"Up"
+	anEvent keyCode = 38 ifTrue: [ 
+		anEvent preventDefault; stopPropagation.
+		self downRepeater stopRepeating.
+		self upRepeater repeat: [ 
+			self activateItem: self previousItem ] ].
+!
+
+onKeyUp: anEvent
+	self downRepeater stopRepeating.
+	self upRepeater stopRepeating
+!
+
+selectItem: anItem
+	self 
+		performAspectAction: self view selectionAspect 
+		with: anItem
+! !
+
+!MKListController methodsFor: 'private'!
+
+itemForTarget: aDOMElement
+	^ self view findItemFor: aDOMElement
+!
+
+nextItem
+	^ self collection 
+		at: (self collection indexOf: self activeItem) + 1
+		ifAbsent: [ self collection last ]
+!
+
+previousItem
+	^ self view collection 
+		at: (self view collection indexOf: self activeItem) - 1
+		ifAbsent: [ self view collection first ]
+! !
+
+MKListController subclass: #MKDropdownListController
+	instanceVariableNames: ''
+	package: 'Moka-Controllers'!
+
+!MKDropdownListController methodsFor: 'actions'!
+
+activateItem: anItem
+	"Select the list item in the view.
+	No change is done to the model"
+	
+	self view activateItem: anItem
+!
+
+onKeyDown: anEvent
+	super onKeyDown: anEvent.
+	
+	anEvent keyCode = String cr asciiValue ifTrue: [
+		self selectItem: (self itemForTarget: anEvent target) ]
+!
+
+onMouseMove: anEvent
+	(self upRepeater isRepeating or: [ self downRepeater isRepeating ])
+		ifTrue: [ ^ self ].
+		
+	self activateItem: (self itemForTarget: anEvent target)
+! !
+
+MKSingleAspectController subclass: #MKModalPaneController
+	instanceVariableNames: ''
+	package: 'Moka-Controllers'!
+
+!MKModalPaneController methodsFor: 'actions'!
+
+onClick: anEvent
+	self view closeOnClick ifTrue: [ self removeView ]
+!
+
+onKeyDown: anEvent
+	"ESC"
+	anEvent keyCode = 27 ifTrue: [
+		self removeView ].
+		
+	self view closeOnEnter ifTrue: [
+		anEvent keyCode = String cr asciiValue ifTrue: [ 
+			self removeView ] ]
+!
+
+removeView
+	self view overlay remove
+! !
+
+MKSingleAspectController subclass: #MKOverlayController
+	instanceVariableNames: ''
+	package: 'Moka-Controllers'!
+!MKOverlayController commentStamp!
+I am the default controller for `MKOverlayView`.
+
+On a click to the overlay, it is removed together with it's content view.!
+
+!MKOverlayController methodsFor: 'actions'!
+
+onClick: anEvent
+	self view remove
+! !
+
+Object subclass: #MKRepeater
+	instanceVariableNames: 'repeatInterval interval delay'
+	package: 'Moka-Controllers'!
+!MKRepeater commentStamp!
+I am an internal class used by controllers to repeat block actions after a `delay` and with an `interval`.!
+
+!MKRepeater methodsFor: 'accessing'!
+
+repeatInterval
+	^ repeatInterval ifNil: [ self defaultRepeatInterval ]
+!
+
+repeatInterval: aNumber
+	repeatInterval := aNumber
+! !
+
+!MKRepeater methodsFor: 'actions'!
+
+repeat: aBlock
+	self isRepeating ifTrue: [ ^ self ].
+	aBlock value.
+	delay := [ interval := aBlock valueWithInterval: self repeatInterval ] 
+		valueWithTimeout: 300
+!
+
+stopRepeating
+	interval ifNotNil: [ interval clearInterval ].
+	delay ifNotNil: [ delay clearTimeout ].
+	interval := delay := nil
+! !
+
+!MKRepeater methodsFor: 'defaults'!
+
+defaultRepeatInterval
+	^ 70
+! !
+
+!MKRepeater methodsFor: 'testing'!
+
+isRepeating
+	^ delay notNil
 ! !
 

+ 226 - 57
st/Moka-Core.st

@@ -25,10 +25,45 @@ view: aView
 	view := aView
 ! !
 
-MKController subclass: #MKAspectController
-	instanceVariableNames: 'aspect'
+!MKController methodsFor: 'actions'!
+
+onChange: anEvent
+!
+
+onClick: anEvent
+!
+
+onDblClick: anEvent
+!
+
+onKeyDown: anEvent
+!
+
+onKeyPress: anEvent
+!
+
+onKeyUp: anEvent
+!
+
+onMouseEnter: anEvent
+!
+
+onMouseLeave: anEvent
+!
+
+onMouseMove: anEvent
+!
+
+onMouseOut: anEvent
+!
+
+onMouseOver: anEvent
+! !
+
+MKController subclass: #MKAspectsController
+	instanceVariableNames: ''
 	package: 'Moka-Core'!
-!MKAspectController commentStamp!
+!MKAspectsController commentStamp!
 I am an abstract controller for performing one action using an `aspect` on a model.
 
 ## API
@@ -36,30 +71,36 @@ I am an abstract controller for performing one action using an `aspect` on a mod
 - Use `#aspect:` to plug a selector to be performed on the model
 - Subclasses can either use `#performActionWith:` or `#performAction` to evaluate the `aspect` selector on the model with one or no argument.!
 
-!MKAspectController methodsFor: 'accessing'!
+!MKAspectsController methodsFor: 'actions'!
 
-aspect
-	^ aspect
+performAspectAction: aSelector
+	self model perform: aSelector
 !
 
-aspect: aSelector
-	aspect := aSelector
+performAspectAction: aSelector with: anObject
+	self model 
+		perform: aSelector asMutator
+		withArguments: { anObject }
 ! !
 
-!MKAspectController methodsFor: 'actions'!
+MKAspectsController subclass: #MKSingleAspectController
+	instanceVariableNames: ''
+	package: 'Moka-Core'!
+!MKSingleAspectController commentStamp!
+I am an abstract controller used with single aspect views.
+
+My view must hold onto one aspect accessed with `#aspect`.!
 
-performAction
-	self aspect ifNotNil: [
-		self model 
-			perform: self aspect ]
+!MKSingleAspectController methodsFor: 'actions'!
+
+performAspectAction
+	^ self performAspectAction: self view aspect
 !
 
-performActionWith: anObject
-	self aspect ifNil: [ ^ self ].
-	
-	self model 
-		perform: self aspect asMutator
-		withArguments: { anObject }
+performAspectActionWith: anObject
+	^ self 
+		performAspectAction: self view aspect
+		with: anObject
 ! !
 
 Object subclass: #MKModel
@@ -133,7 +174,7 @@ aspect: aSelector
 ! !
 
 Widget subclass: #MKView
-	instanceVariableNames: 'controller model wrapper'
+	instanceVariableNames: 'controller model root layout extraCssClass'
 	package: 'Moka-Core'!
 !MKView commentStamp!
 I implement the View part of the MVC pattern in Moka.
@@ -143,7 +184,8 @@ I implement the View part of the MVC pattern in Moka.
 - rendering is done through `#renderContentOn:`, to be overridden in concrete view classes
 - `#update` provide updating facility, refreshing the entire view
 - subclasses can override `#defaultControllerClass` to provide a default controller specific to a view
-- subclasses can override `#observeModel`.!
+- subclasses can override `#observeModel`
+- Extra css classes can be added with `#extraCssClass:`.!
 
 !MKView methodsFor: 'accessing'!
 
@@ -166,6 +208,25 @@ controller: aController
 		model: self model
 !
 
+cssClass
+	^ String streamContents: [ :stream |
+		stream << 'moka_view'.
+		self extraCssClass ifNotEmpty: [
+			stream << ' ' << self extraCssClass ] ]
+!
+
+extraCssClass
+	^ extraCssClass ifNil: [ '' ]
+!
+
+extraCssClass: aString
+	extraCssClass := aString
+!
+
+layout
+	^ layout ifNil: [ layout := self defaultLayout ]
+!
+
 model
 	^ model
 !
@@ -173,12 +234,49 @@ model
 model: aModel
 	model := aModel.
 	self observeModel
+!
+
+position
+	"Answer the position of the reciever in the page"
+	
+	^ root ifNotNil: [ 
+		|  offset |
+		offset := root asJQuery offset.
+		offset left @ offset top ]
+!
+
+tag
+	^ 'div'
+! !
+
+!MKView methodsFor: 'actions'!
+
+blur
+	root ifNotNil: [ root asJQuery blur ]
+!
+
+focus
+	root ifNotNil: [ root asJQuery focus ]
+!
+
+remove
+	"Removes the receiver from the DOM"
+	root ifNotNil: [ root asJQuery remove ]
 ! !
 
 !MKView methodsFor: 'defaults'!
 
 defaultControllerClass
 	^ MKController
+!
+
+defaultLayout
+	^ MKLayout new
+		left: 0;
+		top: 0;
+		right: 0;
+		bottom: 0;
+		yourself
 ! !
 
 !MKView methodsFor: 'factory'!
@@ -187,12 +285,63 @@ defaultController
 	^ self defaultControllerClass new
 ! !
 
+!MKView methodsFor: 'layout'!
+
+bottom: aNumber
+	self layout bottom: aNumber
+!
+
+centerX: aNumber
+	self layout centerX: aNumber
+!
+
+centerY: aNumber
+	self layout centerY: aNumber
+!
+
+height: aNumber
+	self layout height: aNumber
+!
+
+left: aNumber
+	self layout left: aNumber
+!
+
+right: aNumber
+	self layout right: aNumber
+!
+
+top: aNumber
+	self layout top: aNumber
+!
+
+width: aNumber
+	self layout width: aNumber
+! !
+
 !MKView methodsFor: 'observing'!
 
 observeModel
 	"No op. Override in subclasses"
 ! !
 
+!MKView methodsFor: 'private'!
+
+setupEventHandlers
+	root
+		onClick: [ :event | self controller onClick: event ];
+		onDblClick: [ :event | self controller onDblClick: event ];
+		onMouseEnter: [ :event | self controller onMouseEnter: event ];
+		onMouseLeave: [ :event | self controller onMouseLeave: event ];
+		onMouseOver: [ :event | self controller onMouseOver: event ];
+		onMouseOut: [ :event | self controller onMouseOut: event ];
+		onMouseMove: [ :event | self controller onMouseMove: event ];
+		onKeyDown: [ :event | self controller onKeyDown: event ];
+		onKeyUp: [ :event | self controller onKeyUp: event ];
+		onKeyPress: [ :event | self controller onKeyPress: event ];
+		onChange: [ :event | self controller onChange: event ]
+! !
+
 !MKView methodsFor: 'rendering'!
 
 render
@@ -207,26 +356,27 @@ renderContentOn: html
 
 renderOn: html
 	"Basic rendering method.
-	Wraps the content with a `wrapper` div for updating the receiver.
-	
 	Do not override this method, but `#renderContentOn:`"
 	
-	wrapper := html div
-		class: 'moka_view';
+	root := (html tag: self tag)
+		class: self cssClass;
+		style: self layout asCssString;
 		yourself.
-	wrapper with: [ self renderContentOn: html ]
+	root with: [ self renderContentOn: html ].
+	
+	self setupEventHandlers
 ! !
 
 !MKView methodsFor: 'updating'!
 
 update
-	"Update the view's content."
+	"Update the view's content. Override in subclasses to fine-tune updating"
 	
-	wrapper ifNil: [ self error: 'The view has not been rendered yet' ].
+	root ifNil: [ self error: 'The view has not been rendered yet' ].
 	
-	wrapper asJQuery empty.
+	root asJQuery empty.
 	[ :html | self renderContentOn: html ] 
-		appendToJQuery: wrapper asJQuery
+		appendToJQuery: root asJQuery
 ! !
 
 !MKView class methodsFor: 'instance creation'!
@@ -243,17 +393,52 @@ model: aModel controller: aController
 		yourself
 ! !
 
-MKView subclass: #MKAspectView
-	instanceVariableNames: 'aspect label'
+MKView subclass: #MKAspectsView
+	instanceVariableNames: ''
 	package: 'Moka-Core'!
-!MKAspectView commentStamp!
+!MKAspectsView commentStamp!
+I am an abstract view which state depend on aspects of a model.!
+
+!MKAspectsView methodsFor: 'accessing'!
+
+valueForAspect: aSelector
+	^ self model perform: aSelector
+! !
+
+!MKAspectsView methodsFor: 'defaults'!
+
+defaultControllerClass
+	^ MKAspectController
+! !
+
+!MKAspectsView methodsFor: 'observing'!
+
+observeModel
+	super observeModel.
+	
+	self model
+		on: MKModelChanged
+		send: 'update:'
+		to: self
+! !
+
+!MKAspectsView methodsFor: 'updating'!
+
+update: anAnnouncement
+	"Override in subclasses to match the view's aspect(s)"
+! !
+
+MKAspectsView subclass: #MKSingleAspectView
+	instanceVariableNames: 'aspect'
+	package: 'Moka-Core'!
+!MKSingleAspectView commentStamp!
 I am an abstract view which state depend on an `aspect` of a model. 
 
 ##API
 
 - Use the `#aspect:` to listen to a specific aspect of a model. Changes will then trigger `#update`.!
 
-!MKAspectView methodsFor: 'accessing'!
+!MKSingleAspectView methodsFor: 'accessing'!
 
 aspect
 	^ aspect
@@ -264,39 +449,23 @@ aspect: aSelector
 !
 
 aspectValue
-	^ self model perform: self aspect
-!
-
-controller: aController
-	super controller: aController.
-	aController aspect: self aspect
+	^ self valueForAspect: self aspect
 ! !
 
-!MKAspectView methodsFor: 'defaults'!
+!MKSingleAspectView methodsFor: 'defaults'!
 
 defaultControllerClass
-	^ MKAspectController
-! !
-
-!MKAspectView methodsFor: 'observing'!
-
-observeModel
-	super observeModel.
-	
-	self model
-		on: MKModelChanged
-		send: 'update:'
-		to: self
+	^ MKSingleAspectController
 ! !
 
-!MKAspectView methodsFor: 'updating'!
+!MKSingleAspectView methodsFor: 'updating'!
 
 update: anAnnouncement
-	anAnnouncement aspect = self aspect
-		ifTrue: [ self update ]
+	anAnnouncement aspect = self aspect ifTrue: [
+		self update ]
 ! !
 
-!MKAspectView class methodsFor: 'instance creation'!
+!MKSingleAspectView class methodsFor: 'instance creation'!
 
 model: aModel aspect: aSelector
 	^ (self model: aModel)

+ 148 - 16
st/Moka-Examples.st

@@ -1,4 +1,61 @@
 Smalltalk current createPackage: 'Moka-Examples'!
+MKModel subclass: #MKClassesListBuilder
+	instanceVariableNames: ''
+	package: 'Moka-Examples'!
+
+!MKClassesListBuilder methodsFor: 'as yet unclassified'!
+
+build
+	MKPaneView new
+		height: 150;
+		addView: (
+			(MKListView 	
+				model: MKClassesModel new
+				collectionAspect: #classes
+				selectionAspect: #selectedClass)
+					left: 4;
+					top: 4;
+					bottom: 4;
+					right: 0.5;
+					yourself);
+		addView: (MKPanelView new
+			left: 0.5;
+			top: 4;
+			right: 4;
+			bottom: 4;
+			addView: (MKSourceListView 	
+				model: MKClassesModel new
+				collectionAspect: #classes
+				selectionAspect: #selectedClass);
+			yourself);
+		render
+! !
+
+!MKClassesListBuilder class methodsFor: 'as yet unclassified'!
+
+initialize
+	self new build
+! !
+
+MKModel subclass: #MKClassesModel
+	instanceVariableNames: 'classes selectedClass'
+	package: 'Moka-Examples'!
+
+!MKClassesModel methodsFor: 'as yet unclassified'!
+
+classes
+	^ Smalltalk current classes
+!
+
+selectedClass
+	^ selectedClass ifNil: [ self classes first ]
+!
+
+selectedClass: aClass
+	selectedClass := aClass.
+	self changed: #selectedClass
+! !
+
 Object subclass: #MKCounterBuilder
 	instanceVariableNames: 'counter'
 	package: 'Moka-Examples'!
@@ -6,24 +63,84 @@ Object subclass: #MKCounterBuilder
 !MKCounterBuilder methodsFor: 'accessing'!
 
 build
-	(MKLabelView model: self counter aspect: #count) render.
-	(MKButtonView model: self counter aspect: #increase) 
+	| pane |
+	pane := MKPanelView new
+		top: 200;
+		width: 400;
+		borderRight: 1;
+		bottom: 0;
+		yourself.
+	
+	pane addView: ((MKHeadingView model: self counter aspect: #count)
+		level: 3;
+		top: 0;
+		left: 8;
+		height: 28;
+		yourself).
+	pane addView: ((MKButtonView model: self counter aspect: #increase) 
 		label: 'Increase';
-		render.
-	(MKInputView model: self counter aspect: #text)
-		render.
-	(MKInputView model: self counter aspect: #text)
+		top: 50;
+		left: 8;
+		yourself).
+	pane addView: ((MKButtonView model: self counter aspect: #decrease) 
+		label: 'Decrease';
+		default: true;
+		top: 50;
+		left: 92;
+		yourself).
+	pane addView: ((MKInputView model: self counter aspect: #text)
+		top: 100;
+		left: 8;
+		yourself).
+	pane addView: ((MKInputView model: self counter aspect: #text)
+		top: 150;
+		left: 8;
 		triggerChangeOnAnyKey;
-		render.
-	(MKTextAreaView model: self counter aspect: #text)
-		render.
-	(MKCheckboxView model: self counter aspect: #checked)
-		render.
-	(MKSwitchView model: self counter aspect: #checked)
-		render.
-	(MKButtonView model: self counter aspect: #decrease) 
+		yourself).
+	pane addView: ((MKTextAreaView model: self counter aspect: #text)
+		top: 200;
+		left: 8;
+		yourself).
+	pane addView: ((MKCheckboxView model: self counter aspect: #checked)
+		top: 300;
+		left: 8;
+		yourself).
+	pane addView: ((MKSwitchView model: self counter aspect: #checked)
+		top: 350;
+		centerX: 0;
+		yourself).
+	pane addView: ((MKSwitchView model: self counter aspect: #checked)
+		top: 380;
+		centerX: -50;
+		yourself).
+	pane addView: ((MKSwitchView model: self counter aspect: #checked)
+		top: 410;
+		centerX: 50;
+		yourself).
+	pane addView: ((MKSwitchView model: self counter aspect: #checked)
+		right: 4;
+		centerY: 0;
+		yourself).
+	pane addView: ((MKSwitchView model: self counter aspect: #checked)
+		right: 4;
+		centerY: 30;
+		yourself).
+	pane addView: ((MKSwitchView model: self counter aspect: #checked)
+		right: 4;
+		centerY: -30;
+		yourself).
+	pane addView: ((MKDropdownView 
+			model: self counter
+			collectionAspect: #options
+			selectionAspect: #selectedOption)
+		left: 4;
+		top: 440;
+		yourself).
+		
+	pane render
+	"(MKButtonView model: self counter aspect: #decrease) 
 		label: 'Decrease';
-		render
+		render"
 !
 
 counter
@@ -37,9 +154,24 @@ initialize
 ! !
 
 MKModel subclass: #MKCounterModel
-	instanceVariableNames: 'count text checked'
+	instanceVariableNames: 'count text checked options selectedOption'
 	package: 'Moka-Examples'!
 
+!MKCounterModel methodsFor: 'accessing'!
+
+options
+	^ Smalltalk current classes collect: [ :each | each name ]
+!
+
+selectedOption
+	^ selectedOption ifNil: [ selectedOption := self options last ]
+!
+
+selectedOption: aString
+	selectedOption := aString.
+	self changed: #selectedOption
+! !
+
 !MKCounterModel methodsFor: 'actions'!
 
 checked

+ 309 - 0
st/Moka-Layouts.st

@@ -0,0 +1,309 @@
+Smalltalk current createPackage: 'Moka-Layouts'!
+Object subclass: #MKLayout
+	instanceVariableNames: 'properties'
+	package: 'Moka-Layouts'!
+
+!MKLayout methodsFor: 'accessing'!
+
+bottom: aNumber
+	properties 
+		at: 'bottom' 
+		put: (self propertyLabelled: 'bottom' value: aNumber).
+	
+	(self hasProperty: 'top') ifTrue: [
+		self removeProperty: 'height' ].
+	self removeProperty: 'centerY'
+!
+
+centerX: aNumber
+	properties
+		at: 'centerX'
+		put: (MKHorizontalCenteringLayoutProperty layout: self value: aNumber).
+	
+	self 
+		removeProperty: 'left';
+		removeProperty: 'right'
+!
+
+centerY: aNumber
+	properties
+		at: 'centerY'
+		put: (MKVerticalCenteringLayoutProperty layout: self value: aNumber).
+		
+	self 
+		removeProperty: 'top';
+		removeProperty: 'bottom'
+!
+
+height
+	^ properties 
+		at: 'height' 
+		ifPresent: [ :property | property value ]
+		ifAbsent: [ 1 ]
+!
+
+height: aNumber
+	properties 
+		at: 'height' 
+		put: (self propertyLabelled: 'height' value: aNumber).
+	
+	(self hasProperty: 'top') ifTrue: [
+		self removeProperty: 'bottom' ]
+!
+
+left: aNumber
+	properties 
+		at: 'left' 
+		put: (self propertyLabelled: 'left' value: aNumber).
+	
+	(self hasProperty: 'width') ifTrue: [
+		self removeProperty: 'right' ].
+	self removeProperty: 'centerX'
+!
+
+right: aNumber
+	properties 
+		at: 'right' 
+		put: (self propertyLabelled: 'right' value: aNumber).
+	
+	(self hasProperty: 'width') ifTrue: [
+		self removeProperty: 'left' ].
+	self removeProperty: 'centerX'
+!
+
+top: aNumber
+	properties 
+		at: 'top' 
+		put: (self propertyLabelled: 'top' value: aNumber).
+	
+	(self hasProperty: 'height') ifTrue: [
+		self removeProperty: 'bottom' ].
+	self removeProperty: 'centerY'
+!
+
+width
+	^ properties 
+		at: 'width' 
+		ifPresent: [ :property | property value ]
+		ifAbsent: [ 1 ]
+!
+
+width: aNumber
+	properties 
+		at: 'width' 
+		put: (self propertyLabelled: 'width' value: aNumber).
+	
+	(self hasProperty: 'left') ifTrue: [
+		self removeProperty: 'right' ]
+! !
+
+!MKLayout methodsFor: 'converting'!
+
+asCssString
+	^ String streamContents: [ :stream |
+		properties valuesDo: [ :each | 
+			each printCssOn: stream.
+			stream << ';' ] ]
+! !
+
+!MKLayout methodsFor: 'factory'!
+
+propertyLabelled: aString value: aValue
+	^ MKLabelledLayoutProperty layout: self label: aString value: aValue
+! !
+
+!MKLayout methodsFor: 'initialization'!
+
+initialize
+	super initialize.
+	properties := Dictionary new
+! !
+
+!MKLayout methodsFor: 'private'!
+
+hasProperty: aString
+	^ properties includesKey: aString
+!
+
+removeProperty: aString
+	properties remove: aString ifAbsent: []
+! !
+
+MKLayout subclass: #MKLabelLayout
+	instanceVariableNames: ''
+	package: 'Moka-Layouts'!
+!MKLabelLayout commentStamp!
+I am a specialized layout for label views. I can set a `textAlign` property, taking a string argument, `'left'`, `'center'` or `'right'`.!
+
+!MKLabelLayout methodsFor: 'accessing'!
+
+textAlign: aString
+	"Map to CSS' text-align property. Possible values are `'left'`, `'center'` and `'right'`"
+	
+	properties 
+		at: 'text-align' 
+		put: (self propertyLabelled: 'text-align' value: aString)
+! !
+
+MKLayout subclass: #MKPaneLayout
+	instanceVariableNames: ''
+	package: 'Moka-Layouts'!
+!MKPaneLayout commentStamp!
+I am a specialized layout for pane views. I can set border widths to my views.!
+
+!MKPaneLayout methodsFor: 'accessing'!
+
+borderBottom: aNumber
+	properties 
+		at: 'border-bottom' 
+		put: (self propertyLabelled: 'border-bottom-width' value: aNumber asMokaPixelString)
+!
+
+borderLeft: aNumber
+	properties 
+		at: 'border-left' 
+		put: (self propertyLabelled: 'border-left-width' value: aNumber asMokaPixelString)
+!
+
+borderRight: aNumber
+	properties 
+		at: 'border-right' 
+		put: (self propertyLabelled: 'border-right-width' value: aNumber asMokaPixelString)
+!
+
+borderTop: aNumber
+	properties 
+		at: 'border-top' 
+		put: (self propertyLabelled: 'border-top-width' value: aNumber asMokaPixelString)
+! !
+
+Object subclass: #MKLayoutProperty
+	instanceVariableNames: 'layout value'
+	package: 'Moka-Layouts'!
+
+!MKLayoutProperty methodsFor: 'accessing'!
+
+layout
+	^ layout
+!
+
+layout: aLayout
+	layout := aLayout
+!
+
+value
+	^ value
+!
+
+value: aValue
+	value := aValue
+! !
+
+!MKLayoutProperty methodsFor: 'converting'!
+
+asCssString
+	^ String streamContents: [ :stream | 
+		self printCssOn: stream ]
+! !
+
+!MKLayoutProperty methodsFor: 'printing'!
+
+printCssOn: aStream
+	self subclassResponsibility
+! !
+
+!MKLayoutProperty class methodsFor: 'instance creation'!
+
+layout: aLayout value: aValue
+	^ self new
+		layout: aLayout;
+		value: aValue;
+		yourself
+! !
+
+MKLayoutProperty subclass: #MKHorizontalCenteringLayoutProperty
+	instanceVariableNames: ''
+	package: 'Moka-Layouts'!
+
+!MKHorizontalCenteringLayoutProperty methodsFor: 'accessing'!
+
+marginLeft
+	^ 0 - ((self layout width / 2) + self value)
+! !
+
+!MKHorizontalCenteringLayoutProperty methodsFor: 'printing'!
+
+printCssOn: aStream
+	aStream << 'left:50%;'.
+	aStream << 'margin-left:' << self marginLeft asMokaCssString
+! !
+
+MKLayoutProperty subclass: #MKLabelledLayoutProperty
+	instanceVariableNames: 'label'
+	package: 'Moka-Layouts'!
+
+!MKLabelledLayoutProperty methodsFor: 'accessing'!
+
+label
+	^ label
+!
+
+label: aString
+	label := aString
+! !
+
+!MKLabelledLayoutProperty methodsFor: 'printing'!
+
+printCssOn: aStream
+	aStream << self label << ':' << self value asMokaCssString
+! !
+
+!MKLabelledLayoutProperty class methodsFor: 'instance creation'!
+
+layout: aLayout label: aString value: aValue
+	^ self new
+		layout: aLayout;
+		label: aString;
+		value: aValue;
+		yourself
+! !
+
+MKLayoutProperty subclass: #MKVerticalCenteringLayoutProperty
+	instanceVariableNames: ''
+	package: 'Moka-Layouts'!
+
+!MKVerticalCenteringLayoutProperty methodsFor: 'accessing'!
+
+marginTop
+	^ 0 - ((self layout height / 2) + self value)
+! !
+
+!MKVerticalCenteringLayoutProperty methodsFor: 'printing'!
+
+printCssOn: aStream
+	aStream << 'top:50%;'.
+	aStream << 'margin-top:' << self marginTop asMokaCssString
+! !
+
+!Number methodsFor: '*Moka-Layouts'!
+
+asMokaCssString
+	^ self abs > 1 	
+		ifTrue: [ self asMokaPixelString ]
+		ifFalse: [ self asMokaPercentString ]
+!
+
+asMokaPercentString
+	^ (self * 100) asString, '%'
+!
+
+asMokaPixelString
+	^ self asString, 'px'
+! !
+
+!String methodsFor: '*Moka-Layouts'!
+
+asMokaCssString
+	^ self
+! !
+

+ 639 - 59
st/Moka-Views.st

@@ -1,5 +1,5 @@
 Smalltalk current createPackage: 'Moka-Views'!
-MKAspectView subclass: #MKButtonView
+MKSingleAspectView subclass: #MKButtonView
 	instanceVariableNames: 'default label'
 	package: 'Moka-Views'!
 !MKButtonView commentStamp!
@@ -15,9 +15,10 @@ My controller must answer to `#onPressed`.
 !MKButtonView methodsFor: 'accessing'!
 
 cssClass
-	^ self isDefault 
-		ifTrue: [ 'default' ]
-		ifFalse: [ '' ]
+	^ String streamContents: [ :stream |
+		stream << super cssClass << ' mk_button'.
+		self isDefault 
+			ifTrue: [ stream << ' default' ] ]
 !
 
 default
@@ -34,6 +35,10 @@ label
 
 label: aString
 	label := aString
+!
+
+tag
+	^ 'button'
 ! !
 
 !MKButtonView methodsFor: 'defaults'!
@@ -44,21 +49,19 @@ defaultControllerClass
 
 defaultLabel
 	^ 'OK'
-! !
-
-!MKButtonView methodsFor: 'events'!
+!
 
-pressed
-	self controller onPressed
+defaultLayout
+	^ super defaultLayout
+		width: 80;
+		height: 24;
+		yourself
 ! !
 
 !MKButtonView methodsFor: 'rendering'!
 
 renderContentOn: html
-	html button
-		class: self cssClass;
-		with: self label;
-		onClick: [ self pressed ]
+	html with: self label
 ! !
 
 !MKButtonView methodsFor: 'testing'!
@@ -67,7 +70,7 @@ isDefault
 	^ self default ifNil: [ false ]
 ! !
 
-MKAspectView subclass: #MKCheckboxView
+MKSingleAspectView subclass: #MKCheckboxView
 	instanceVariableNames: 'id'
 	package: 'Moka-Views'!
 !MKCheckboxView commentStamp!
@@ -87,7 +90,7 @@ checked
 !
 
 cssClass
-	^ 'mk_checkbox'
+	^ super cssClass, ' mk_checkbox'
 !
 
 id
@@ -98,40 +101,30 @@ id
 
 defaultControllerClass
 	^ MKCheckboxController
+!
+
+defaultLayout
+	^ super defaultLayout
+		width: 16;
+		height: 16;
+		yourself
 ! !
 
 !MKCheckboxView methodsFor: 'events'!
 
-pressed
-	self controller onToggled: self checked not
-!
-
 update
-	| checkbox |
-	checkbox := ('#', self id) asJQuery.
-	
 	self checked
-		ifTrue: [ checkbox attr: 'checked' put: 'checked' ]
-		ifFalse: [ checkbox removeAttr: 'checked' ]
+		ifTrue: [ root asJQuery addClass: 'checked' ]
+		ifFalse: [ root asJQuery removeClass: 'checked' ]
 ! !
 
 !MKCheckboxView methodsFor: 'rendering'!
 
-renderContentOn: html
-	| checkbox |
-	
-	checkbox := html input
-		type: 'checkbox';
-		class: self cssClass;
-		id: self id;
-		onClick: [ self pressed ].
-		
+renderContentOn: html	
 	self checked ifTrue: [ 
-		checkbox at: 'checked' put: 'checked' ].
-		
-	html label
-		for: self id;
-		with: [ html entity: 'nbsp' ]
+		root asJQuery addClass: 'checked' ].
+	
+	root at: 'tabindex' put: '0'
 ! !
 
 MKCheckboxView subclass: #MKSwitchView
@@ -143,30 +136,597 @@ My default controller is `MKCheckboxController`.!
 
 !MKSwitchView methodsFor: 'accessing'!
 
-cssClass
+checkboxCssClass
 	^ 'mk_switch'
+!
+
+cssClass
+	^ super cssClass, ' mk_switch'
+! !
+
+!MKSwitchView methodsFor: 'defaults'!
+
+defaultLayout
+	^ super defaultLayout
+		width: 48;
+		height: 20;
+		yourself
+! !
+
+MKView subclass: #MKContainerView
+	instanceVariableNames: 'childView'
+	package: 'Moka-Views'!
+!MKContainerView commentStamp!
+I display my single `childView`. 
+
+I am used to switch between views.!
+
+!MKContainerView methodsFor: 'accessing'!
+
+childView
+	^ childView
+!
+
+childView: aView
+	childView := aView.
+	self update
+! !
+
+!MKContainerView methodsFor: 'rendering'!
+
+renderContentOn: html
+	html with: self childView
+! !
+
+!MKContainerView class methodsFor: 'instance creation'!
+
+childView: aView
+	^ self new 
+		childView: aView;
+		yourself
 ! !
 
-MKAspectView subclass: #MKLabelView
-	instanceVariableNames: 'input'
+MKSingleAspectView subclass: #MKLabelView
+	instanceVariableNames: ''
 	package: 'Moka-Views'!
 !MKLabelView commentStamp!
 I am an label view. I display a `String`.!
 
+!MKLabelView methodsFor: 'accessing'!
+
+cssClass
+	^ super cssClass, ' mk_label'
+! !
+
 !MKLabelView methodsFor: 'defaults'!
 
 defaultControllerClass
 	^ super defaultControllerClass
+!
+
+defaultLayout
+	^ MKLabelLayout new
+		height: 24;
+		top: 0;
+		left:0;
+		right: 0;
+		textAlign: 'left';
+		yourself
+! !
+
+!MKLabelView methodsFor: 'layout'!
+
+textAlign: aString
+	self layout textAlign: aString
 ! !
 
 !MKLabelView methodsFor: 'rendering'!
 
 renderContentOn: html
-	html span with: self aspectValue
+	html with: self aspectValue
 ! !
 
-MKAspectView subclass: #MKTextAreaView
-	instanceVariableNames: 'input'
+MKLabelView subclass: #MKHeadingView
+	instanceVariableNames: 'level'
+	package: 'Moka-Views'!
+!MKHeadingView commentStamp!
+I display a heading, with a `level` from 1 to 6.!
+
+!MKHeadingView methodsFor: 'accessing'!
+
+cssClass
+	^ String streamContents: [ :stream |
+		stream 
+			<< super cssClass 	
+			<< ' mk_heading level'
+			<< self level asString ]
+!
+
+level
+	^ level ifNil: [ 1 ]
+!
+
+level: aNumber
+	level := aNumber
+!
+
+tag
+	^ 'h', self level asString
+! !
+
+MKView subclass: #MKOverlayView
+	instanceVariableNames: 'childView'
+	package: 'Moka-Views'!
+
+!MKOverlayView methodsFor: 'accessing'!
+
+childView
+	^ childView
+!
+
+childView: aView
+	childView := aView
+!
+
+cssClass
+	^ super cssClass, ' mk_overlay'
+! !
+
+!MKOverlayView methodsFor: 'actions'!
+
+remove
+	super remove.
+	self childView remove
+! !
+
+!MKOverlayView methodsFor: 'defaults'!
+
+defaultControllerClass
+	^ MKOverlayController
+!
+
+renderContentOn: html
+	"Left empty on purpose. 
+	No Content is rendered, as the childView is actually displayed separately"
+! !
+
+!MKOverlayView class methodsFor: 'instance creation'!
+
+childView: aView
+	^ self new
+		childView: aView;
+		yourself
+! !
+
+MKView subclass: #MKPaneView
+	instanceVariableNames: 'views'
+	package: 'Moka-Views'!
+!MKPaneView commentStamp!
+I am a view containing other views.
+
+## API
+
+Use `#addView:` to add a view to the pane.!
+
+!MKPaneView methodsFor: 'accessing'!
+
+cssClass
+	^ super cssClass, ' mk_pane'
+!
+
+views
+	^ views ifNil: [ views := OrderedCollection new ]
+! !
+
+!MKPaneView methodsFor: 'adding'!
+
+addView: aView
+	self views add: aView
+! !
+
+!MKPaneView methodsFor: 'defaults'!
+
+defaultLayout
+	^ MKPaneLayout new
+		left: 0;
+		top: 0;
+		right: 0;
+		bottom: 0;
+		yourself
+! !
+
+!MKPaneView methodsFor: 'layout'!
+
+borderBottom: aNumber
+	self layout borderBottom: aNumber
+!
+
+borderLeft: aNumber
+	self layout borderLeft: aNumber
+!
+
+borderRight: aNumber
+	self layout borderRight: aNumber
+!
+
+borderTop: aNumber
+	self layout borderTop: aNumber
+! !
+
+!MKPaneView methodsFor: 'rendering'!
+
+renderContentOn: html
+	self views do: [ :each | 
+		html with: each ]
+! !
+
+MKPaneView subclass: #MKModalPaneView
+	instanceVariableNames: 'overlay closeOnEnter closeOnClick'
+	package: 'Moka-Views'!
+
+!MKModalPaneView methodsFor: 'accessing'!
+
+closeOnClick
+	^ closeOnClick ifNil: [ false ]
+!
+
+closeOnClick: aBoolean
+	closeOnClick := aBoolean
+!
+
+closeOnEnter
+	^ closeOnEnter ifNil: [ false ]
+!
+
+closeOnEnter: aBoolean
+	closeOnEnter := aBoolean
+!
+
+cssClass
+	^ super cssClass, ' mk_modal'
+!
+
+overlay
+	^ overlay ifNil: [ overlay := MKOverlayView childView: self ]
+!
+
+zindex
+	^ 1001
+! !
+
+!MKModalPaneView methodsFor: 'defaults'!
+
+defaultControllerClass
+	^ MKModalPaneController
+!
+
+defaultLayout
+	^ super defaultLayout
+		centerY: 0;
+		centerX: 0;
+		width: 300;
+		height: 200;
+		yourself
+! !
+
+!MKModalPaneView methodsFor: 'rendering'!
+
+renderOn: html
+	super renderOn: html.
+	root at: 'tabindex' put: '0'.
+	root asJQuery focus.
+	html with: self overlay
+! !
+
+MKPaneView subclass: #MKPanelView
+	instanceVariableNames: ''
+	package: 'Moka-Views'!
+!MKPanelView commentStamp!
+I am similar to a `MKPaneView` but I am scrollable and display a light background.!
+
+!MKPanelView methodsFor: 'accessing'!
+
+cssClass
+	^ super cssClass, ' mk_panel'
+! !
+
+MKAspectsView subclass: #MKSelectionView
+	instanceVariableNames: 'selectionAspect collectionAspect'
+	package: 'Moka-Views'!
+!MKSelectionView commentStamp!
+I an abstract selection view of a list of elements.!
+
+!MKSelectionView methodsFor: 'accessing'!
+
+collection
+	^ self valueForAspect: self collectionAspect
+!
+
+collectionAspect
+	^ collectionAspect
+!
+
+collectionAspect: aSelector
+	collectionAspect := aSelector
+!
+
+selectedItem
+	^ self valueForAspect: self selectionAspect
+!
+
+selectionAspect
+	^ selectionAspect
+!
+
+selectionAspect: aSelector
+	selectionAspect := aSelector
+! !
+
+!MKSelectionView methodsFor: 'defaults'!
+
+defaultDisplayBlock
+	^ [ :item | item asString ]
+! !
+
+!MKSelectionView class methodsFor: 'instance creation'!
+
+model: aModel collectionAspect: collectionSelector selectionAspect: selectionSelector
+	^ (self model: aModel)
+		collectionAspect: collectionSelector;
+		selectionAspect: selectionSelector;
+		yourself
+! !
+
+MKSelectionView subclass: #MKDropdownView
+	instanceVariableNames: 'modalPaneView listView'
+	package: 'Moka-Views'!
+!MKDropdownView commentStamp!
+I am a push button view. My default controller is `MKButtonController`.
+
+My controller must answer to `#onPressed`.
+
+## API
+
+- Instances can be set a `default` button
+- Use `#label:` to set the label string!
+
+!MKDropdownView methodsFor: 'accessing'!
+
+cssClass
+	^ super cssClass, ' mk_dropdown'
+!
+
+selectedListItem
+	^ (root asJQuery find: ':selected') text
+!
+
+tag
+	^ 'button'
+!
+
+update: anAnnouncement
+	({self selectionAspect. self collectionAspect} 
+		includes: anAnnouncement aspect) ifTrue: [
+			self update ]
+! !
+
+!MKDropdownView methodsFor: 'actions'!
+
+popupList
+	"Show a new list view inside a modal pane"
+	self modalPaneView render.
+	self listView focus
+! !
+
+!MKDropdownView methodsFor: 'defaults'!
+
+defaultControllerClass
+	^ MKDropdownController
+!
+
+defaultLayout
+	^ super defaultLayout
+		width: 120;
+		height: 24;
+		yourself
+! !
+
+!MKDropdownView methodsFor: 'rendering'!
+
+renderContentOn: html
+	html div class: 'mk_dropdown_arrows'.
+	html with: self selectedItem
+! !
+
+!MKDropdownView methodsFor: 'views'!
+
+listView
+	^ listView ifNil: [
+		listView := (MKDropdownListView 	
+			model: self model
+			collectionAspect: self collectionAspect
+			selectionAspect: self selectionAspect)
+				width: 'auto';
+				height: 'auto';
+				yourself ]
+!
+
+modalPaneView
+	^ modalPaneView ifNil: [
+		modalPaneView := MKModalPaneView new
+			extraCssClass: 'mk_dropdown_pane';
+			closeOnEnter: true;
+			closeOnClick: true;
+			addView: self listView;
+			left: self position x;
+			top: self position y;
+			"Max height of the list"
+			height: 400;
+			yourself ]
+! !
+
+MKSelectionView subclass: #MKListView
+	instanceVariableNames: 'displayBlock'
+	package: 'Moka-Views'!
+!MKListView commentStamp!
+I display a list of elements in a list control field.!
+
+!MKListView methodsFor: 'accessing'!
+
+activeItem
+	^ self findItemFor: (root asJQuery find: '.', self selectedCssClass)
+!
+
+cssClass
+	^ super cssClass, ' mk_list'
+!
+
+displayBlock
+	^ displayBlock ifNil: [ self defaultDisplayBlock ]
+!
+
+displayBlock: aBlock
+	displayBlock := aBlock
+!
+
+findItemFor: aListItem
+	^ aListItem asJQuery data at: 'item'
+!
+
+findListItemFor: anObject
+	^ (((root asJQuery find: 'li') 
+		filter: [ :thisArg | (thisArg asJQuery data: 'item') = anObject ] currySelf) eq: 0)
+!
+
+selectedCssClass
+	^ 'selected'
+!
+
+tag
+	^ 'ul'
+! !
+
+!MKListView methodsFor: 'actions'!
+
+activateItem: anObject
+	self activateListItem: (self findListItemFor: anObject)
+!
+
+activateListItem: aListItem
+	| item |
+	
+	(aListItem get: 0) ifNil: [ ^ self ].
+	aListItem parent children removeClass: self selectedCssClass.
+	aListItem addClass: self selectedCssClass.
+    
+	self ensureVisible: aListItem
+! !
+
+!MKListView methodsFor: 'defaults'!
+
+defaultControllerClass
+	^ MKListController
+!
+
+defaultDisplayBlock
+	^ [ :item | item asString ]
+! !
+
+!MKListView methodsFor: 'private'!
+
+ensureVisible: aListItem	
+	"Move the scrollbar to show the active element"
+	
+	| parent position |
+	(aListItem get: 0) ifNil: [ ^ self ].
+	position := self positionOf: aListItem.
+	parent := aListItem parent.
+	
+    aListItem position top < 0 ifTrue: [
+		(parent get: 0) scrollTop: ((parent get: 0) scrollTop + aListItem position top - 10) ].
+    aListItem position top + aListItem height > parent height ifTrue: [ 
+		(parent get: 0) scrollTop: ((parent get: 0) scrollTop + aListItem height - (parent height - aListItem position top)) +10 ]
+!
+
+positionOf: aListItem
+	"TODO: rewrite in smalltalk"
+	<return aListItem.parent().children().get().indexOf(aListItem.get(0)) + 1>
+! !
+
+!MKListView methodsFor: 'rendering'!
+
+renderContentOn: html
+	self collection do: [ :each  | 
+    	self renderItem: each  on: html ].
+	
+	"make the list focusable"
+	root at: 'tabindex' put: '0'
+!
+
+renderItem: anObject on: html
+	| li |
+	
+	li := html li.
+	li asJQuery data: 'item' put: anObject.
+	
+	self selectedItem = anObject ifTrue: [
+		li class: self selectedCssClass ].	
+	li with: (self displayBlock value: anObject)
+! !
+
+!MKListView methodsFor: 'updating'!
+
+update: anAnnouncement
+	anAnnouncement aspect = self selectionAspect ifTrue: [
+		self updateSelectedItem ].
+		
+	anAnnouncement aspect = self collectionAspect ifTrue: [
+		self update ]
+!
+
+updateSelectedItem
+	self activateItem: self selectedItem
+! !
+
+!MKListView class methodsFor: 'instance creation'!
+
+model: aModel collectionAspect: collectionSelector selectionAspect: selectionSelector
+	^ (self model: aModel)
+		collectionAspect: collectionSelector;
+		selectionAspect: selectionSelector;
+		yourself
+! !
+
+MKListView subclass: #MKDropdownListView
+	instanceVariableNames: ''
+	package: 'Moka-Views'!
+!MKDropdownListView commentStamp!
+I am similar to a `MKListView`, but inside a `MKDropdownView`.!
+
+!MKDropdownListView methodsFor: 'accessing'!
+
+cssClass
+	^ super cssClass, ' mk_dropdown_list'
+!
+
+defaultControllerClass
+	^ MKDropdownListController
+! !
+
+MKListView subclass: #MKSourceListView
+	instanceVariableNames: ''
+	package: 'Moka-Views'!
+!MKSourceListView commentStamp!
+I am similar to a `MKListView`, but displayed slightly differently, in a similar way as in the left-side the of Finder in OSX.!
+
+!MKSourceListView methodsFor: 'accessing'!
+
+cssClass
+	^ super cssClass, ' mk_sourcelist'
+! !
+
+MKSingleAspectView subclass: #MKTextAreaView
+	instanceVariableNames: ''
 	package: 'Moka-Views'!
 !MKTextAreaView commentStamp!
 I am an text area view. My default controller is `MKAnyKeyInputController`.
@@ -175,34 +735,41 @@ My controller must answer to `#onKeyPressed:`.!
 
 !MKTextAreaView methodsFor: 'accessing'!
 
+cssClass
+	^ super cssClass, ' mk_textarea'
+!
+
+tag
+	^ 'textarea'
+!
+
 value
-	^ input asJQuery val
+	^ root asJQuery val
 ! !
 
 !MKTextAreaView methodsFor: 'defaults'!
 
 defaultControllerClass
 	^ MKAnyKeyInputController
-! !
-
-!MKTextAreaView methodsFor: 'events'!
+!
 
-keyUp: anEvent
-	self controller onKeyPressed: anEvent
+defaultLayout
+	^ super defaultLayout
+		width: 160;
+		height: 80;
+		yourself
 ! !
 
 !MKTextAreaView methodsFor: 'rendering'!
 
 renderContentOn: html
-	input := html textarea 
-		with: self aspectValue;
-		onKeyUp: [ :event | self keyUp: event ]
+	root with: self aspectValue
 ! !
 
 !MKTextAreaView methodsFor: 'updating'!
 
 update
-	input ifNotNil: [ input asJQuery val: self aspectValue ]
+	root ifNotNil: [ root asJQuery val: self aspectValue ]
 ! !
 
 MKTextAreaView subclass: #MKInputView
@@ -213,20 +780,33 @@ I am an input view. My default controller is `MKEnterInputController`.
 
 My controller must answer to `#onKeyPressed:`.!
 
+!MKInputView methodsFor: 'accessing'!
+
+cssClass
+	^ 'moka_view mk_input'
+!
+
+tag
+	^ 'input'
+! !
+
 !MKInputView methodsFor: 'defaults'!
 
 defaultControllerClass
 	^ MKEnterInputController
+!
+
+defaultLayout
+	^ super defaultLayout
+		width: 160;
+		height: 24;
+		yourself
 ! !
 
 !MKInputView methodsFor: 'rendering'!
 
 renderContentOn: html
-	input := html input
-		value: self aspectValue;
-		onKeyUp: [ :event |
-			self keyUp: event ];
-		yourself
+	root value: self aspectValue
 ! !
 
 !MKInputView methodsFor: 'settings'!

+ 3 - 1
support/amber.js

@@ -52,7 +52,9 @@ require = function (require) {
             'amber_core/_source': amber_home + '/st',
             'amber_html': amber_home,
             'jquery': document_home + '/bower_components/jquery/jquery.min',
-            'jquery-ui': amber_home + '/support/jQuery/jquery-ui-1.8.24.custom.min'
+            'jquery-ui': amber_home + '/support/jQuery/jquery-ui-1.8.24.custom.min',
+			'jscrollpane': document_home + '/bower_components/jscrollpane/script/jquery.jscrollpane.min',
+			'mousewheel': document_home + '/bower_components/jscrollpane/script/jquery.mousewheel'
         },
         map: {
             '*': {

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä