Node.js HTTP(S) server router with JSIN support
JavaScript Other
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
node_modules
public
test
.gitignore
README.md
index.js
jasine.js
logger.js
package.json
server.js

README.md

Jasine

Router for Node.js's HTTP(S) server, calls JS controller and JSIN template using URL.

Basic

Install:

$ npm install jasine

Start test server (examples in node_modules/jasine/test directory):

$ npm test jasine

To stop test server use Ctrl+C.

Live example, where I'm using and testing Jasine server at the moment: kawaiinyan.com.

Start server:

$ node node_modules/jasine/server config.json

Stop server:

$ node node_modules/jasine/server config.json stop

Graceful reload server:

$ node node_modules/jasine/server config.json reload

Kill server:

$ node node_modules/jasine/server config.json kill

Default config:

{
    // Server settings
    "protocol":         "http", // http or https
    "host":             "localhost",
    "port":             8008,
    "socket":           null, // UNIX socket instead of host and port
    "workers":          null, // Default: count of CPUs
    "group":            null, // Default: nobody. Works under root only.
    "user":             null, // Default: nobody. Works under root only.
    "daemon":           false, // In most cases you should set it to TRUE, don't forget to set "pid" and "log" also
    "pid":              null, // Required for stop, reload and kill commands
    "log":              null,
    "logError":         null, // Default: same as "log"

    // Router settings
    "logLevel":         "info", // debug, info, warn, error
    "init":             null, // Module required before server starts (main application module)
    "error":            __dirname + "/public/", // Universal controller for all errors
    // Use errorXXX for specified error code.
    // Example: "error404": "/path/to/error404" will look for /path/to/error404.js and/or /path/to/error404.jsin.
    "dirRoot":          __dirname, // Should be overridden
    "dirPublic":        "public", // Where controllers and templates located
    "dirStatic":        "static", // Where static files located
    "uriStatic":        "/static/", // URL prefix for static files
    "mimeDefault":      "text/html",
    "mimeJSON":         "text/json",
    "charset":          "utf-8"
}

Server side

When you open any URL, Jasine first looks for .js file with same path in public directory:

http://localhost:8008/boo  -> public/boo.js
http://localhost:8008/boo/ -> public/boo/index.js
http://localhost:8008/     -> public/index.js

This .js file should be node module exporting one function:

module.exports = function(request, response, callback) {
    if (1 !== 1) {
        callback(new Error("Something went wrong: 1 !== 1"));
    } else {
        callback(null, {
            boo: "booooo",
            foo: "fooooo"
        });
    }
};

You can pass HTTP error code (404, 403, etc) to first argument of this function, or just throw this code.

callback(404);
// or
throw 404;

Also you can set statusCode of response:

response.statusCode = 404;

Data object, passed in callback, will be passed to JSIN template at same file path, but .jsin extension.

You can override template using property template of data object:

callback(null, {
    template: "overrided_template", // instead of URI + .jsin
    boo: "booooo",
    foo: "fooooo"
});

If .js file was not found at requested path in public dir, next, Jasine will try to load index module in same directory and call exported method with name equal to basename of URL.

For example URL http://localhost:8008/boo: if module public/boo.js not found, Jasine will try to call method boo of module public/index.js:

// public/index.js
module.exports.index = function(request, response, callback) {...}
module.exports.boo = function(request, response, callback) {...}

If method was not found, next, Jasine will look for router method in index module and call this method with basename of URL as additional argument.

For example URL http://localhost:8008/boo: if module public/boo.js not found, method boo in public/index.js not found also, Jasine will try to call method router of module public/index.js:

// public/index.js
module.exports.router = function(request, response, basename, callback) {
    // basename == 'boo'
    ...
}

If method was not found, next, Jasine will look for .jsin file at same path (public/boo.jsin), and call it without data.

If you open URL ending with .json extension, Jasine will look for .js module or appropriate method in the same way as explained above, and response generated data as JSON, without using JSIN template.

http://localhost:8008/boo.json -> public/boo.js or method boo in public/index.js

Client side

