pencil

Custom tags/components for Jade. Extend, mixin and inherit.


version 0.1.4 (testing) - History

Pencil

Are you working with Jade? Do you want to make custom tags? Pencil is built on top of Jade to add extra features:

  • Create custom tags
  • Use jquery like functions to manipulate tags
  • Bootstrap support (not yet)
  • Extends Jade's include and extends

Install this using npm as follows

$ npm install pencil
var http = require('http')
  , fs = require('fs')
  , pencil = require('pencil')
  ;
 
http.createServer(function (reqres) {
  
  var path = __dirname + '/text.jade'
    , str = fs.readFileSync(path, 'utf8')
    , fn = pencil.compile(str, { filename: path, pretty: true })
    ; 
  
  res.writeHead(200, { 'Content-Type': 'text/html' });
  res.end(fn({}));
  
}).listen(3000);

Supports Express 2.x and 3.x

var express = require('express')
  , pencil = require('pencil')
  ;
 
var app = express.createServer();
 
app.configure(function(){
  app.use(pencil.adapter.express(express, app));
});
 
app.get('/', function(reqresnext){
  res.render('text.jade', {
    layout: false
  });
});
 
app.listen(3000);

Pencil configures your Express server with defaults:

  • *.jade files are associated to the Jade parser
  • views are located in the ./view folder of your project

To use your own configuration:

app.use(pencil.adapter.express(express, app, {
  views: '/path/to/my/views'  // optional 
}));

Pencil extends a few html tags to have default attributes.

html
// <html lang='en'></html>
favicon
// <link href='/favicon.ico' type='image/x-icon' rel='shortcut icon' />
 
favicon(href='/image.ico')
// <link href='/image.ico' type='image/x-icon' rel='shortcut icon' />
head
  style(href='/style.css')
// <head>
//   <link href='/style.css' type='text/css' rel='stylesheet' />
// </head>
 
style
// <style type='text/css'></style>
script
// <script type="text/javascript"></script>
 
script(src='/script_path')
// <script type="text/javascript" scr="/script_path"></script>
form(action='/action_path')
// <form type='post' action='/action_path'>
//   <input type='hidden' name='_method' value='post' />
// </form>
 
form(method='put',action='/action_path')
// <form type='post' action='/action_path'>
//   <input type='hidden' name='_method' value='put' />
// </form>
 
// Alias
form:get
form:post
form:put
form:del
input
// <input type="text" />
 
// Alias
input:button
input:checkbox
input:file
input:hidden
input:image
input:password
input:radio
input:reset
input:submit
input:text
button
// <button type="button"></button>
 
// Alias
button:submit
button:reset

FROM NOW ON THE DOCUMENTATION IS NOT READY YET

The main purpose of Pencil is to build custom tags. Using Bike this comes very easy.

/example.jade

foo:box
// <div class='box'>Title Undefined</div>
 
foo:box(title='This is a box')
// <div class='box'>This is a box</div>

/foo/box.js

var Pencil = require('pencil');
 
Pencil.define('foo.box', {
 
  initializefunction(){
    var self = this
      ;
    
    this.tag
      .tag('div')
      .addClass('box')
      .html(this.title || 'Title Undefined')
    ;
  },
  
  renderfunction(){
    return this;
  }
  
});

First you need to define a namespace.

Pencil.ns(__dirname + '/foodir');

The above code will look in the given directory for a file named namespace.json, the configuration of your namespace.

Attributes of the json file are:

  • name: [string] tells Jade's syntax to search any tag starting with the prefix name:* in the /foodir directory.
  • nameAlias: [string] alias for the name
  • alias: [object] key/value of alias for your custom tags used as shortcuts
foo:panel(title='Hello World')

This for examples searches the file /foodir/panel.js.

Optionally you could set your namespace as default to avoid the use of the prefix

Pencil.ns(__dirname + '/foodir', true);

Now you could do this:

panel(title='Hello World')

Every given attribute will be passed to the custom tag object.

Additionals elements in the tag name will be considered as subdirectories

foo:container:panel:header
=> /foodir/container/panel/header.js

/foodir/container.js

var Pencil = require('pencil');
 
Pencil.define('foo.container', {
 
  initializefunction(){
    var me = this;
    
    this.tag
      .tag('div')
      .html('Hello World')
  },
  
  renderfunction(){
    return this;
  }
  
});

Now inside your control you have the variable this.tag, this is the Jade Tag Object that you can manipulate as you like with the below functions (Extended Tag Object)

foo:container
=> <div>Hello World</div>

Since Pencil uses Bike it very easy to extend your custom controls

/foodir/panel.js

var Pencil = require('pencil');
 
Pencil.define('foo.panel', {
  
  extend: 'foo.container',
  
  initializefunction(){
    this._super.apply(this, arguments);
    
    this.tag.addClass('panel');
  }
  
});
foo:panel
=> <div class='panel'>Hello World</div>

For working and complex examples take a look at the /namespaces folder.

Jade's Tag object is extended with more methods to manipulate it in a jQuery like style.

This is very usefull when building custom controls or filters

  • isTag
  • sanitize
  • getName
  • tag
  • is
  • attr
  • getAttr
  • setAttr
  • removeAttr
  • attrToObj
  • css
  • addClass
  • removeClass
  • toggleClass
  • hasClass
  • append
  • appendTo
  • clone (*)
  • remove
  • prepend
  • prependTo
  • insertAfter
  • insertAfterTo
  • insertBefore
  • insertBeforeTo
  • show
  • hide
  • replaceWith
  • hasChilden
  • children
  • empty
  • clear
  • html
  • wrap
  • unwrap
  • wrapAll
  • wrapInner
  • include
  • extends

If you set the variable Pencil.root with a path this will be helpful when using include and extends.

Pencil.root = '/root';

With Pencil your could include an external navbar.jade like this;

include user/navabar@repos/hello

The above code will try to include the file /root/repos/hello/view/user/navbar.jade.

The same works for extends

Install dev dependencies and make tests:

$ npm install -d
$ make test
Gabriele Di Stefano <gabriele.ds@gmail.com>

The MIT License