From 5efdd65677f1cb94d7f617accbb0bb798e50eddc Mon Sep 17 00:00:00 2001 From: s-ol Date: Sat, 10 Nov 2018 20:14:44 +1100 Subject: begin documenting mmm.component --- render.moon | 1 + root/meta/mmm.component/description: text$plain | 1 + .../tests: text$moonscript -> mmm$dom.moon | 246 +++++++++++++++++++++ .../text$moonscript -> fn -> mmm$dom.moon | 169 ++++++++++++++ .../mmm.component/todoMVC/description: text$plain | 1 + .../todoMVC/text$moonscript -> mmm$component.moon | 34 +++ root/meta/mmm.dom/text$moonscript -> mmm$dom.moon | 2 +- .../test_mmm.component/description: text$plain | 1 - .../text$moonscript -> mmm$dom.moon | 246 --------------------- root/meta/todo/description: text$plain | 1 - .../todo/text$moonscript -> mmm$component.moon | 34 --- 11 files changed, 453 insertions(+), 283 deletions(-) create mode 100644 root/meta/mmm.component/description: text$plain create mode 100644 root/meta/mmm.component/tests: text$moonscript -> mmm$dom.moon create mode 100644 root/meta/mmm.component/text$moonscript -> fn -> mmm$dom.moon create mode 100644 root/meta/mmm.component/todoMVC/description: text$plain create mode 100644 root/meta/mmm.component/todoMVC/text$moonscript -> mmm$component.moon delete mode 100644 root/meta/test_mmm.component/description: text$plain delete mode 100644 root/meta/test_mmm.component/text$moonscript -> mmm$dom.moon delete mode 100644 root/meta/todo/description: text$plain delete mode 100644 root/meta/todo/text$moonscript -> mmm$component.moon diff --git a/render.moon b/render.moon index 5284e66..4998452 100644 --- a/render.moon +++ b/render.moon @@ -17,6 +17,7 @@ while root\find '^%.%./' path = trimmed .. path root = dofile '$bundle.lua' +assert root, "couldn't load $bundle.lua" root\mount path, true content, rehydrate = render root, path diff --git a/root/meta/mmm.component/description: text$plain b/root/meta/mmm.component/description: text$plain new file mode 100644 index 0000000..e55fcd6 --- /dev/null +++ b/root/meta/mmm.component/description: text$plain @@ -0,0 +1 @@ +a small and DOM-centric framework for reactive web interfaces diff --git a/root/meta/mmm.component/tests: text$moonscript -> mmm$dom.moon b/root/meta/mmm.component/tests: text$moonscript -> mmm$dom.moon new file mode 100644 index 0000000..547b030 --- /dev/null +++ b/root/meta/mmm.component/tests: text$moonscript -> mmm$dom.moon @@ -0,0 +1,246 @@ +import article, div, h1, ul, li, pre from require 'mmm.dom' + +_content = {} +append = (stuff) -> table.insert _content, stuff + +last = nil +test_group = (name) -> + if last + append div (h1 last.name), ul last + + last = { :name } + (name, test) -> + ok, err = pcall test + table.insert last, li if ok + "passed '#{name}'" + else + "failed '#{name}'", pre err + +expect = (expected, note, ...) -> + ok, msg = pcall ... + if ok or not msg\find expected + error note + +run_test = test_group 'component.moon' + +local ReactiveVar, ReactiveElement +run_test "exports ReactiveVar, ReactiveElement", -> + import ReactiveVar, ReactiveElement from require 'mmm.component' + assert ReactiveVar, "ReactiveVar not exported" + assert ReactiveElement, "ReactiveElement not exported" + +run_test "exports tohtml helper", -> + import tohtml from require 'mmm.component' + assert 'function' == (type tohtml), "tohtml not exported" + +-- @TODO: get_or_create + +run_test "exports text helper", -> + import text from require 'mmm.component' + assert 'function' == (type text), "text not exported" + + node = text 'a test string' + + data = if MODE == 'CLIENT' + assert (js.instanceof node, js.global.Node), "expected text to generate a Node" + node.data + else + node + + assert data == 'a test string', "expected text to store the string" + +run_test "text joins multiple arguments", -> + import text from require 'mmm.component' + + node = text 'a', 'test', 'string' + + data = if MODE == 'CLIENT' then node.data else node + assert data == 'a test string', "expected text to join arguments with spaces" + +run_test "exports elements table", -> + import elements from require 'mmm.component' + + assert (type elements.div!) == 'table', "expected to build element with elements.div!" + assert (type elements.madeup!) == 'table', "expected to build element with elements.madeup!" + +run_test = test_group 'ReactiveVar' + +run_test "stores a value", -> + reactive = ReactiveVar 'test' + assert 'test' == reactive\get!, "expected x to be 'test'" + +run_test "provides #map shorthand", -> + local done + + original = ReactiveVar 1 + mapped = original\map (a) -> a + 10 + + assert mapped\get! == 11, "expected mapped to be 11" + return if MODE == 'SERVER' + + original\set 4 + assert mapped\get! == 14, "expected mapped to update" + + mapped\subscribe coroutine.wrap (next, last) -> + assert next == 26, "expected next to be 26" + assert last == 14, "expected last to be 14" + done = true + + original\set 16 + assert done, "expected to reach the end" + +if MODE == 'CLIENT' + run_test "propagates updates", -> + local done + + reactive = ReactiveVar 'test' + reactive\subscribe coroutine.wrap (next) -> + assert next == 'toast', "expected next to be 'toast'" + assert coroutine.yield! == 'cheese', "expected next to be 'cheese'" + done = true + + reactive\set 'toast' + assert 'toast' == reactive\get!, "expected #get to return 'toast'" + reactive\set 'cheese' + assert done, "expected to reach the end" + + run_test "passes old value as well", -> + local done + + reactive = ReactiveVar 1 + reactive\subscribe coroutine.wrap (next, last) -> + assert last == 1, "expected last:1 to be 1" + next, last = coroutine.yield! + assert last == 2, "expected last:2 to be 2" + done = true + + reactive\set 2 + reactive\set 3 + assert done, "expected to reach the end" + + run_test "provides #transform shorthand", -> + local done + + reactive = ReactiveVar 1 + reactive\subscribe coroutine.wrap (next, last) -> + assert last == 1, "expected last:1 to be 1" + next, last = coroutine.yield! + assert last == 2, "expected last:2 to be 2" + done = true + + add_one = (a) -> a + 1 + reactive\transform add_one + reactive\transform add_one + assert done, "expected to reach the end" + + run_test "#subscribe returns function to unsubscribe", -> + calls = 0 + + reactive = ReactiveVar 1 + unsub = reactive\subscribe coroutine.wrap () -> + calls += 1 + coroutine.yield! + calls += 1 + coroutine.yield! + calls += 1 + + assert 'function' == (type unsub), "expected to receive a function" + + reactive\set 2 + reactive\set 3 + assert calls == 2, "wat" + + unsub! + reactive\set 4 + assert calls == 2, "expected to stop receiving updates" + + run_test "tracks multiple subscriptions at once", -> + reactive = ReactiveVar 'test' + unsub = reactive\subscribe coroutine.wrap (next) -> + assert next == 'toast', "expected next to be toast" + next = coroutine.yield! + assert next == 'cheese', "expected next to be cheese" + coroutine.yield! + error "expected not to get here" + + reactive\set 'toast' + + local done + reactive\subscribe coroutine.wrap (next) -> + assert next == 'cheese', "expected next to be cheese" + next = coroutine.yield! + assert next == 'test', "expected next to be test" + done = true + + reactive\set 'cheese' + unsub! + reactive\set 'test' + assert done, "expected to reach the end" + +run_test = test_group 'ReactiveElement' + +run_test "creates a HTML element", -> + elem = ReactiveElement 'span' + assert elem.node and elem.node.localName == 'span', "expected Node to be a " + +-- @TODO: can take over a DOM Node + +run_test "sets attributes from a table arg", -> + elem = ReactiveElement 'span', class: 'never' + assert elem.node.className == 'never', "expected class to be 'never'" + +run_test "appends Nodes from arguments", -> + e_div, e_pre = div!, pre! + elem = ReactiveElement 'span', e_div, e_pre + assert elem.node.firstElementChild == e_div, "expected div to be the first child of elem" + assert elem.node.lastElementChild == e_pre, "expected pre to be the last child of elem" + +run_test "can append ReactiveElements and text", -> + e_div = ReactiveElement 'div' + elem = ReactiveElement 'div', e_div, 'testtext' + assert elem.node.firstElementChild == e_div.node, "expected div to be the first child of elem" + assert elem.node.lastChild.data == 'testtext', "expected last child of elem to be 'testtext'" + +run_test "accepts attributes after children", -> + e_div = div! + elem = ReactiveElement 'div', e_div, class: 'test' + assert elem.node.firstElementChild == e_div, "expected div to be the first child of elem" + assert elem.node.className == 'test', "expected class to be 'test'" + +run_test "allows mixing attributes and children in a single table", -> + e_div, e_pre = div!, pre! + elem = ReactiveElement 'div', { class: 'test', e_div, e_pre } + assert elem.node.firstElementChild == e_div, "expected div to be the first child of elem" + assert elem.node.lastElementChild == e_pre, "expected pre to be the last child of elem" + assert elem.node.className == 'test', "expected class to be 'test'" + +run_test "can unwrap and track attributes from ReactiveVars", -> + klass = ReactiveVar 'test' + elem = ReactiveElement 'div', class: klass + assert elem.node.className == 'test', "expected class to be 'test'" + klass\set 'toast' + assert elem.node.className == 'toast', "expected class to be 'toast'" + +run_test "can unwrap and track children from ReactiveVars", -> + child = ReactiveVar h1 'test' + elem = ReactiveElement 'div', child, pre 'fixed' + assert elem.node.firstElementChild.localName == 'h1', "expected first child to be h1" + assert elem.node.childElementCount == 2, "expected node to have two children" + child\set div 'toast' + assert elem.node.firstElementChild.localName == 'div', "expected first child to be div" + assert elem.node.childElementCount == 2, "expected node to have two children" + +run_test "warns when appending a string from a ReactiveVar", -> + import text from require 'mmm.component' + + str = ReactiveVar 'test' + elem = ReactiveElement 'div', str + expect 'cannot replace string node', 'expected error', str\set, 'string too' + elem\destroy! + + elem = ReactiveElement 'div', str\map text + str\set 'this is text' + +test_group! + +article _content diff --git a/root/meta/mmm.component/text$moonscript -> fn -> mmm$dom.moon b/root/meta/mmm.component/text$moonscript -> fn -> mmm$dom.moon new file mode 100644 index 0000000..d5acc1e --- /dev/null +++ b/root/meta/mmm.component/text$moonscript -> fn -> mmm$dom.moon @@ -0,0 +1,169 @@ +import article, section, h1, h2, h3, p, a, div, ul, li, pre, code from require 'mmm.dom' +import lua, moonscript from (require 'mmm.highlighting').languages + +mmmcomp = -> code 'mmm.component' + +source = do + (moon_src, lua_src, demo=true) -> + the_code = pre (moonscript moon_src), (lua lua_src), class: 'dual-code' + + return the_code unless demo + + example = assert load lua_src + div the_code, div example!, class: 'example' + +=> article { + h1 mmmcomp! + p mmmcomp!, " is a small and DOM-centric framework for reactive web interfaces." + + p do + fengari = a "fengari.io", href: '//fengari.io' + + "Built for reactive UI, ", mmmcomp!, " is meant to run on the client using ", fengari, ". + However, like ", (code 'mmm.dom'), ", the API is supported both on the client as well as + on the server (were most reactive features have been omitted) so that static pre-rendered + content can still be generated from the same code that powers the reactive interface." + + h2 "Examples" + p "Feel free to read the API documentation below, or take a look at the following examples using the ", + (code 'mmmfs'), " inspect mode:" + + ul for child in *@children + li a (child\gett 'name: alpha'), { + href: child.path, + onclick: (e) => + e\preventDefault! + BROWSER\navigate child.path + } + + h2 "API" + p "Begin by requiring ", mmmcomp!, ". The module returns a table containing the following:" + + ul { + li (code 'ReactiveVar'), ": class/constructor for reactive state variables.", + li (code 'ReactiveElement'), ": class/constructor for reactive DOM elements. Rarely used directly." + li (code 'elements'), ": 'magic table' containing constructors for ReactiveElements by tag name." + li (code 'tohtml'), ": helper to convert from ReactiveElements to mmm/dom (DOM nodes / HTML strings)" + li (code 'text'), ": helper to convert Lua strings to DOM Text Nodes." + li (code 'get_or_create'), ": helper for rehydratable views." + } + + section do + rvar = -> code 'ReactiveVar' + + { + id: 'ReactiveVar' + + h3 "Reactive Variables" + p mmmcomp!, " is centered around the concept of Reactive Variables (", rvar!, "s). + A ", rvar!, " is a container for a piece of application state that other pieces of code can + subscribe to. These attached callbacks are invoked whenever the value changes." + + p "You can instantiate a ", rvar!, " via the constructor at any time. The constructor takes + the initial variable as an argument, but if you omit it ", (code 'nil'), " will work fine as well. + After instantiation, ", (code ':get()'), " and ", (code ':set(val)'), " will give access to the value:" + + source [[ +import ReactiveVar from require 'mmm.component' + +test = ReactiveVar 3 +print test\get! -- prints '3' +test\set 4 +print test\get! -- prints '4' + ]], [[ +local ReactiveVar = require 'mmm.component'.ReactiveVar + +local test = ReactiveVar(3) +print(test:get()) -- prints '3' +test:set(4) +print(test:get()) -- prints '4' + ]], false + + p "The value can also be changed using ", (code ':transform(fn)'), ", which is simply a shorthand for ", + (code 'var:set(fn(var:get()))'), ":" + + source [[ +import ReactiveVar from require 'mmm.component' + +add_one = (n) -> n + 1 +count = ReactiveVar 1 + +count\transform add_one +print test\get! -- prints '2' + +count\transform add_one +print test\get! -- prints '3' + ]], [[ +local ReactiveVar = require 'mmm.component'.ReactiveVar + +local function add_one(x) return x + 1 end +local count = ReactiveVar(1) + +count:transform(add_one) +print(test:get()) -- prints '2' + +count:transform(add_one) +print(test:get()) -- prints '3' + ]], false + + p "Now, so far we haven't really seen anything useful - this is all just behaving like a normal variable. + The ", (code ':subscribe(callback)'), " method is what makes ", rvar!, "s interesting: Whenever the value + changes, the ", rvar!, " calls each of the registered handlers, passing the new as well as the previous value:" + + source [[ +import ReactiveVar from require 'mmm.component' + +add_one = (n) -> n + 1 +count = ReactiveVar 1 +count\subscribe (new, old) -> + print "changing from #{old} to #{new}!" + + +count\transform add_one -- changing from 1 to 2 +count\set "a string" -- changing from 2 to a string + ]], [[ +local ReactiveVar = require 'mmm.component'.ReactiveVar + +local function add_one(x) return x + 1 end +local count = ReactiveVar(1) +cout:subscribe(function(new old) + print("changing from " .. old .. " to " .. new) +end) + +count:transform(add_one) -- changing from 1 to 2 +count:set("a string") -- changing from 2 to a string + ]], false + + p "This allows other code (such as ", (code 'ReactiveElement'), "s) to react to value changes and update + themselves, as we will see in a minute. Often you will want to derive state from other state. To make this + easy while keeping everything reactive, ", mmmcomp!, " includes the ", (code ':map(fn)'), " method." + + p (code ':map(fn)'), " applies the function ", (code 'fn'), " to the current value, just as ", + (code ':transform(fn)'), " would, but it doesn't update the value itself - it rather returns a new ", rvar!, + " instance that is already set up to update whenever the original one changes." + + source [[ +import ReactiveVar from require 'mmm.component' + +fruit = ReactiveVar "apple" +loud_fruit = fruit\map string.upper + +print fruit\get! -- prints 'apple' +print loud_fruit\get! -- prints 'APPLE' + +fruit\set "orange" +print loud_fruit\get! -- prints 'ORANGE' + ]], [[ +local ReactiveVar = require 'mmm.component'.ReactiveVar + +local fruit = ReactiveVar("apple") +local loud_fruit = fruit:map(string.upper) + +print(fruit:get()) -- prints 'apple' +print(loud_fruit:get()) -- prints 'APPLE' + +fruit:set("orange") +print(loud_fruit:get()) -- prints 'ORANGE' + ]], false + } +} diff --git a/root/meta/mmm.component/todoMVC/description: text$plain b/root/meta/mmm.component/todoMVC/description: text$plain new file mode 100644 index 0000000..baaf6fc --- /dev/null +++ b/root/meta/mmm.component/todoMVC/description: text$plain @@ -0,0 +1 @@ +TodoMVC using mmm.component diff --git a/root/meta/mmm.component/todoMVC/text$moonscript -> mmm$component.moon b/root/meta/mmm.component/todoMVC/text$moonscript -> mmm$component.moon new file mode 100644 index 0000000..dc4e5e1 --- /dev/null +++ b/root/meta/mmm.component/todoMVC/text$moonscript -> mmm$component.moon @@ -0,0 +1,34 @@ +import ReactiveVar, text, elements from require 'mmm.component' +import article, div, form, span, h3, a, input from elements + +parent = div! +todoItem = (desc, done) -> + -- convert into reactive data sources + desc, done = (ReactiveVar desc), ReactiveVar done + with me = div style: + margin: '8px' + padding: '8px' + background: '#eeeeee' + \append h3 (desc\map text), style: 'margin: 0;' + \append span done\map (done) -> text if done then 'done' else 'not done yet' + \append input type: 'checkbox', checked: done, onchange: (e) => done\set e.target.checked + \append a (text 'delete'), href: '#', onclick: (e) => parent\remove me + +parent\append todoItem 'write a Component System', true +parent\append todoItem 'eat Lasagna', true +parent\append todoItem 'do other things' + +desc = ReactiveVar 'start' +form = with form { + action: '' + style: + margin: '2px' + onsubmit: (e) => + e\preventDefault! + parent\append todoItem desc\get! + desc\set '' + } + \append input type: 'text', value: desc, onchange: (e) => desc\set e.target.value + \append input type: 'submit', value: 'add' + +article parent, form diff --git a/root/meta/mmm.dom/text$moonscript -> mmm$dom.moon b/root/meta/mmm.dom/text$moonscript -> mmm$dom.moon index 1479c00..090b53b 100644 --- a/root/meta/mmm.dom/text$moonscript -> mmm$dom.moon +++ b/root/meta/mmm.dom/text$moonscript -> mmm$dom.moon @@ -1,4 +1,4 @@ -import article, h1, h2, p, a, span, div, pre, code from require 'mmm.dom' +import article, h1, h2, p, a, div, pre, code from require 'mmm.dom' import lua, moonscript from (require 'mmm.highlighting').languages mmmdom = -> code 'mmm.dom' diff --git a/root/meta/test_mmm.component/description: text$plain b/root/meta/test_mmm.component/description: text$plain deleted file mode 100644 index 691fea5..0000000 --- a/root/meta/test_mmm.component/description: text$plain +++ /dev/null @@ -1 +0,0 @@ -Tests for mmm.component diff --git a/root/meta/test_mmm.component/text$moonscript -> mmm$dom.moon b/root/meta/test_mmm.component/text$moonscript -> mmm$dom.moon deleted file mode 100644 index 547b030..0000000 --- a/root/meta/test_mmm.component/text$moonscript -> mmm$dom.moon +++ /dev/null @@ -1,246 +0,0 @@ -import article, div, h1, ul, li, pre from require 'mmm.dom' - -_content = {} -append = (stuff) -> table.insert _content, stuff - -last = nil -test_group = (name) -> - if last - append div (h1 last.name), ul last - - last = { :name } - (name, test) -> - ok, err = pcall test - table.insert last, li if ok - "passed '#{name}'" - else - "failed '#{name}'", pre err - -expect = (expected, note, ...) -> - ok, msg = pcall ... - if ok or not msg\find expected - error note - -run_test = test_group 'component.moon' - -local ReactiveVar, ReactiveElement -run_test "exports ReactiveVar, ReactiveElement", -> - import ReactiveVar, ReactiveElement from require 'mmm.component' - assert ReactiveVar, "ReactiveVar not exported" - assert ReactiveElement, "ReactiveElement not exported" - -run_test "exports tohtml helper", -> - import tohtml from require 'mmm.component' - assert 'function' == (type tohtml), "tohtml not exported" - --- @TODO: get_or_create - -run_test "exports text helper", -> - import text from require 'mmm.component' - assert 'function' == (type text), "text not exported" - - node = text 'a test string' - - data = if MODE == 'CLIENT' - assert (js.instanceof node, js.global.Node), "expected text to generate a Node" - node.data - else - node - - assert data == 'a test string', "expected text to store the string" - -run_test "text joins multiple arguments", -> - import text from require 'mmm.component' - - node = text 'a', 'test', 'string' - - data = if MODE == 'CLIENT' then node.data else node - assert data == 'a test string', "expected text to join arguments with spaces" - -run_test "exports elements table", -> - import elements from require 'mmm.component' - - assert (type elements.div!) == 'table', "expected to build element with elements.div!" - assert (type elements.madeup!) == 'table', "expected to build element with elements.madeup!" - -run_test = test_group 'ReactiveVar' - -run_test "stores a value", -> - reactive = ReactiveVar 'test' - assert 'test' == reactive\get!, "expected x to be 'test'" - -run_test "provides #map shorthand", -> - local done - - original = ReactiveVar 1 - mapped = original\map (a) -> a + 10 - - assert mapped\get! == 11, "expected mapped to be 11" - return if MODE == 'SERVER' - - original\set 4 - assert mapped\get! == 14, "expected mapped to update" - - mapped\subscribe coroutine.wrap (next, last) -> - assert next == 26, "expected next to be 26" - assert last == 14, "expected last to be 14" - done = true - - original\set 16 - assert done, "expected to reach the end" - -if MODE == 'CLIENT' - run_test "propagates updates", -> - local done - - reactive = ReactiveVar 'test' - reactive\subscribe coroutine.wrap (next) -> - assert next == 'toast', "expected next to be 'toast'" - assert coroutine.yield! == 'cheese', "expected next to be 'cheese'" - done = true - - reactive\set 'toast' - assert 'toast' == reactive\get!, "expected #get to return 'toast'" - reactive\set 'cheese' - assert done, "expected to reach the end" - - run_test "passes old value as well", -> - local done - - reactive = ReactiveVar 1 - reactive\subscribe coroutine.wrap (next, last) -> - assert last == 1, "expected last:1 to be 1" - next, last = coroutine.yield! - assert last == 2, "expected last:2 to be 2" - done = true - - reactive\set 2 - reactive\set 3 - assert done, "expected to reach the end" - - run_test "provides #transform shorthand", -> - local done - - reactive = ReactiveVar 1 - reactive\subscribe coroutine.wrap (next, last) -> - assert last == 1, "expected last:1 to be 1" - next, last = coroutine.yield! - assert last == 2, "expected last:2 to be 2" - done = true - - add_one = (a) -> a + 1 - reactive\transform add_one - reactive\transform add_one - assert done, "expected to reach the end" - - run_test "#subscribe returns function to unsubscribe", -> - calls = 0 - - reactive = ReactiveVar 1 - unsub = reactive\subscribe coroutine.wrap () -> - calls += 1 - coroutine.yield! - calls += 1 - coroutine.yield! - calls += 1 - - assert 'function' == (type unsub), "expected to receive a function" - - reactive\set 2 - reactive\set 3 - assert calls == 2, "wat" - - unsub! - reactive\set 4 - assert calls == 2, "expected to stop receiving updates" - - run_test "tracks multiple subscriptions at once", -> - reactive = ReactiveVar 'test' - unsub = reactive\subscribe coroutine.wrap (next) -> - assert next == 'toast', "expected next to be toast" - next = coroutine.yield! - assert next == 'cheese', "expected next to be cheese" - coroutine.yield! - error "expected not to get here" - - reactive\set 'toast' - - local done - reactive\subscribe coroutine.wrap (next) -> - assert next == 'cheese', "expected next to be cheese" - next = coroutine.yield! - assert next == 'test', "expected next to be test" - done = true - - reactive\set 'cheese' - unsub! - reactive\set 'test' - assert done, "expected to reach the end" - -run_test = test_group 'ReactiveElement' - -run_test "creates a HTML element", -> - elem = ReactiveElement 'span' - assert elem.node and elem.node.localName == 'span', "expected Node to be a " - --- @TODO: can take over a DOM Node - -run_test "sets attributes from a table arg", -> - elem = ReactiveElement 'span', class: 'never' - assert elem.node.className == 'never', "expected class to be 'never'" - -run_test "appends Nodes from arguments", -> - e_div, e_pre = div!, pre! - elem = ReactiveElement 'span', e_div, e_pre - assert elem.node.firstElementChild == e_div, "expected div to be the first child of elem" - assert elem.node.lastElementChild == e_pre, "expected pre to be the last child of elem" - -run_test "can append ReactiveElements and text", -> - e_div = ReactiveElement 'div' - elem = ReactiveElement 'div', e_div, 'testtext' - assert elem.node.firstElementChild == e_div.node, "expected div to be the first child of elem" - assert elem.node.lastChild.data == 'testtext', "expected last child of elem to be 'testtext'" - -run_test "accepts attributes after children", -> - e_div = div! - elem = ReactiveElement 'div', e_div, class: 'test' - assert elem.node.firstElementChild == e_div, "expected div to be the first child of elem" - assert elem.node.className == 'test', "expected class to be 'test'" - -run_test "allows mixing attributes and children in a single table", -> - e_div, e_pre = div!, pre! - elem = ReactiveElement 'div', { class: 'test', e_div, e_pre } - assert elem.node.firstElementChild == e_div, "expected div to be the first child of elem" - assert elem.node.lastElementChild == e_pre, "expected pre to be the last child of elem" - assert elem.node.className == 'test', "expected class to be 'test'" - -run_test "can unwrap and track attributes from ReactiveVars", -> - klass = ReactiveVar 'test' - elem = ReactiveElement 'div', class: klass - assert elem.node.className == 'test', "expected class to be 'test'" - klass\set 'toast' - assert elem.node.className == 'toast', "expected class to be 'toast'" - -run_test "can unwrap and track children from ReactiveVars", -> - child = ReactiveVar h1 'test' - elem = ReactiveElement 'div', child, pre 'fixed' - assert elem.node.firstElementChild.localName == 'h1', "expected first child to be h1" - assert elem.node.childElementCount == 2, "expected node to have two children" - child\set div 'toast' - assert elem.node.firstElementChild.localName == 'div', "expected first child to be div" - assert elem.node.childElementCount == 2, "expected node to have two children" - -run_test "warns when appending a string from a ReactiveVar", -> - import text from require 'mmm.component' - - str = ReactiveVar 'test' - elem = ReactiveElement 'div', str - expect 'cannot replace string node', 'expected error', str\set, 'string too' - elem\destroy! - - elem = ReactiveElement 'div', str\map text - str\set 'this is text' - -test_group! - -article _content diff --git a/root/meta/todo/description: text$plain b/root/meta/todo/description: text$plain deleted file mode 100644 index baaf6fc..0000000 --- a/root/meta/todo/description: text$plain +++ /dev/null @@ -1 +0,0 @@ -TodoMVC using mmm.component diff --git a/root/meta/todo/text$moonscript -> mmm$component.moon b/root/meta/todo/text$moonscript -> mmm$component.moon deleted file mode 100644 index dc4e5e1..0000000 --- a/root/meta/todo/text$moonscript -> mmm$component.moon +++ /dev/null @@ -1,34 +0,0 @@ -import ReactiveVar, text, elements from require 'mmm.component' -import article, div, form, span, h3, a, input from elements - -parent = div! -todoItem = (desc, done) -> - -- convert into reactive data sources - desc, done = (ReactiveVar desc), ReactiveVar done - with me = div style: - margin: '8px' - padding: '8px' - background: '#eeeeee' - \append h3 (desc\map text), style: 'margin: 0;' - \append span done\map (done) -> text if done then 'done' else 'not done yet' - \append input type: 'checkbox', checked: done, onchange: (e) => done\set e.target.checked - \append a (text 'delete'), href: '#', onclick: (e) => parent\remove me - -parent\append todoItem 'write a Component System', true -parent\append todoItem 'eat Lasagna', true -parent\append todoItem 'do other things' - -desc = ReactiveVar 'start' -form = with form { - action: '' - style: - margin: '2px' - onsubmit: (e) => - e\preventDefault! - parent\append todoItem desc\get! - desc\set '' - } - \append input type: 'text', value: desc, onchange: (e) => desc\set e.target.value - \append input type: 'submit', value: 'add' - -article parent, form -- cgit v1.2.3