peterwmwong / cell Goto Github PK
View Code? Open in Web Editor NEWA more modular client side
Home Page: http://peterwmwong.github.io/cell/spec-runner/
License: MIT License
A more modular client side
Home Page: http://peterwmwong.github.io/cell/spec-runner/
License: MIT License
We need some easy way of declaring a View that is based on another.
define (require)->
BaseView = require 'BaseView'
require('cell/defineView!')
renderEl: (_)->
_ BaseView # Pass transformed options
cell/defineView!
is modified to handle a new extends
property that allows the following:
define (require)->
require('cell/defineView!')
extends: require 'BaseView'
beforeRender: ->
# Mutate @options, which will be passed to BaseView when rendering
# DO NOT specify a renderEl() or render()...
Initially, this seemed like a nice solution, BUT...
renderEl()
or render()
Solution 1 seems to be the way to go as you can do this now and it doesn't add weirdness that Solution 2 adds. I'm leaving issue open and unworked on if anyone else has any better ideas.
Maybe we can atleast partially replace some of the specs in specs/fixtures/defineView-builder-plugin/
with a spec setup that runs require.optimize()
.
There are cases the View doesn't have a @model and instead you'd like x_model to use the View itself as the model.
This causes some weird patterns that don't feel right...
define (require)->
x_model = require 'cell/exts/x_model'
require('defineView!')
beforeRender: ->
@model = @ # !!! Whoa... wah? /upchuck
@set 'text', ''
render: (_)-> [
_ 'textarea', (x_model 'text')
]
Add new method signature to x_model
x_model( {propName:string, model:Model} )
An example of usage:
define (require)->
x_model = require 'cell/exts/x_model'
require('defineView!')
beforeRender: ->
@set 'text', ''
render: (_)-> [
_ 'textarea', (x_model prop:'text', model:@)
]
render: (_)->
->if @get 'condition'
_.map [1,2,3], (item)=>
_ '.item', "item #{item}"
<div class='item'>1</div>
<div class='item'>2</div>
<div class='item'>3</div>
@set 'condition', 'another truthy value'
<div class='item'>1</div>
<div class='item'>2</div>
<div class='item'>3</div>
<div class='item'>1</div> <!-- :((( -->
<div class='item'>2</div> <!-- :((( -->
<div class='item'>3</div> <!-- :((( -->
When @get 'condition'
changes, all the times in @collection
get re-rendered WITHOUT the previous items being removed.
Why?
So...
data-cell-template-renderer
, data-cell-style-renderer
attributes to specify pluginspy.watch obj, (-> collection.at(0).get 'property'), ->
Only collection
should be watched for the following events:
'change:property'
(model events bubble up to their collection)'add'
'remove'
Instead, currently, the first model in the collection
is being watched for 'change:property'
This will be a problem for large Collections.
http://requirejs.org/docs/plugins.html#apiwrite
A cell plugin could implement this API to allow cell's to be packaged and optimized...
Do something.
render: (_)-> [
-> @collection.map (item)-> ...
]
render: (_)-> [
_.each @collection, (item)-> ...
]
_.each
has the significant benefit of rerendering ONLY items added, when items are added to the collection. With a simple binding all items are rerendered upon collection changes.
Look into doing something like require.js (http://requirejs.org/docs/jquery.html) with data-* attributes.
Maybe something like this...
<script data-render-cell='App'
data-render-target='body'
src='cell/cell.js'>
</script>
spy.watch obj,
->
a = model.get 'a'
spy.watch obj,
-> model.get 'b'
a
Outer watch doesn't trigger when 'a'
changes on model
.
Inner watch clobbers spy log. :(
model.each (prop, value)->
model.map (prop, value)->
model.reduce initial, (sum, prop, value)->
note: Make sure these are monitored by spy.watch()
https://github.com/peterwmwong/cell/blob/master/src/dom/data.coffee#L32
... shouldn't this be something like:
if expandoStore.cellRef and expandoStore.cellRef.destroy
cellRef = expandoStore.cellRef
delete expandoStore.cellRef
try cellRef.destroy()
ChildView = View.extend
render: -> [
_ 'textarea', (x_model 'text') # Tricky
]
ParentView = View.extend
render: (_)-> [
# Rerenders bind when child model 'text' attribute changes. Yikes!
-> _ ChildView, model: new Model()
]
render: -> [
->
if @get 'switch' then @get 'one'
else @get 'two'
]
Unfortunately, other than the 'switch' property, ONLY 'one' or 'two' will be watched to trigger an expression.
spy.watch()
should monitor access patterns every evaluation of the watched expression, not just the first time.
spy.watch obj, (-> collection.filterBy someProperty: null), ->
# does NOT trigger watch change :(((
collection.at(0).set 'someProperty', 'a new value'
Currently Cell has alot in common with Backbone.Views. In fact, aside from a differences in name (initialize/init) and small functionality (tag) there equal in functionality. Cell should not try to duplicate what already has alot of mindshare and buy-in from the community.
Cell should be:
Currently, Cell's are loaded and added in the same context as the rest of the page.
Although most cases won't, there is the opportunity for Cell's to break encapsulation and cause some head scratching problems (why didn't my Cell render/behave the same way):
These problems could be remedied by using...
HTML5 IFrame's @Seamless/@sandbox
http://www.w3.org/TR/2010/WD-html5-20100624/author/the-iframe-element.html#attr-iframe-seamless
http://www.w3.org/TR/2010/WD-html5-20100624/author/the-iframe-element.html#attr-iframe-sandbox
HTML5 Style's @Scoped
http://www.whatwg.org/specs/web-apps/current-work/multipage/semantics.html#attr-style-scoped
There are cases where frequent cell rendering is required.
http://github.com/peterwmwong/headsup/issues/closed#issue/2
... or large cell templates.
The resolution for the above issue required a change in APP using cell... I think CELL should be able handle this. Less worries for app writers.
Using requestAnimationFrame
as a nextTick
alternative was a poor performance choice.
http://jsperf.com/setimmediate-test/8
We should try to use setImmediate
, fallback to postMessage
, otherwise use setTimeout
.
beforeRender: ->
@collection = new Collection()
render: (_)-> [
'Before'
-> @collection.map (item)-> item.get 'name'
]
afterRender: ->
@collection.add name: 'YOLO'
Unfortunately, this'll end up rendering 'YOLOBefore' instead 'BeforeYOLO'. :(
I think the condition on...
Line 120 in 0de9a65
See commit: d226167
__.if()
and __.each()
are unnecessary API's adding bloat that can easily be expressed as general binds.
__.each
equivalence_.each aCollection, (item)->
-> aCollection.map (item)->
__.if
equivalence_.if (-> @model.get 'condition'),
then: -> 'yes'
else: -> 'no'
-> if @model.get 'condition' 'yes'
else 'no'
Input and Output.
Takes a Collection input and outputs another Collection. Can be used for any type of transformation like, but not limited to: filtering, sorting, mapping, and reducing.
It allows for *nix style pipeing of data:
# *nix piping
> collection | Filter | Sort | Page
# cell/Collection piping
collection.pipe Filter(), Sort(), Page()
A Pipe can either be simple or incremental.
Just a function.
# Simple passthrough pipe
passthrough = (input)-> input.toArray()
For large, high performance, and active collections.
A pipeline of simple pipes can be very costly calculate. And when a collection changes (add, remove), starting from scratch and executing each pipe could make it piping impractical if changes occur frequently and/or the collection is large.
Incremental pipes to the rescue.
If the input collection changes (add,remove), the first pipe is notified and can choose to operate on just the small subset that has changed. This may or may not effect it's output. If no changes are made to first pipe's output, then no other downstream pipe's are notified. If there changes are made, the next pipe is notified of only the changes. Thus only the minimal amount processing is done.
# Passthrough Incremental Pipe
Passthrough = Pipe.extend
constructor: (options)->
# You can listen to changes to option values using spy.watch() and change the output as necessary
# Ex. Filtering of list changes based on user input
spy.watch @, options.option1, -> # Do stuff
onReset: -> @output.reset @input
onAdd: (item, index)-> @output.add item, index
onRemove: (item, index)-> @output.remove index
# Used in a view...
require('cell/defineView!')
render: (_)-> [
# User input can change options watched by an Incremental Pipe
_ 'textarea', (x_model prop:'filterOption1', model:@)
# Smart Pipes can be passed an options hash
_.each (inputCollection.pipe Passthrough option1:-> @get 'filterOption1'), (item)->
# Render item
]
As Object.observe()
seems imminent, we should consider leveraging this to allow for non-{Model/Collection/Resource} access to be watched.
ChangeSummary seems to provide a nice API ontop of Object.observe()
and polyfill for environments that don't have Object.observe
.
https://github.com/rafaelw/ChangeSummary/tree/master
Common code flows (from View and Ext) have come up when using spy.watch...
This causes the client code of spy.watch to declare dependencies on 'cell/util/fn' and 'cell/util/hash'.
The above should come for free and API should be:
spy.watch( context:any, watchFnOrValue:any, callbackFn:function )
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.