Skip to content

Commit

Permalink
First knockoutjs Tutorial works!
Browse files Browse the repository at this point in the history
  • Loading branch information
ionoy committed Jul 21, 2012
1 parent 10357ba commit 887fae1
Show file tree
Hide file tree
Showing 13 changed files with 3,595 additions and 56 deletions.
Expand Up @@ -12,7 +12,7 @@ namespace MVCTest.Controllers
{
public Index() : ActionResult
{
Content(Utils.MakePageHtml(BetterListViewModel("", ["Fries", "Eggs Benedict", "Ham", "Cheese"], ["Ham"]), Views.BetterListView));
Content("" /*Utils.MakePageHtml(BetterListViewModel("", ["Fries", "Eggs Benedict", "Ham", "Cheese"], ["Ham"]), Views.BetterListView)*/);
}

public Tutorial() : ActionResult
Expand Down
6 changes: 6 additions & 0 deletions snippets/Nemerle.WUI.Reactive/MVCTest/MVCTest.nproj
Expand Up @@ -286,6 +286,12 @@
<Content Include="Scripts\knockout-1.3.0beta.js">
<SubType>Content</SubType>
</Content>
<Content Include="Scripts\knockout-2.1.0.debug.js">
<SubType>Content</SubType>
</Content>
<Content Include="Scripts\knockout-2.1.0.js">
<SubType>Content</SubType>
</Content>
<Content Include="Scripts\modernizr-2.0.6-development-only.js">
<SubType>Content</SubType>
</Content>
Expand Down
2 changes: 1 addition & 1 deletion snippets/Nemerle.WUI.Reactive/MVCTest/MVVM/BetterList.n
Expand Up @@ -12,7 +12,7 @@ using System.Xml.Linq;

namespace MVCTest
{
[Record, ViewModel]
[Record, /*ViewModel*/]
public class BetterListViewModel
{
public ItemToAdd : string { get; set; }
Expand Down
Expand Up @@ -17,7 +17,7 @@ namespace MVCTest
{
public FirstName : string { get; set; }
public LastName : string { get; set; }
public FullName : string { get { FirstName + LastName } }
public FullName : string { get { FirstName + " " + LastName } }

CapitalizeLastName() : void
{
Expand All @@ -33,13 +33,13 @@ namespace MVCTest
_ = viewModel;
xml <#
<div xmlns="">
<p>First name: <strong data-bind="text: FirstName"></strong></p>
<p>Last name: <strong data-bind="text: LastName"></strong></p>
<p>First name: <strong data-bind="text: FirstName"> </strong></p>
<p>Last name: <strong data-bind="text: LastName"> </strong></p>

<p>First name: <input data-bind="value: FirstName" /></p>
<p>Last name: <input data-bind="value: LastName" /></p>

<p>Full name: <strong data-bind="text: FullName"></strong></p>
<p>Full name: <strong data-bind="text: FullName"> </strong></p>

<button data-bind="click: CapitalizeLastName">Go caps</button>
</div>
Expand Down
3,443 changes: 3,443 additions & 0 deletions snippets/Nemerle.WUI.Reactive/MVCTest/Scripts/knockout-2.1.0.debug.js

Large diffs are not rendered by default.

86 changes: 86 additions & 0 deletions snippets/Nemerle.WUI.Reactive/MVCTest/Scripts/knockout-2.1.0.js

Large diffs are not rendered by default.

Expand Up @@ -5,10 +5,9 @@
<title>@ViewBag.Title</title>
<link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
<script src="@Url.Content("~/Scripts/jquery-1.6.2.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/knockout-1.3.0beta.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/knockout-2.1.0.debug.js")" type="text/javascript"></script>
</head>

<body>
@RenderBody()
</body>
<body>
@RenderBody()
</body>
</html>
2 changes: 1 addition & 1 deletion snippets/Nemerle.WUI.Reactive/Nemerle.WUI.Reactive/JsAST.n
Expand Up @@ -29,7 +29,7 @@ namespace Nemerle.WUI.Reactive
| Literal { Value : JsLiteral }
| LocalRef { Name : string }
| MethodRef { Obj : JsAST; Method : string }
| MethodCorLib { Obj : string; Method : string }
| StaticRef { Type : string; Method : string }
| OpCode { Name : string; }
| Object { Fields : list[(string * JsAST)] }
| Seq { Items : list[JsAST] }
Expand Down
Expand Up @@ -27,11 +27,10 @@ namespace Nemerle.WUI.Reactive
| ArrayIndexer => JsAST.NotImpl()
| Assign(s, t) => JsAST.Assign(Build(s), Build(t))
| Base => JsAST.NotImpl()
| Block(body = body) => Build(body)
| Block(body = body) => Build(body)
| Cache => JsAST.NotImpl()
| CacheRef => JsAST.NotImpl()
| Call(StaticRef(from, mem, _), parms, _) => JsKnownMembers.Convert(from.TypeInfo.FullName, mem, parms.Map(p => Build(p.expr)))
| Call(func, parms, istail) => JsAST.Call(Build(func), parms.Map(p => Build(p.expr)))
| Call as call => JsKnownMembers.Convert(call, Build(_, false))
| ClosureFieldOf => JsAST.NotImpl()
| ClosureObjectOf => JsAST.NotImpl()
| ConstantObjectRef => JsAST.NotImpl()
Expand Down Expand Up @@ -86,7 +85,7 @@ namespace Nemerle.WUI.Reactive
| MethodAddress => JsAST.NotImpl()
| MethodOf => JsAST.NotImpl()
| MethodRef(obj, meth, _, _) =>
if(meth.Name.StartsWith("get_"))
if(meth.Name.StartsWith("get_") || meth.Name.StartsWith("set_"))
JsAST.MethodRef(Build(obj), meth.Name.Substring(4))
else
JsAST.MethodRef(Build(obj), meth.Name)
Expand Down
Expand Up @@ -14,8 +14,8 @@ namespace Nemerle.WUI.Reactive
public Optimize(ast : JsAST) : JsAST
{
def allowedForAssignment = [typeof(JsAST.Call), typeof(JsAST.MethodRef), typeof(JsAST.LocalRef),
typeof(JsAST.MethodCorLib), typeof(JsAST.Literal), typeof(JsAST.Code),
typeof(JsAST.Void), typeof(JsAST.Ternary), typeof(JsAST.NotImpl)];
typeof(JsAST.Literal), typeof(JsAST.Code), typeof(JsAST.Void),
typeof(JsAST.Ternary), typeof(JsAST.NotImpl)];

def delayAssignment(e : JsAST, left : JsAST) {
def delayAssignment = delayAssignment(_, left);
Expand Down
Expand Up @@ -55,8 +55,7 @@ $(Write(body, indent + 1))
| Literal(String(val)) => $<#"$val"#>
| Literal(Bool(val)) => $"$val"
| LocalRef(name) => $"$name"
| MethodRef(obj, meth) => i() + $"$(Write(obj)).$meth"
| MethodCorLib(obj, meth) => i() + $"$obj.$meth"
| MethodRef(obj, meth) => i() + $"$(Write(obj)).$meth"
| OpCode(name) => $"$name"
| Object(fields) =>
def fieldToObjectField((name, ast)) {
Expand Down
30 changes: 17 additions & 13 deletions snippets/Nemerle.WUI.Reactive/Nemerle.WUI.Reactive/JsKnownMembers.n
Expand Up @@ -3,6 +3,7 @@ using Nemerle.Collections;
using Nemerle.Text;
using Nemerle.Utility;
using Nemerle.Compiler;
using Nemerle.Compiler.Typedtree;

using System;
using System.Collections.Generic;
Expand All @@ -12,26 +13,22 @@ namespace Nemerle.WUI.Reactive
{
module JsKnownMembers
{
public Convert(typeName : string, member : IMember, parms : list[JsAST]) : JsAST
public Convert(call : TExpr.Call, builder : TExpr -> JsAST) : JsAST
{
match(member.MemberKind) {
| Method => ConvertMethod(typeName, member, parms)
| Field => ConvertField(typeName, member, parms)
| Property => ConvertProperty(typeName, member, parms)
| _ =>
Message.Warning($"MemberKind $(member.MemberKind) not supported");
JsAST.NotImpl()
}
def result = match(call) {
| Call(MethodRef(obj = o, meth = meth), parms, _) => ConvertMethod(o.Type.TypeInfo.FullName, builder(o), meth, parms.Map(p => builder(p.expr)))
| Call(StaticRef(from = fromType, mem = meth) as left, parms, _) => ConvertMethod(fromType.TypeInfo.FullName, builder(left), meth, parms.Map(p => builder(p.expr)))
}
result
}

public ConvertMethod(typeName : string, member : IMember, parms : list[JsAST]) : JsAST
public ConvertMethod(typeName : string, left : JsAST, member : IMember, parms : list[JsAST]) : JsAST
{
match(member.Name, parms) {
| ("op_Inequality", _) => JsAST.Call(JsAST.OpCode("!="), parms)
| ("Concat", h :: t) when typeName == typeof(string).FullName => JsAST.Call(JsAST.MethodRef(h, "concat"), t)
| _ =>
Message.Warning($"member.Name $(member.Name) unsupported by type $(typeName)");
JsAST.NotImpl();
| ("ToUpper", []) when typeName == typeof(string).FullName => JsAST.Call(JsAST.MethodRef(left, "toUpperCase"), [])
| _ => JsAST.Call(JsAST.MethodRef(left, RemoveGetSet(member.Name)), parms)
}
}

Expand All @@ -54,5 +51,12 @@ namespace Nemerle.WUI.Reactive
JsAST.NotImpl();
}
}

private RemoveGetSet(method : string) : string {
if(method.StartsWith("get_") || method.StartsWith("set_"))
method.Substring(4);
else
method;
}
}
}
49 changes: 26 additions & 23 deletions snippets/Nemerle.WUI.Reactive/Nemerle.WUI.Reactive/ViewModel.n
Expand Up @@ -163,48 +163,51 @@ namespace Nemerle.WUI.Reactive
def code =
if (isDependent)
$<#
viewModel.$name = ko.dependentObservable(
function()
{
$scriptBody;
}, viewModel);#>
this.$name = ko.computed(function() {
return $scriptBody;
}, this);#>
else
$<#
viewModel.$name =
function()
{
this.$name = function() {
$scriptBody;
};#>;
};#>;
<[ $(code : string) ]>
}

assert2(false);

def convertMember(member : IMember) : PExpr
{
| meth is MethodBuilder when meth.Name.StartsWith("get_") || meth.Name.StartsWith("set_") => null //TODO: Add property IMethod.IsAccessor
| meth is MethodBuilder when meth.IsConstructor => null
| meth is MethodBuilder when meth.ReturnType is FixedType.Void =>
convertMethod(meth.Name, meth, false)
| prop is PropertyBuilder when prop.CanRead && !prop.CanWrite =>
convertMethod(prop.Name, prop.GetGetter() :> MethodBuilder)

| meth is MethodBuilder when meth.Header.ParametersDeclarations.Length == 0 =>
convertMethod(meth.Name, meth)

| meth is MethodBuilder when meth.ReturnType is FixedType.Void => convertMethod(meth.Name, meth, false)
| prop is PropertyBuilder when prop.AutoPropertyField.IsSome =>
//assert2(false);
def arrayTypes = [<[ ttype: Nemerle.Core.list[_] ]>, <[ ttype: System.Collections.Generic.List[_] ]>];
def isArray = arrayTypes.Any(t => prop.Getter.ReturnType.TryUnify(t));
def ctor = if (isArray) "observableArray" else "observable";
def prefix = $<#this.$(prop.Name) = ko.$ctor(#>;
<[ $(prefix : string)
+ Nemerle.WUI.Reactive.Utils.ToJson(this.$(prop.Ast.name))
+ $(<#);#> : string) ]>
| prop is PropertyBuilder when prop.CanRead && !prop.CanWrite => convertMethod(prop.Name, prop.GetGetter() :> MethodBuilder)
| meth is MethodBuilder when meth.Header.ParametersDeclarations.Length == 0 => convertMethod(meth.Name, meth)
| _ => null
}
}

assert2(false);
def members = tb.GetMembers(BF.DeclaredOnly | BF.Instance | BF.Public);
//assert2(false);
def members = tb.GetMembers(BF.DeclaredOnly | BF.Instance | BF.Public | BF.NonPublic);
def exprs1 = members.RevMap(convertMember).RevFilter(_ != null);
def exprs2 = exprs1.Map(e => <[ _ = sb.AppendLine($e) ]>);

_ = tb.DefineWithSource(<[ decl:
public GetViewModelScript() : string
{
def sb = System.Text.StringBuilder();
_ = sb.AppendLine("var viewModel = { };");
{ ..$exprs2 }
_ = sb.AppendLine("ko.applyBindings(viewModel);");
_ = sb.AppendLine("function ViewModel() { ");
{ ..$exprs2 }
_ = sb.AppendLine("}");
_ = sb.AppendLine("ko.applyBindings(new ViewModel());");
sb.ToString()
}
]>);
Expand Down

0 comments on commit 887fae1

Please sign in to comment.