oj
Version:
A unified templating language for the people. Thirsty people.
998 lines (708 loc) • 28.4 kB
Markdown
.plan
=====
Need
-------------------------------------------------------------------------------
### Bugs
* GO THROUGH ALL EXAMPLES FOR JS / CS
* Make sure all ids on headers make sense
* JS and CS buttons do not toggle all editors
* First load of TryEditor looks horrible
* website docs figure out what is missing
* website docs add live examples
* Remove sandbox?
* DOCS need to spacing on links for code anchors
Document jQuery ojAppend oj
### Website
* website learn page
* Top spacing to show header off #anchor-tag
* create js
* advanced css
* media query
* Binding List to model
* Binding table to model
* Creating a Type
* Creating a ModelType
* Creating a CollectionType
* Download page should say stuff=)
Want
-------------------------------------------------------------------------------
### Objects
* Try to shrink the size of oj.js by 50%
* Perf test OJ and then speed up HTML/CSS creation, and DOM manipulation
* Add oj to jsfiddle.net as includable library
* Add oj and plugins to one of the open source CDN (http://cdnjs.com/)
* JSFiddle doesn't work in anything but chrome
(this is jsfiddle.net bug)
* Bug: Literal notation should not require object at start. Use argumentsUnion (improves OJML examples)
* Commandline: Add --html option to build only the html (no js)
* Commandline: Add --js option to build on .js file
* Commandline: Add --css option to build on .css file
* Validation on form elements
validate:(value) ->
if value blasjdf
return 'failure message'
TextBox '2062189935', validate:oj.validPhoneNumber((err)-> if err alert('error happened'))), validate
* Bug: Fix .on handlers in attribute events (multi argument event bindings)
* Bug: Allow tags to take html snippets: oj.div('<u>underlined stuff</u>')
* Allow css to take raw css for plugins
* Feature: Consider adding Events to objects
* Feature: Compile.ojlc files as literate coffee-script
* GoogleChart plugin
* Area (P1)
* Bar (P1)
* Bubble (P1)
* Candlestick (P2)
* Column (P2) -- Fancy Bar Chart
* Combo (P1)
* Guage (P3)
* Geo (P1)
* Line (P2)
* Pie (P1)
* Timeline (P1)
* TreeMap (P1)
* Trendlines (P2)
* Table (P2)
* Scatter (P1)
* Google Analytics plugin
* Google AdWords plugin
* Create enums
* Consider event support on oj.Types
* Bootstrap Plugin
* Add concept of defaultThemes to Types
oj.Bootstrap.Button (P1)
oj.Bootstrap.BulletList (P1)
oj.Bootstrap.NumberList (P1)
oj.Bootstrap.List (P1)
oj.Bootstrap.InlineList (P1)
oj.Bootstrap.Table (P1)
theme:['striped', 'hover']
oj.Bootstrap.HorizontalDivider
...
* oj.Page
* Figure out page navigation and virtual page navigation
- Can I navigate to foo/bar, where bar transitions rather then refreshes?
- Triggering off of URL
- may require manual requiring of pages that can be transitioned to
* Should interface with oj.load
* Should interface with commandline tool to prepackage loadable pages
* oj.Grid (consider how this integrates with Boostrap, if at all)
- CSS Grid framework made easy
* oj.Tabs
* oj.Form
* Support form creation and submition with validation
* Consider moving Form elements into this plugin
* oj.Image
* Consider if
* oj.SpriteImage
* Support positioned sprites in background image
* oj.FontImage
* Support images derived from fonts.
* Consider if needs Bootstrap integration
* oj.NGridImage
* Support n grid
* consider support for sprites either in this object or SpriteImage
* oj.Bootstrap.Grid
* oj.Bootstrap.NavBar
* oj.SearchBox (text box + filter list)
* oj.FilterBox (list box + filter list to choose)
* oj.FacebookLikeButton -- embed a Facebook like button
* oj.GooglePlusButton -- embed a GooglePlusButton
* oj.TwitterTweet -- embed a tweet
* Optimization: Look up if _.filter and _.map are implemented in IE9+. Remove if so.
* Optimization: Look up underscore utilities to see if they exist in IE9+. Remove if so
* Optimization: Factor out the two methods needed from path to reduce file size (omit windows specific stuff)
* Unit tests: for build, watch, compile by string
* Unit test for View.removeAttribute and View.removeAttributes
* Write unit tests to verify properties can inherit get and set separately
* OJ static generator: client side unit tests
Like
-------------------------------------------------------------------------------
* oj.GoogleMap
* oj.BingMap
* oj.ScribdDocument
* oj.Region
liquid:true; n grid region with fixed width that grows with content
liquid:false; n grid region with fixed width and height. Supports layers of images
- consider horizontal region, vertical region
- consider grid related regions
- consider Row, Column as namings. (dynamic grid stuff?)
* Linked plugin doesn't recompile with watch enabled
* Bug: .json file type doesn't get sent to the client correctly in .oj and .ojc files
Questions
-------------------------------------------------------------------------------
Server-side Thinking
===============================================================================
Usage: oj [options] <file> <dir> ...
Options:
-h, --help output usage information
-V, --version output the version number
-m, --minify Turn on minification (default: false)
-w, --watch Turn on watch mode (default: off)
-r, --recurse Recurse into directories (default: off)
-o, --output <dir> Directory to output all files to (default: .)
-v, --verbose <level> Turn on verbose level 0-3 (default: 1)
-e, --exclude <modules> List of modules to exclude (jquery,oj,...)
Output Options:
--unify Output html/css/js into a single .html file
--html Output only the html
--css Output only the css
--js Output only the js
--js-modules Output the modules.js file
Path Options:
--modules-dir Directory to find modules.oj or modules.ojc
--html-dir
--css-dir
--js-dir
oj . foo --output www/ --jsdir foo/scripts --cssdir foo/styles --output-module foo/scripts/modules.js
--js Output .js files only
--js-modules Output modules.js that includes js (modules only)
--js-pages Output js pages
require
oj
jquery
modules
--script <dir>
--style <dir>
--module <dir>
Events
------------------------------------------
thingy = Thingy({
// Will bind on('inserted', fn)
events:{
// This is automatically bound when insertions happen
inserting:function(){
},
'inserted':function(){
}
}
thing.inserted.on(function(){
})
})
thingy.trigger('foobar:bar')
thingy.on('click', function(){})
thingy.off(fn)
thingy.one(function(){})
Questions on Versions
------------------------------------------
Go core or not?
Pros:
Illusion of smaller
Form, List and Table can evolve seperately
Cons:
Breaks compatability
Harder to get started
Almost everyone will need Forms and List for complex things
Work
Separate Form, List, Table
Add placeholder for Form, List, Table that when executed throws warning module is missing
0.2.0
Rewrite in JS
0.2.1
load event on tag functions
0.2.2
oj command - Build unified files
------------------------------------------------------------------------------
--unify
oj command - Build full website
------------------------------------------------------------------------------
Build a static website with enough configuration to make it structured however you want.
Reuse options that express needs
/
index.oj -> index.html and pages/index.js
modules.oj
modules/
modules.oj -> will convert to modules.js
pages/
index.js
login.js
blog/
index.js
scripts/
test.js
test.oj -> will convert to test.js
styles/
test.oj -> will convert to test.css
Pick a directory
--modules
--modules-output-dir
oj express - Build full website
------------------------------------------------------------------------------
app.use(oj.middleware({
modulesInDir:__dirname + "/modules",
modulesOutDir:__dirname +
minify: false
}))
Form Validation
-------------------------------------------------------------------------------
CreditCardTextBox
PhoneNumber
credit card
inList: (list) -> (v, prop) -> if not list?.indexOf? or list.indexOf(v) == -1 then "#{prop}: #{v} is not in list: #{list}"
inEnum: (enumList) -> (v, prop) -> if not enumList?.indexOf? or enumList.indexOf(v) == -1 then "#{prop}: #{v} is not in enum: #{enumList}"
range: (min, max) -> (v, prop) -> if v < min or max < v then "#{prop}: #{v} is not in range: [#{min}, #{max}]"
min: (min) -> (v, prop) -> if v < min then "#{prop}: #{v} is too small for min: #{min}"
max: (max) -> (v, prop) -> if v > max then "#{prop}: #{v} is too large for max: #{max}"
lessThan: (num) -> (v, prop) -> if v >= num then "#{prop}: #{v} is too large for lessThan: #{num}"
moreThan: (num) -> (v, prop) -> if v <= num then "#{prop}: #{v} is too small for moreThan: #{num}"
lengthRange: (min, max) -> (v, prop) -> if not v?.length? or v.length < min or max < v.length then "#{prop}: #{v}.length is not in range: [#{min}, #{max}]"
lengthMin: (min) -> (v, prop) -> if not v?.length? or v.length < min then "#{prop}: #{v}.length is too small for min: #{min}"
lengthMax: (max) -> (v, prop) -> if not v?.length? or v.length > max then "#{prop}: #{v}.length is too large for max: #{max}"
lengthLessThan: (num) -> (v, prop) -> if not v?.length? or v.length >= num then "#{prop}: #{v}.length is too large for lessThan: #{num}"
lengthMoreThan: (num) -> (v, prop) -> if not v?.length? or v.length <= num then "#{prop}: #{v}.length is too small for moreThan: #{num}"
Advanced Control thinking
-------------------------------------------------------------------------------
View
el
Core
Form
values # readwrite, map from element key to value
elements # map from element key to OJ instance (readonly)
submit() # submit the form
reset() # reset all elements
clear() # clear all elements
Form
FormView
clear()
reset()
validate:->
Button
type: 'submit' # Can be submit, reset, or null.
# It will bind submit and reset automatically
CheckBox
value: true/false
TextBox # Edit box
TextArea # Big area text box
ListBox # Pull down list box
FilterBox # Multi select. http://rmm5t.github.com/jquery-flexselect/
PasswordBox # Text box wit1h type:'password' set.
Button # Button
ResetButton # Helper button that automatically resets the form
SubmitButton # Helper button that automatically calls submit
CreditCardBox # (P3)
PhoneNumberBox # (P3)
RichTextBox
SearchBox # Like filter but uses ajax
Need
Form.TextFilterBox # Text + List box. Typing filters
Tabs
Image
ToolTip # Built in to all controls?
Form.FileBox # File upload + drag and drop
Want
Watch should trigger off of changes to required files (partials, templates)
This is pretty hard. Possibly watching triggers watching deeply as require is called
LightBox # Pop with screen darkening
Calendar
Form.DateBox # w/Calendar popup
Form.CreditCardBox
Form.ProgressBar
Form.SliderBar
Google.Maps # Hard but so important
Google.Plus.FollowMe
Facebook.LikeMe
Facebook.FollowMe
Twitter.FollowMe
Twitter.FollowCount
GitHub.FollowCount
GitHub.Repo
Like
CollapsiblePanel
ColorPicker
Rating # Star rating
Docking # Drag targets for elements, so hard
DragAndDrop # So hard... probably just go with jquery
ImageSlider # http://dev7studios.com/nivo-slider/#/support
Grid # Display grid to help designers.
ZoomBox # http://www.mind-projects.it/projects/jqzoom/demos.php#demo1
TreeMenu
Button
Input
TextArea
SubmitInput
Table id
-> inserted in the dom
$el awakens it
Table id dom fragment
Bootstrap thinking
-------------------------------------------------------------------------------
oj.use require(oj-bootstrap), global:true
oj.Bootstrap.Table
theme:['striped', 'hover']
oj.Bootstrap.Button
DropDownButton
size: large,small, mini
SplitButton
Tabs
add ->
Bootstrap.Tab 'Name', href:'#fooaction'
remove
get(3).disabled = true
move
Pills
add ->
Bootstrap.Pill 'Name', href:'#fooaction'
remove
move
disable(3)
enable(3)
NavList // have to think about headers
HorizontalDivider
TabbableNav
direction: 'left', 'below', 'above', 'right'
NavBar
position: 'fixed-top', 'fixed-bottom', 'static-top'
responsive: true
inverse: true
NavBrand
NavLink
NavVerticalDivider
NavForm
NavSearchBox
NavButton
align: 'left', 'right'
NavDropDown alias NavListBox
Breadcrumbs
Pagination
Pager
Label 'default', 'success', 'warning', 'important', 'info', 'inverse'
Badges 'default', 'success', 'warning', 'important', 'info', 'inverse'
Hero
PageHeader
Thumbnail span:4, image: 'foo.bar.js'
Alert
ProgressBar
theme:'default', 'basic', 'striped', 'animated', 'stacked', color:'warning'
MediaObject
MediaList
Well
Icon
Div
align:'left', 'right', 'center'
emphasis: 'warning', 'muted', 'error', 'info', 'success'
Abbreviation
title:'full text', short text
address
blockquote
BulletList
NumberList
List (unstyled)
InlineList
Code
Model thinking
-------------------------------------------------------------------------------
Table
inherits: CollectionView
each: (model) ->
rows: [list of lists of ojml] (readwrite)
row: (r) ->
[list of oj or element] (readwrite)
cell: (r,c) ->
oj or element (readwrite)
cellCount (readonly)
rowCount (readonly)
methods:
addRow(index)
removeRow(index)
make creates <table> empty
internals:
on change doesn't matter because the row / cell will do it
on add -- uses each to add a thing
on remove -- closes handlers on cells, row, and deletes row
Table.Row
inherits: ModelView
make: ->
tr ...
model: bind a model
each: (model)->
[list of ojml]
row: ->
get/set row all at once
cell: (c) ->
oj or element
cellCount (readonly)
addCell: (c) ->
removeCell: (c) ->
Layout Thinking
-------------------------------------------------------------------------------
Page
scripts
styles
title
body: ->
Layout OneQuarterRight,
small: ->
large: ->
body ->
GG columns:[25,75],
header: ->
first: ->
second: ->
third: ->
fourth: ->
fifth: ->
left: ->
middle: ->
right: ->
footer: ->
<button class:'oj-Button'>
Layout columns: [1/3,1/3,1/3]
engine:'gg'
engine:'bootstrap'
header:->
left:->
middle:->
right: ->
footer:->
Grid
columnRatios: [1,3]
Layout
left, right, header, footer
Button
-------------------------------------------------------------------------------
image = Image(grid:{n:1,2})
image: forState:
:normal
:selected
:hover
:depressed
TextTheme
RegionTheme
image
nine grid
nw,n,ne
sw,s,se
Mixin
-------------------------------------------------------------------------------
Mixin - Link Colors:
style = require('oj-style-link-colors')(normal, hover, active, visited, focus)
Mixin - Link Hover: oj.css require('oj-css-link-hover')()
Mixin - Compass CS3 support
http://compass-style.org/reference/compass/css3/
Special Tags
.scripts
type: 'foo' // optional
list // list of script paths
.styles
type: 'foo' // optional
list // list of css paths
.link
url: // same as href
label: // text being displayed
.H1 to .H6
anchor: // wraps in anchor with this name
.Row // Panel designed to seperate stuff vertically
// inherits from Panel
.Column // Panel designed to seperate stuff horizontally
.Row []
.Link
Model-Each strategy
div ->
Table models:models, each: (model) ->
[Checkbox model:model, key:'male', 3, new Date()]
div ->
List ordered:false, models:models, each: (model) ->
a -> model.name
Argument strategy
div ->
Table ->
for model in models
argument ->
[(Checkbox model:model, key:'male'), 3, -> (div 'asdf')]
Table models:models, each: (model, col, row) ->
row ->
col ->
Checkbox model:model, key:'male'
col ->
div 'asdf'
Table models:models, each: (model, col, row) ->
row ->
col ->
Checkbox model:model, key:'male'
col ->
div 'asdf'
List models:models, each: (model, item) ->
model.name
Documentation
==========================================================================
OJ Download Learn Docs Plugins Express Blog
OK, I'm here. What is OJ?
--------------------------------------------------------------------------
OJ is a JavaScript library that helps you create websites with objects. For example the oj.Button object makes buttons and the oj.YouTubeVideo object makes -- wait for it -- YouTube videos!
(YouTubeVideo)
These objects create their own html and JavaScript event bindings so they _have no depedencies_. Simply include them with the package manager of your choice (npm or bower) and they will _just work_:
That sounds cool. Who is this for?
--------------------------------------------------------------------------
OJ is best used server-side with Express. It uses npm as a package manager even will gather and minify your modules together so they can run client-side seamlessly. If you love trying out template engines like Jade, Less, or CoffeeCup, OJ is going to impress you.
(Get started with Express)
For static pages there is an [oj commandline tool]() that will watch, compile, and minify everything for you in a similar way the Express support does.
(Get started with commandline)
For those folks wanting just client-side just `<script>` include oj.js.
(Get started with client-side)
What does the core oj.js library include?
--------------------------------------------------------------------------
The library gives you objects to create form elements: [oj.TextBox](), [oj.Button](), [oj.ListBox](), [oj.CheckBox](), as well as other basic tags: [oj.NumberList](), [oj.BulletList]() and [oj.Table](). In addition the core library handles compiling html/css (server side) and dom creation and event binding (client side). Lastly you can create your own objects with the [oj.createType]() function, and at its lowest level lets you create html tags directly with [tag functions]().
(example of a table of form elements?)
What plugins exist so far?
--------------------------------------------------------------------------
Check out the full list here: [ojjs.org/plugins.html](ojjs.org/plugins.html).
Really, OJ plugins can do almost anything that is useful. One of my favorites is oj.markdown:
(markdown)
I'm afraid to ask... is OJ an MVC framework? =)
--------------------------------------------------------------------------
No it isn't! OJ is just the _View_ layer, and nothing else. It doesn't make Models or Controllers. In fact, there is no reason OJ couldn't be used as the rendering layer for actual MVC frameworks, especially the ones still using mustache templating!
That said, OJ does support two-way binding to Backbone Models and Collections. The reasoning behind this is a good View needs to be able to update as data changes. Backbone seemed a good choice to support right away, but there is no reason an adaptor couldn't be written to support other model systems.
Take a look at these form elements bound to a Backbone model. Changing one changes them all!
(Backbone binding example)
The Apocalypse is Nigh!
--------------------------------------------------------------------------
That isn't a question, but I understand where you are coming from=). In my quest to make websites with objects OJ had to do _a lot_ more with JavaScript then people usually do. Since this is all server-side and in many cases can even be pre-compiled I think of OJ as more of templating engine with cool objects you can add to your page. JavaScript is just the medium, but it is no different from other templating engines like Jade or Less before it.
I'm sold, what do I do next?
--------------------------------------------------------------------------
The best way to start depends on what you want to do:
Get started with Express in JavaScript or CoffeeScript
Get started with making a static site with the CLI tool in JavaScript or CoffeeScript.
Get started client-side in JavaScript.
Note: OJ was written in JavaScript but was designed with CoffeeScript syntax in mind. It is great in both.
Contact Info
--------------------------------------------------------------------------
IRC: [freenode.net#oj](http://webchat.freenode.net/?channels=oj)
Email: [evan@ojjs.org](mailto:evan@ojjs.org)
Twitter: @evanmoran
Repo: github.com/ojjs/oj
# How To Create a Static Website with the OJ CLI Tool
OJ has a [commandline tool](http://ojjs.org/docs.html#commandline) that can build OJ server-side. This will get you started:
## Installing Commandline Tool
(1) Install node
(2) Install the `oj` commandline tool with npm:
npm install -g oj
(3) Install the `yeoman` tool:
npm install -g yeoman
(4) Install the Yeoman `generator-oj` tool:
npm install -g generator-oj
(5) Create your project using Yeoman:
yo oj:static
(6) Use to OJ CLI tool to build your static website!
oj . --minify --watch
Note: the OJ tool traverses through `require` includes and unifies all files together. It can inculde node modules such as `underscore`, `backbone`, etc, the same way. These will be picked up from your `package.json` file as you would expect. In addition, it can minify with `--minify` or watch with `--watch` options set.
Bootstrap Implementation
===============================================================================
Tag Magic
-------------------------------------------------------------------------------
hidden:['xs','sm','md','lg'] // adds hidden-xs
visible:['xs','sm','md','lg'] // adds visible-xs
emphasis:'danger' // adds text-danger
labelText: 'foo' // appends _label
badge:5 // appends _badge
pull: 'left' // adds pull-left
align: 'left' // adds text-left
tooltip: everything should support the full tooltip system. When inserted the event should be bound
The general kind
BSNavBar
BSNavForm
BSNavDropdown
BSNavHeader brand:'Foo', brandHref:'#', srOnly: true
BSPills
base: BSNavs
stacked:true
BSPill
active:true
href:#
disabled:true/false
BSDropdown
BSItem()
BSDivider()
BSItem()
BSDropdown(
_BSItem('Text', {href:'#'}), {divider:{}}]
BSTabs
base: BSNavs
justified:true
BSTab
active:true
href:#
disabled:true/false
BSDropdown(
BSItem('Text', href:'#')
bsDivider(),
)
BSBreadCrumbs
BSBreadCrumb
active:true
href:#
BSTable
BSProgressBar
BSList
BSDropDown
BSNavBar
Bootstrap.panel
-------------------------------------------------------------------------------
// <div class="panel panel-danger">
// <div class="panel-body">
// Panel content
// </div>
// <div class="panel-footer">Panel footer</div>
// </div>
Bootstrap.panel({danger:true}, function(){
Bootstrap.panelHeader('')
Bootstrap.panelBody(function(){
})
Bootstrap.panelFooter()
})
Bootstrap alignment: left,right,center
-------------------------------------------------------------------------------
// <h1>h1. Bootstrap heading <small>Secondary text</small></h1>
// <h2>h2. Bootstrap heading <small>Secondary text</small></h2>
h1('h1. Bootstrap heading ', _small('Secondary text'))
h2('h2. Bootstrap heading ', _small('Secondary text'))
// <p class="text-left">Left aligned</p>
// <p class="text-right">Right aligned</p>
// <p class="text-center">Center aligned</p>
p({textLeft:true}, 'Left aligned')
p({textRight:true}, 'Right aligned')
p({textCenter:true}, 'Center aligned')
Bootstrap colors: primary, success, info, warning, danger, muted
-------------------------------------------------------------------------------
// <p class="text-primary">primary text</p>
// <p class="text-success">success text</p>
// <p class="text-info">info text</p>
// <p class="text-warning">warning text</p>
// <p class="text-danger">danger text</p>
// <p class="text-muted">muted text</p>
p({textPrimary:true}, 'Primary text')
p({textSuccess:true}, 'Success text')
p({textInfo:true}, 'Info text')
p({textWarning:true}, 'Warning text')
p({textDanger:true}, 'Danger text')
p({textMuted:true}, 'Muted text')
Bootstrap code
-------------------------------------------------------------------------------
// <pre><p>Sample text here...</p></pre>
// Alias code to pre
Bootstrap.code("<p>Sample text here...</p>")
Bootstrap grid: row/col/ with sizes and offset/pull
-------------------------------------------------------------------------------
// <div class="row marketing">
Bootstrap.row(c:'marketing', function(){
// <div class="col-lg-6 col-md-3">
// <h4>Subheading</h4>
// <p>Donec id elit non mi porta gravida at eget metus. Maecenas faucibus mollis interdum.</p>
// </div>
// <div class="col-lg-6 col-md-3">
// <h4>Subheading</h4>
// <p>Donec id elit non mi porta gravida at eget metus. Maecenas faucibus mollis interdum.</p>
// </div>
Bootstrap.col({lg:6, xs:3}, function(){
h4('Subheading');
p('Donec id elit non mi porta gravida at eget metus. Maecenas faucibus mollis interdum.');
});
Bootstrap.col({lg:6, md:4, sm:2, xs:3, xsOffset:3, mdOffset:4, mdPush:4, mdPull:5}, function(){
h4('Subheading');
p('Donec id elit non mi porta gravida at eget metus. Maecenas faucibus mollis interdum.');
});
});
Bootstrap.footer
-------------------------------------------------------------------------------
Bootstrap.footer(function({
p("© Company 2013")
}))
});