To make AJAX requests, include compiled JSIN templates and client side script jasine.js on html page. Call jasine.init at the end of body, or in window onload handler.

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Test</title>
    </head>
    <body>

        <?js contents() ?>

        <script src="/static/jsin.compiled.js"></script>
        <script src="/static/jasine.js"></script>
        <script>
            jasine.init();
        </script>
    </body>
</html>

By default all AJAX requests attached to body element and excludes layout with name layout. You can set defaults, passing object with element and excludeLayout properties as argument to jasine.init method. URI for static files (by default /static/) ignored by Jasine, you can change default using property uriStatic.

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Test</title>
    </head>
    <body>

        <div id="my-main-content">
            <?js contents() ?>
        </div>

        <script src="/static/jsin.compiled.js"></script>
        <script src="/static/jasine.js"></script>
        <script>
            jasine.init({
                element: "#my-main-content",
                excludeLayout: [
                    "myMainLayout",
                    "layouts/additionalMainLayout"
                ],
                uriStatic: "/my_static/"
            });
        </script>
    </body>
</html>

Init method adds onclick handler to all a with href starting with / and any elements with data-href attribute starting with /. The handler will add .json extension to URL and make XMLHttpRequest. Resulting HTML will be generated using JSON response and pre-compiled JSIN templates. Generated HTML will replace inner contents of an element: body by default, or element defined in init method, or element defined in data-element attribute. You can specify element selector "by id" in href attribute, if actual link specified in data-href attribute. Also, data-href attribute has priority over href attribute of a element. In addition, you can specify comma-separated list of layout names to exclude in data-exclude-layout attribute.

<a href="/mypage">
    Will load contents of "/mypage"
    to body or default element
    using "/mypage.json"
</a>

<a href="/mypage2" data-exclude-layout="MyPage2Layout, MyPage2Layout2">
    Will load contents of "/mypage2"
    to body or default element
    using "/mypage2.json"
    excluding layout "MyPage2Layout" and "MyPage2Layout2" while rendering
</a>

<a href="/mypage" data-href="/mypage-priority">
    Will load contents of "/mypage-priority"
    to body or default element
    using "/mypage-priority.json"
</a>

<div id="my-block">
    <a href="/ajax/myblock?boo=123" data-element="#my-block">
        Will load contents of "/ajax/myblock?boo=123"
        to div with id "my-block"
        using "/ajax/myblock.json?boo=123"
    </a>
</div>

<div id="another-block">
    <a href="#another-block" data-href="/ajax/anotherblock">
        Will load contents of "/ajax/anotherblock"
        to div with id "another-block"
        using "/ajax/anotherblock.json"
    </a>
</div>

Clicking a with href starting with / will change history state for "back" button in browser. Clicking elements without href or href starting with # will not change history state. Method jasine.init adds popstate event listener of window to handle history "back" and "forward".

AJAX forms works in same manner as links, but with action and data-action attributes instead of href and data-href. AJAX forms supports next enctype: application/x-www-form-urlencoded, multipart/form-data (with file upload support) and text/json. Forms with method get will change history state if action starts with /. Forms with method post or action starting with # will not change history state.

You can make AJAX request using method jasine.load. This method has one argument - options object:

jasine.load({
    url: '/any_url', // same as "href" or "action"
    dataUrl: '/any_url', // same as "data-href" or "data-action"
    element: '#any-element', // same as "data-element"
    excludeLayout: 'layoutToExclude', // array or string: layouts to exclude, same as "data-exclude-layout"
    post: 'post data', // post data
    postType: 'mime/type', // mime type of post data
    onelementbeforeload: function(event){}, // event listener for "elementbeforeload"
    onelementload: function(event){}, // event listener for "elementload"
    onelementafterload: function(event){} // event listener for "elementafterload"
});

Jasine AJAX requests has three events:

  • elementbeforeload - fires before request.
  • elementload - fires after response received and before HTML and history were changed.
  • elementafterload - fires after response received and HTML and history were changed.

These events has additional properties:

  • options - Jasine options of request.
  • request - current XMLHttpRequest.
  • data - received JSON.
  • error - error occurred during request.

License

Copyright © 2014 Maksim Krylosov Aequiternus@gmail.com

This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.