Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Manipulate DOM models like they're ActiveRecord models.

branch: master

Fetching latest commit…

Octocat-spinner-32-eaf2f5

Cannot retrieve the latest commit at this time

Octocat-spinner-32 dist
Octocat-spinner-32 src
Octocat-spinner-32 test
Octocat-spinner-32 Readme.md
Octocat-spinner-32 grunt.js
Readme.md

Jewel

Operate with DOM elements like they're ActiveRecord models.

Features

  • DOM elements as models
  • CRUD methods you are already used to
  • Validation (built-in rules + ability to set custom ones)
  • No additional dependencies (except of jQuery, which, I guess you already have)

Getting Started

Dependencies

  • jQuery

Compatability

  • Safari
  • Google Chrome
  • Firefox
  • Opera
  • IE - not tested

Include Jewel (2.8kb minified and gzipped):

<!-- jQuery must be included before that -->
<script src="jewel.min.js"></script>

Usage

Let's say we have such HTML:

<div id="posts">
    <div class="post">
        <h1>First title</h1>
        <p>First body</p>
    </div>
    <div class="post">
        <h1>Second title</h1>
        <p>Second body</p>
    </div>
    <p class="not-found">
        No posts here, sorry.
    </p>
</div>

Now, we need to define Post model:

class Post extends Jewel.Model
    @view 'container', selector: '#posts' # selector for a container view
    @view 'empty', selector: 'p.not-found' # selector for a view, that shows up only when there is no posts

    @key 'title', selector: 'h1' # selector for a title, h1 in our case. Will be used as #posts div.post h1
    @key 'body', selector: 'p' # selector for a body. Will be used as #posts div.post p

    @template 'default', (fields) ->
        "<div class='post'><h1>#{ fields.title }</h1><p>#{ fields.body }</p></div>"

Post = Jewel.Model.setup Post

That's it! We can start doing cool stuff:

# Finding all posts
posts = Post.all

# Finding first post
post = Post.find(limit: 1)[0]

# Finding second post
post = Post.find(skip: 1)[0]
post.title # "Second title"

# Updating a post
post.title = 'Last post'
post.save()

# Removing a post
post.remove()

# Removing all posts
Post.remove()

# Creating a new one
post = new Post
post.title = 'Latest post'
post.body = 'Latest content'
post.save() # will be prepended to #posts

Events

You can listen to events which are emitted by all instances of the model:

Post.on 'create', (post) ->
    post.title is 'Post title' # true

post = new Post
post.title = 'Post title'
post.body = 'Post body'
post.save()

Available events: create, update, remove and save (fires on create and update events too).

Hooks

Jewel offers ability to define hooks to listen to events on per-model basis:

class Post extends Jewel.Model
    @view 'container', selector: 'div.posts'
    @view 'empty', 'p.not-found'

    @key 'title', selector: 'h1'
    @key 'body', selector: 'p'

    @template 'default', (fields) ->
        "<div class='post'><h1>#{ fields.title }</h1><p>#{ fields.body }</p></div>"

    beforeSave: ->
        @title # value of model's title field

Post = Jewel.Model.setup Post

Available hooks (for save, create, update and remove): before, around, after. For example, beforeSave, aroundRemove or afterUpdate.

Transports

Jewel can also transport your data to one or more destinations. You need to specify which transports you would like to use and Jewel will do the rest:

class Post extends Jewel.Model
    # other typical parameters

    @transport 'local', primary: yes
    @transport 'session'

Post = Jewel.Model.setup Post

Note: you should include transports you would like to use:

<script src="transports/local.min.js"></script>
<script src="transports/session.min.js"></script>

Making your own transports

Here is the skeleton of your own transport:

class MyTransport
    constructor: (@model) -> # model class

    identifier: 'my' # identifier of your transport

    @isAvailable: -> yes # detect if transport is available

    fetch: (callback) -> # fetch data from storage and do a callback(data)

    create: (model, callback) -> # get field data in model.fields

    update: (model, callback) ->

    remove: (model, callback) ->

    removeAll: (callback) ->

Jewel.Transports.register 'my', MyTransport # register your transport

If one of the transports is not available in browser, it will be ignored and no errors will be throwed.

Tests

Run tests by opening test/test.html in browser.

Contributing

  • Fork
  • Write code, build using grunt
  • Write tests for the code
  • Commit & push
  • Send pull request

Roadmap

  • Sync with server

License

(The MIT License)

Copyright (c) 2011 Vadim Demedes sbioko@gmail.com

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Something went wrong with that request. Please try again.