{"_id":"charlotte","_rev":"25-289aefbeb216367b8fe47cc148826e4e","name":"charlotte","description":"A framework for building mobile web apps using Express and PhoneGap","dist-tags":{"latest":"0.1.8"},"versions":{"0.1.0":{"name":"charlotte","description":"A framework for building mobile web apps using Express and PhoneGap","homepage":"http://danieldkim.github.com/charlotte/","keywords":["express","phonegap","mobile"],"author":{"name":"Daniel Kim","email":"danieldkimster@gmail.com"},"version":"0.1.0","repository":{"type":"git","url":"git://github.com/danieldkim/charlotte.git"},"bugs":{"url":"http://github.com/danieldkim/charlotte/issues"},"licenses":[{"type":"MIT","url":"http://github.com/danieldkim/charlotte/raw/master/LICENSE"}],"dependencies":{"express":"~2.5.6"},"_npmUser":{"name":"danieldkim","email":"danieldkimster@gmail.com"},"_id":"charlotte@0.1.0","devDependencies":{},"optionalDependencies":{},"engines":{"node":"*"},"_engineSupported":true,"_npmVersion":"1.1.0","_nodeVersion":"v0.6.7","_defaultsLoaded":true,"dist":{"shasum":"6e902dcc07ea6a492f3746fbf69edb12429ef9fc","tarball":"https://registry.npmjs.org/charlotte/-/charlotte-0.1.0.tgz","integrity":"sha512-ZfFK5AZ8o4P1PdIsOnixTdu4CW8wCPj/C74J2OepiwIb45VDEtJ6hpNAd9S2UtMnfiKcbjCPQy2mgbLjRr4nnw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDU9NdQ5Ux8dPzwmemlaM8GcyYqXM9yFwf1Yr/Z9FQZ6AIhAPmsBgD+Z6UkVwvfYMGM0sBNXvw2HNDOUkxNRHsz1ftQ"}]},"maintainers":[{"name":"danieldkim","email":"danieldkimster@gmail.com"}],"directories":{}},"0.1.1":{"name":"charlotte","description":"A framework for building mobile web apps using Express and PhoneGap","homepage":"http://danieldkim.github.com/charlotte/","keywords":["express","phonegap","mobile"],"author":{"name":"Daniel Kim","email":"danieldkimster@gmail.com"},"version":"0.1.1","repository":{"type":"git","url":"git://github.com/danieldkim/charlotte.git"},"bugs":{"url":"http://github.com/danieldkim/charlotte/issues"},"licenses":[{"type":"MIT","url":"http://github.com/danieldkim/charlotte/raw/master/LICENSE"}],"dependencies":{"underscore":">=1.3.1","express":"~2.5.6"},"_npmUser":{"name":"danieldkim","email":"danieldkimster@gmail.com"},"_id":"charlotte@0.1.1","devDependencies":{},"optionalDependencies":{},"engines":{"node":"*"},"_engineSupported":true,"_npmVersion":"1.1.0","_nodeVersion":"v0.6.7","_defaultsLoaded":true,"dist":{"shasum":"879d13a72a5be2432c1f2d5ac51383d0f5231f71","tarball":"https://registry.npmjs.org/charlotte/-/charlotte-0.1.1.tgz","integrity":"sha512-REwTgUUu55dXH9nS4orgnxt6c6iPkDbqjT8gcUBa5bRLuSQwUc50HFrlCvEQpsW0t1TPa8E98gfNR11RWBN5+w==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBZX56fFFOjShI5AjnqSMVsFrJB3HqQKENYPAX6JY0DZAiEAxogK54SHxlEpalHnk+AupvdCUp19JUB7Sd3PaDja69c="}]},"maintainers":[{"name":"danieldkim","email":"danieldkimster@gmail.com"}],"directories":{}},"0.1.2":{"name":"charlotte","description":"A framework for building mobile web apps using Express and PhoneGap","homepage":"http://danieldkim.github.com/charlotte/","keywords":["express","phonegap","mobile"],"author":{"name":"Daniel Kim","email":"danieldkimster@gmail.com"},"version":"0.1.2","repository":{"type":"git","url":"git://github.com/danieldkim/charlotte.git"},"bugs":{"url":"http://github.com/danieldkim/charlotte/issues"},"licenses":[{"type":"MIT","url":"http://github.com/danieldkim/charlotte/raw/master/LICENSE"}],"dependencies":{"underscore":">=1.3.1","express":"~2.5.6"},"_npmUser":{"name":"danieldkim","email":"danieldkimster@gmail.com"},"_id":"charlotte@0.1.2","devDependencies":{},"optionalDependencies":{},"engines":{"node":"*"},"_engineSupported":true,"_npmVersion":"1.1.0","_nodeVersion":"v0.6.7","_defaultsLoaded":true,"dist":{"shasum":"6a4262884ff78ccc99dc180329c24923dca67d76","tarball":"https://registry.npmjs.org/charlotte/-/charlotte-0.1.2.tgz","integrity":"sha512-Sma/+fn8wXOl7v0vaSWtuNHzG1ATJR7atoFFgYT2pF4p/i7PVFzdN5fZzB0RFGfXzP51n6bypqUN3u08moleBQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAJ0FaITEw/4zLcdgRVCuOCbmVa8ADRa16OW7tk51kShAiEAusVwOdPR8dzAuzr2ifkjL2l8jhMEXdq7oDXjhgC/d6g="}]},"maintainers":[{"name":"danieldkim","email":"danieldkimster@gmail.com"}],"directories":{}},"0.1.3":{"name":"charlotte","description":"A framework for building mobile web apps using Express and PhoneGap","homepage":"http://danieldkim.github.com/charlotte/","keywords":["express","phonegap","mobile"],"author":{"name":"Daniel Kim","email":"danieldkimster@gmail.com"},"version":"0.1.3","repository":{"type":"git","url":"git://github.com/danieldkim/charlotte.git"},"bugs":{"url":"http://github.com/danieldkim/charlotte/issues"},"licenses":[{"type":"MIT","url":"http://github.com/danieldkim/charlotte/raw/master/LICENSE"}],"dependencies":{"underscore":">=1.3.1","express":"~2.5.6"},"_npmUser":{"name":"danieldkim","email":"danieldkimster@gmail.com"},"_id":"charlotte@0.1.3","devDependencies":{},"optionalDependencies":{},"engines":{"node":"*"},"_engineSupported":true,"_npmVersion":"1.1.0","_nodeVersion":"v0.6.7","_defaultsLoaded":true,"dist":{"shasum":"8244069ef8d947e6addcd34498db696852a5bd71","tarball":"https://registry.npmjs.org/charlotte/-/charlotte-0.1.3.tgz","integrity":"sha512-XE0E6BKnQwjwviFMGHOdOuAAZNIhR4g/OAH/2zOdwFZRjkZQTmTF+kl1khab+kKohJ7Qq0KyJazYDMpeXoHobw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCdlqFdm85ue+JwL8vegF2GIMCA4d7EOGw3hGWTnOXgfAIhAM2e0l2LMA8W7ffeN2W8ivC5SABYsSLb7lgH44hoFLAV"}]},"maintainers":[{"name":"danieldkim","email":"danieldkimster@gmail.com"}],"directories":{}},"0.1.4":{"name":"charlotte","description":"A framework for building mobile web apps using Express and PhoneGap","homepage":"http://danieldkim.github.com/charlotte/","keywords":["express","phonegap","mobile"],"author":{"name":"Daniel Kim","email":"danieldkimster@gmail.com"},"version":"0.1.4","repository":{"type":"git","url":"git://github.com/danieldkim/charlotte.git"},"bugs":{"url":"http://github.com/danieldkim/charlotte/issues"},"licenses":[{"type":"MIT","url":"http://github.com/danieldkim/charlotte/raw/master/LICENSE"}],"dependencies":{"underscore":">=1.3.1","express":"~2.5.6"},"_npmUser":{"name":"danieldkim","email":"danieldkimster@gmail.com"},"_id":"charlotte@0.1.4","devDependencies":{},"optionalDependencies":{},"engines":{"node":"*"},"_engineSupported":true,"_npmVersion":"1.1.0","_nodeVersion":"v0.6.7","_defaultsLoaded":true,"dist":{"shasum":"930961f16e6ae1198ec017cd2beda308386cf8b8","tarball":"https://registry.npmjs.org/charlotte/-/charlotte-0.1.4.tgz","integrity":"sha512-oPM9/SepRDvmtpRd/C5tLT/4iDbhGQKGXdrxqNoXeEMXdwglso2arENpAw5YcCX5r/YFkSWYTE9LbisKBRDexQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHu6zYhJVPs+5bc/NSKymlM9LkiR8bCQRo8qQ+5/upadAiEApbyMifBlF2hUADjoFnJafIxWffqtndhLywT71ArYIaE="}]},"maintainers":[{"name":"danieldkim","email":"danieldkimster@gmail.com"}],"directories":{}},"0.1.5":{"name":"charlotte","description":"A framework for building mobile web apps using Express and PhoneGap","homepage":"http://danieldkim.github.com/charlotte/","keywords":["express","phonegap","mobile"],"author":{"name":"Daniel Kim","email":"danieldkimster@gmail.com"},"version":"0.1.5","repository":{"type":"git","url":"git://github.com/danieldkim/charlotte.git"},"bugs":{"url":"http://github.com/danieldkim/charlotte/issues"},"licenses":[{"type":"MIT","url":"http://github.com/danieldkim/charlotte/raw/master/LICENSE"}],"dependencies":{"underscore":">=1.3.1","express":"~2.5.6"},"_npmUser":{"name":"danieldkim","email":"danieldkimster@gmail.com"},"_id":"charlotte@0.1.5","devDependencies":{},"optionalDependencies":{},"engines":{"node":"*"},"_engineSupported":true,"_npmVersion":"1.1.0","_nodeVersion":"v0.6.7","_defaultsLoaded":true,"dist":{"shasum":"9962d2aed4fa03489858cfee41abeb01a74815a2","tarball":"https://registry.npmjs.org/charlotte/-/charlotte-0.1.5.tgz","integrity":"sha512-IE2aSRWPBkYzN/CdnVGU88suBymwzKZFKpNubLTfMH2kfBDchdeaqdKkZGX3NkVHYXxt6MtqlCkH9ch32rlKtg==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC25JGYesu80+0K9z8AmggiEsMtwDqXeTuObfx6YDQe8AIhAMUREOT4xCxEBwvdZCDL9KaiWuVcH5vVqGtWxdipYACT"}]},"maintainers":[{"name":"danieldkim","email":"danieldkimster@gmail.com"}],"directories":{}},"0.1.6":{"name":"charlotte","description":"A framework for building mobile web apps using Express and PhoneGap","homepage":"http://danieldkim.github.com/charlotte/","keywords":["express","phonegap","mobile"],"author":{"name":"Daniel Kim","email":"danieldkimster@gmail.com"},"version":"0.1.6","repository":{"type":"git","url":"git://github.com/danieldkim/charlotte.git"},"bugs":{"url":"http://github.com/danieldkim/charlotte/issues"},"licenses":[{"type":"MIT","url":"http://github.com/danieldkim/charlotte/raw/master/LICENSE"}],"dependencies":{"underscore":">=1.3.1","express":"~2.5.6"},"_npmUser":{"name":"danieldkim","email":"danieldkimster@gmail.com"},"_id":"charlotte@0.1.6","devDependencies":{},"optionalDependencies":{},"engines":{"node":"*"},"_engineSupported":true,"_npmVersion":"1.1.0","_nodeVersion":"v0.6.7","_defaultsLoaded":true,"dist":{"shasum":"8be7088b970a2fa35fcaa4ef01bc9cccd097dfe4","tarball":"https://registry.npmjs.org/charlotte/-/charlotte-0.1.6.tgz","integrity":"sha512-Fw9eUUS5ha6JEWeJJNke1MJFHEIiSxw1VyRh3L3PLzKOsGCC7edOcg3gckqKU7VuWCXI0X8cbJubo8BsgDxhQA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDAjARqGdQvkPdTNzDY8qgRFLORuDZBJngE9nLNNSdOEQIhANmBuzMsE9cU26BPP01LvOyxh+LZxoTd1uVUbr/pW2eq"}]},"maintainers":[{"name":"danieldkim","email":"danieldkimster@gmail.com"}],"directories":{}},"0.1.7":{"name":"charlotte","description":"A framework for building mobile web apps using Express and PhoneGap","homepage":"http://danieldkim.github.com/charlotte/","keywords":["express","phonegap","mobile"],"author":{"name":"Daniel Kim","email":"danieldkimster@gmail.com"},"version":"0.1.7","repository":{"type":"git","url":"git://github.com/danieldkim/charlotte.git"},"bugs":{"url":"http://github.com/danieldkim/charlotte/issues"},"licenses":[{"type":"MIT","url":"http://github.com/danieldkim/charlotte/raw/master/LICENSE"}],"dependencies":{"underscore":">=1.3.1","express":"~2.5.6"},"_npmUser":{"name":"danieldkim","email":"danieldkimster@gmail.com"},"_id":"charlotte@0.1.7","devDependencies":{},"optionalDependencies":{},"engines":{"node":"*"},"_engineSupported":true,"_npmVersion":"1.1.18","_nodeVersion":"v0.6.15","_defaultsLoaded":true,"dist":{"shasum":"202c2e7386521d565e0e2863b11c3fc169090554","tarball":"https://registry.npmjs.org/charlotte/-/charlotte-0.1.7.tgz","integrity":"sha512-MYC11ZiAnPi/ILQM08rWpQndfR/PeiMJfEBu93HpzYO1bdFWQGPbd5cyHor6/YOlZXCeS3ECbuDakBnPocy9cw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFnSOrEgI6BW199Mh5zVUrN+w73+ROOhIeQLhBb/LPHAAiAPdS5LnRFigXg7ki+Qd8hMZ4Iu5y53xUwiImQWarOvoA=="}]},"maintainers":[{"name":"danieldkim","email":"danieldkimster@gmail.com"}],"directories":{}},"0.1.8":{"name":"charlotte","description":"A framework for building mobile web apps using Express and PhoneGap","homepage":"http://danieldkim.github.com/charlotte/","keywords":["express","phonegap","mobile"],"author":{"name":"Daniel Kim","email":"danieldkimster@gmail.com"},"version":"0.1.8","repository":{"type":"git","url":"git://github.com/danieldkim/charlotte.git"},"bugs":{"url":"http://github.com/danieldkim/charlotte/issues"},"licenses":[{"type":"MIT","url":"http://github.com/danieldkim/charlotte/raw/master/LICENSE"}],"dependencies":{"underscore":">=1.3.1","express":"~2.5.6"},"devDependencies":{"async":">=0.1.18","mocha":">=1.0.3","chai":">=1.0.1","sinon":">=1.3.4","jade":">=0.26.0"},"scripts":{"test":"cd test && ./run_all_tests.sh"},"_npmUser":{"name":"danieldkim","email":"danieldkimster@gmail.com"},"_id":"charlotte@0.1.8","optionalDependencies":{},"engines":{"node":"*"},"_engineSupported":true,"_npmVersion":"1.1.18","_nodeVersion":"v0.6.15","_defaultsLoaded":true,"dist":{"shasum":"2f135f1e34ceecae68939f68bcbeffea74c0ba17","tarball":"https://registry.npmjs.org/charlotte/-/charlotte-0.1.8.tgz","integrity":"sha512-GjtC8BP9x2sLmHRfwkLbHww8t26kxBRcil9mc7NjThKMclTmpPf/GlzkThBd6iUc2AGL3PgLejp+mqjp7irotA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBvtEbSmCeob5njHaM9cKP+acwIexliRfxVcBDYTr9/fAiEAwumORh9IAcKSsYuky2Ti9C9czewqkZ3rFTdsKWFXjoo="}]},"maintainers":[{"name":"danieldkim","email":"danieldkimster@gmail.com"}]}},"readme":"# Introduction\n\nCharlotte is a framework for building mobile hybrid web/native apps using\n[Express](http://expressjs.com/) and [PhoneGap](http://phonegap.com/). It\nallows you to build a web app using a traditional web development approach and\nthen to reuse that web app and progressively enhance it for a native app.\n\nBy extending Express to the web browser Charlotte allows the rendering of view\ntemplates to transparently move to the client where it can be combined with\nCSS3 animations to provide page transitions with native feel. It leverages the\nPhoneGap File API to provide reliable and granular control over the caching of\napplication assets and data on the device.\n\nCharlotte provides a browser abstraction in JS that effectively produces,\nwithin the single-page application environment of PhoneGap, a multi-page web\napplication development environment with user-defined page transition\nanimations, robust error handling, and the performance characteristics\n(minimal network overhead) of an architecture based on a JavaScript MVC\nframework and JSON server API.\n\n(Charlotte is not a JavaScript MVC framework, though, and does not require you\nto build an API.)\n\nCharlotte is an implementation of the [*html bundle*][html_bundles] concept.\nRead the wiki doc for some background.\n\nAlso, check out the [charlotte demo][demo] app.\n\n# Requirements\n\n* underscore >=1.3.1\n \n* async >=0.1.16\n\n* Express ~2.5.6\n\n* zepto >=1.0rc1\n\n* PhoneGap >=1.5.0\n\n* jade (optional)\n\n# Express Setup\n\nInstall charlotte:\n\n    npm install charlotte\n    \nRequire charlotte:\n\n    var charlotte = require('charlotte');\n    \nSet a version:\n\n    charlotte.version = \"1.0\";\n\nSupport express (do this just before you use the router middleware):\n\n    charlotte.supportExpress(app);\n    app.use(app.router);\n    \nServe up views statically:\n\n    app.use(express.static(__dirname + '/views'));\n\nUse the `charlotte.byPassViews` route middleware in routes:\n\n    var bypassViews = process.env.NODE_ENV == 'development' ? \n                        charlotte.bypassViews() : function(req, res, next) { next(); };\n\n    app.get('/', bypassViews, function(req, res) {\n    ...\n\n\nThe above assumes that we don't need to worry about bypassing views in\nnon-development environments as static asset files will be served out of a\ndifferent server.\n\nCreate a symlink to the charlotte module's lib directory somewhere in your\nviews directory:\n\n    [~/projects/foo/node/views/lib]$ ln -s ../../node_modules/charlotte/lib charlotte\n\nCreate a `versions` directory in the `views` directory. Create a symlink\nwithin the versions directory that points to the views directory above it for\neach new version of your app :\n\n    [~/projects/foo/node/views]$ mkdir versions\n    [~/projects/foo/node/views]$ cd versions\n    [~/projects/foo/node/views/versions]$ ln -s .. 1.0\n\n# Layout Structure\n\nCreate a layout template and a layout body partial, which gets included by the layout:\n\nlayout.jade:\n\n    !!! 5\n    html(xmlns=\"http://www.w3.org/1999/xhtml\")\n      head\n        meta(name=\"viewport\", content=\"user-scalable=no, width=device-width\")\n        meta(name=\"apple-touch-fullscreen\", content=\"yes\")\n        meta(name=\"apple-mobile-web-app-status-bar-style\", content=\"black\")\n        - if (!requestId)\n          != stylesheets('foo')\n        != javascripts(\"/lib/underscore\", \"/lib/async\", \"/lib/zepto\", \"/lib/jade\")\n        != javascripts(\"/lib/charlotte/shared\", \"/lib/charlotte/charlotte\", \"/lib/charlotte/util\")\n        script(type=\"text/javascript\")\n          charlotte.baseUrl = 'http://foo.com/';\n          charlotte.assetRootUrl = '#{assetRootUrl}';\n          charlotte.version = '#{version}';\n      \n      body\n        #content.content-container\n          - if (isBlank(\"layoutBody\"))\n            !=partial('layout_body')\n          - else if (layoutBody)\n            !=partial(layoutBody)\n          - else\n            != body\n\nlayout_body.jade:\n\n    - if (!requestId)\n      != stylesheets('foo')\n\n    != body\n\nThis layout body is rather empty but the bulk of the layout content for your\npages should go in the layout body partial, which should also include the body\nof the response. The outer layout template should just be a basic html\nskeleton with a content container that includes the layout body partial. It\nshould include charlotte and its dependencies.\n\nThe actual layout body partial to use should be given in the `layoutBody`\nparameter, and should default to `layout_body`; if not blank (`undefined`,\n`null`, or '') and not truthy we just include the body of the response\ndirectly rather than go through the layout body.\n\nUse the `javascripts()` and `stylesheets()` helper functions provided by\nCharlotte to include JavaScript and CSS files. Simply pass paths to source\nfiles to the functions (you can omit the '.js' and '.css' extensions) and they\nwill output script tags or link tags, respectively.\n\nNote that the inclusion of the `stylesheets` partial is either in the outer\nlayout template or in the inner layout body depending on the presence of a\n`requestId`.\n\nThe outer layout partial will only be used when rendering templates on the\nserver in node. We do some basic client-side charlotte setup in it, setting\nthe `baseUrl`, `assetUrl`, and `version` attributes on the global charlotte\nobject. When running in [*html bundle*][html_bundles] mode and rendering\ntemplates on the client, the `baseUrl` and `assetUrl` attributes will be set\nby the bootstrap process , which you can see in the **Client `window` setup**\nsection of this document, and the version will be handled in a different\nmanner.\n\n# Client `window` Setup\n\nInclude charlotte and its dependencies in your `index.html` file to bootstrap\ncharlotte. Also include a link to your own boot script which should create a\ncharlotte browser and a tab and load the home page.\n\n    <script type=\"text/javascript\" charset=\"utf-8\" src=\"lib/cordova-1.5.0.js\"></script>\n    <script type=\"text/javascript\" charset=\"utf-8\" src=\"lib/underscore.js\"></script>\n    <script type=\"text/javascript\" charset=\"utf-8\" src=\"lib/async.js\"></script>\n    <script type=\"text/javascript\" charset=\"utf-8\" src=\"lib/zepto.js\"></script>\n    <script type=\"text/javascript\" charset=\"utf-8\" src=\"lib/charlotte/shared.js\"></script>\n    <script type=\"text/javascript\" charset=\"utf-8\" src=\"lib/charlotte/charlotte.js\"></script>\n    <script type=\"text/javascript\" charset=\"utf-8\" src=\"boot.js\"></script>\n\n(You'll need to have a process setup wherein these files are copied to your\nxcode project's `www` directory when building. For instance, the [charlotte\ndemo][demo] project has a shell script called `copy_boot_scripts.sh` that is\ncalled from a \"Run Script\" build stage in the xcode project.)\n\nCreate tab containers and tab content containers in the `index.html`:\n\n    <body onload=\"onBodyLoad()\">\n      <div id=\"foo-tab\" class=\"tab\">\n        <div id=\"content\" class=\"content-container\"></div>\n      </div>\n      <div id=\"bar-tab\" class=\"tab\">\n        <div id=\"content\" class=\"content-container\"></div>\n      </div>\n    </body>\n\n\nIn your boot script, initialize the global charlotte object:\n\n    charlotte.baseUrl = 'http://foo.com/';\n    charlotte.rootUrl =  'http://local.host:3000/';\n    charlotte.htmlBundleMode = true;\n\nThen create a charlotte browser and some tabs:\n\n    browser = charlotte.createBrowser();\n\n    _.each(['foo', 'bar'], function(name) {\n      browser.createTab({\n        name: name, \n        container: '#' + name + '-tab'\n      });\n    });\n\nAnd load the initial page into the initial tab:\n\n    var fooTab = browser.switchTab('foo');\n    fooTab.load({ url: '/' });\n\nThere are a number of possible options that you can and should specify when\nyou create a browser and when you load a page. Refer to the API documentation\nbelow and check out the [charlotte demo][demo] app to learn more.\n\nOptionally, may want to load newer versions of the core scripts required for\nbootstrap from the server:\n\n    charlotte.assets({ \n      javascripts: {\n        urls: [\n          \"/lib/underscore\", \"/lib/async\", \"/lib/zepto\", \"/lib/jade\",\n          \"/lib/charlotte/shared\", \"/lib/charlotte/charlotte\"\n        ]\n      }\n    }, next);\n\nYou'll want to do this before you create a browser. `charlotte.assets()` is\nasync so you should pass a callback method as the final argument which will be\ninvoked when all the assets have been loaded.\n\nYou may also may want to clean up the file cache on startup. This will clean\nup all of the version caches except for the current version:\n\n    if (charlotte.inNativeApp) {\n      charlotte.clearFileCache(localStorage.getItem(\"version\"), next);        \n    } \n\n`charlotte.clearFileCache()` is also async and takes a callback as the final\nargument.\n\n\n# Template API\n\nThe template API provides a common set of variables and helper functions that\ntemplates can use whether they are running on the server within node or on the\nclient.\n\n## Asset Helpers\n\nAsset helpers should *always* be used to include application assets. The\noutput shown below can be considered to be the *logical* output of these\nhelpers. When running in node on the server, the output is literally what is\nshown and is rendered inline in the template output. When running in [*html\nbundle*][html_bundles] mode on the client there's a bit more going on.\n\n### javascripts\n\nthis:\n\n    != javascripts('/js/underscore', '/js/async')\nwill output this:\n\n    <script type=\"text/javascript\" src=\"http://local.host:3000/versions/1.0/js/underscore.js\"></script>\n    <script type=\"text/javascript\" src=\"http://local.host:3000/versions/1.0/js/async.js\"></script>\n\n\n### stylesheets\n  \nthis:\n\n    != stylesheets('/css/foo', '/foo/bar')\nwill output this:\n\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"http://local.host:3000/versions/1.0/css/foo.css\"></link>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"http://local.host:3000/versions/1.0/css/bar.css\"></link>\n\n### img\n\nthis:\n\n    != img({src: '/img/foo.jpg'})\nwill output this:\n\n    <img src=\"http://local.host:3000/versions/1.0/img/foo.jpg\"></img>\n    \n\nDo not use the `img` helper to include non-application-asset images such as\nuser-generated content. Should only be used for images that are part of the\napplication itself, i.e. icons.\n\n## Utility Helpers\n\n* isBlank(varName) - returns `true` is the variable named `varName` in `this`\n  scope is `undefined`, `null` or an empty string.\n\n## Dynamic Helpers / Variables\n\n* NODE_ENV - the value of the `NODE_ENV` environment variable (e.g.,\n  development, production, etc.).\n\n* rootUrl - the root url of the charlotte object, browser, or tab within which\n  this template is rendered.\n \n* assetRootUrl - the root url of the server for downloading application\n  assets, i.e. javascripts, stylesheets, and image assets.\n\n* version - the version of this request.\n\n* requestId - the request id of this request (always `null` on the server).\n\n* viewOnly - whether this is a view-only request.\n\n* referer - the referer for this request -- use this instead of checking the\n  `Referer` header.\n\n* inNativeApp - this tells the template if it's running within a native app\n  and device APIs are available.\n\n\n# Client `window` API\n\nThe client side of the charlotte framework runs within the `window` of a web\nbrowser or *web view* of a PhoneGap-based native app. The progressive\nenhancement of your web app for a native environment happens within this\ncontext.\n\n## Callback Style\n\nA side note here on callback style. Charlotte uses the standard node callback\nstyle wherein an error is passed as the first argument to the callback; it\nuses this style on the client as well as the server. This is true for\nuser-provided callbacks as well as the callbacks that Charlotte provides for\nthe user to call. So check the first argument for an error on any callbacks\nthat you pass to Charlotte. Send an `Error` object as the first argument when\ninvoking any Charlotte-provided callbacks to pass an error back to Charlotte.\n\nEvent handler callbacks, such as `ready` event handlers, are the exception to\nthis rule. By definition they are invoked to handle specific -- generally\nnon-error -- states and do not need an optional error argument.\n\n## charlotte.ready(requestId, handler)\n\nAs with a typical web page, the action begins when the page is *ready*, and we\nregister a function to be invoked when it is.\n\nCall the `charlotte.ready()` method to register functions to execute when the\npage is ready:\n\n    script(type=\"text/javascript\")\n      charlotte.ready('#{requestId}', function(callback) {\n        $('#body-frame', this.container).height(window.innerHeight - 40);\n        callback();\n      });\n\n`charlotte.ready()` takes 2 arguments:\n\n* requestId - the id of the current request. you don't need to worry about\n  what this is or how to get it -- charlotte provides it to you through the\n  `requestId` helper in the template API. just interpolate the value into the\n  template and pass it to the ready() method.\n* your handler.  \n\nCharlotte provides two things to your handler function. \n\nFirst it provides, as the only argument to the handler, a callback that must\nbe invoked when the handler is done doing what it has to do. This callback is\nin the node style -- pass an error as the first argument to it if an error\noccurs within your handler.\n\nReady event handlers are invoked in a chain, in order of their registration in\nthe flow of the HTML. The next handler is not invoked until the current one\nhas signaled completion by invoking its callback. Passing an error to the\ncallback halts the execution chain.\n\nThe second thing that charlotte provides to your handler is the value of\n`this`. What is `this`, you ask? Read on to learn more ...\n\n## Charlotte, Browsers, and Tabs\n\nA page in a charlotte-based app can be executing in one of three possible\nscopes or contexts, depending on how the page was loaded into the `window`.\nThe execution context defines the value of `this` in the page's `ready` event\nhandlers.\n\n`this` is useful in a few of ways in your handler:\n\n* you can access properties of the execution context, such as `container` and\n  `rootUrl`.\n\n* you can access asset loading methods of the execution context, such as\n  `javascripts()` and `require()`, that are auto-versioned with the version of\n  the current request.\n\n* you can do some duck-typing on it to do different things depending on what\n  the execution context is. for example, you will usually only want to\n  override anchor tag click handlers when executing within a tab context.\n\n### Global charlotte object\n\nWhen not executing in [*html bundle*][html_bundles] mode, with templates being\nrendered on the server in node, `this` in your ready handler is the global\n`window.charlotte` object.\n\n### Charlotte browser tab\n\nMost pages in your app will be loaded into a charlotte browser tab. Tabs\nmaintain history as you load pages into them. You can go back and you can\nreload. This is when you'll want to override anchor tag click handlers to load\nlinked pages into the current tab, or to go back in the history.\n\n    function(callback) {\n      var self = this,\n          container = self.container;\n\n      if (container) {\n\n        $(self.contentContainer, container).on('click', '#nav-bar .button.left', function(e) {\n          e.preventDefault();\n          self.back();\n        });\n    \n        $(self.contentContainer, container).on(\"click\", 'a.post.show', function(e) {\n          e.preventDefault();\n          // this load is not very interesting without some load and back transitions\n          // but i'm keeping this example short\n          self.load({url: this.href});\n        });\n    \n      }\n      callback();\n    }        \n\nOnly tabs have a `container` property so we use it above to determine if we're\nin a tab execution context. It should also be used to scope any selector-based\noperations. We use the tab `container` property above and it's\n`contentContainer` property to select the root for event delegation.\n\n\n### Charlotte browser\n\nWhen you load a page into the DOM using the `request()` method on a charlotte\nbrowser instance, `this` in your ready handler will be the browser object.\nThis will generally be the case when issuing AJAX-style requests to retrieve\npage data or to update parts of a page outside of the normal tab history flow.\n\nTypically, these types of requests occur to update part of a page within a\ntab, so it is not necessary to add event event handlers so long as event\ndelegation was used properly when the tab was loaded. See the [charlotte\ndemo][demo] app for an example of this.\n\n## DOM Event Handling\n\nBecause a charlotte-based application is underneath-the-hood still a\nsingle-page application, and pages are removed from the DOM as they are popped\noff the stack, it is important that [event\ndelegation](http://www.sitepoint.com/javascript-event-delegation-is-easier-than-you-think/)\nbe used properly. Use zepto's `on()` method to attach event handlers, not\n`bind()`. In a tab execution context, use the supplied `container` and\n`contentContainer` properties to select the root for event delegation:\n\n    function(callback) {\n      var self = this,\n          container = self.container;\n\n      if (container) {\n\n        $(self.contentContainer, container).on('click', '#nav-bar .button.left', function(e) {\n          e.preventDefault();\n          self.back();\n        });\n    \n      }\n      callback();\n    }\n\nCharlotte will detach all event handlers from a page's content container when\n`tab.back()` is called, to prevent any possible memory leaks. If you are\nattaching event handlers to elements outside of the context of tabs in your\napp then you are responsible for detaching those handlers when you remove the\nelements from the DOM.\n\n## Common properties\n\nAll of the execution contexts have these properties:\n\n* **baseUrl** - this is the *logical* base url for the execution context. it\n  is used in 2 ways:\n\n  1. to resolve relative module names passed to the `require()` method. \n\n  2. whenever a module is encountered whose name is under `baseUrl` it will be\n  retrieved using the `rootUrl`.\n  \n  only required if using AMD.\n\n* **rootUrl** - the root url of the node server, used to resolve all relative\n  paths (except for AMD module names). defaults to '/'; should be set to a\n  full absolute URL in a native app execution environment. will typically be\n  equal to the `baseUrl` only in production.\n\n* **assetRootUrl** - the root url of the static asset server, used to resolve\n  all relative asset paths. if no `assetRootUrl` is provided, the `rootUrl`\n  will be used.\n\nGenerally, it is only necessary to set these properties on the global\n`charlotte` object, as browsers created by it will inherit these values, and\ntabs will inherit these values from browsers.\n\nIt is theoretically possible, however, to have multiple browsers in an app\nwith different bases/roots, or tabs within a browser that have different\nbases/roots.\n\n## Common methods\n\n### Asset methods\n\nAll of the execution contexts have methods to dynamically load application assets: \n\n* `stylesheets(options, callback)` - load CSS stylesheets.\n\n* `javascripts(options, callback)` - load JavaScript files.\n\nThe options for each of these methods are: \n\n* **urls** - an array of resource paths minus the filename extensions (i.e.\n  \"/foo/bar\", instead of \"/foo/bar.js\")\n\n* **version** - version of assets to load. relative resource paths will be\n  versioned using this value (e.g. \"/foo/bar\" -> \"/versions/1.0/foo/bar\")\n\n* **rootUrl** - url of node server; this server will be used to retrieve the\n  current version if none is provided\n\n* **assetRootUrl** - static asset server that assets will be downloaded from; the\n  `rootUrl` will be used if no assetUrl is provided here or on the object\n  itself.\n\nIf the `version`, `rootUrl`, and `assetRootUrl` options are not provided, the\nproperties of the execution context will be used.\n\nThere's also a wrapper around these methods that can be used to load both\nstylesheets and JavaScripts at once:\n\n* `assets(options, callback)` \n\nThe two possible options are:\n\n* **javascripts** - options for the JavaScripts load\n\n* **stylesheets** - options for the stylesheets load\n\n### AMD\n\nIn addition to the asset methods described above, Charlotte provides an AMD\nmodule loading mechanism. Each of the execution contexts has a `require()`\nmethod.\n\n* require(options, callback)\n\nThe options are the same as the options to the other asset loader methods\nplus:\n\n* **dependencies** - array of module names.\n\n* **baseUrl** - used to resolve relative module names in the dependencies list\n\nModules are defined using the `charlotte.define()` method.\n\n#### Ready event handler modules\n\nIn many cases, all you want to do in your `ready` event handlers is require a\nmodule and invoke it in this manner:\n\n    charlotte.ready('#{requestId}', function(callback) {\n      this.require(\n        {\n          dependencies: ['foo/bar']\n        }, \n        function(err, foobar) {\n          if (err) return callback(err);\n          foobar.call(this, callback);\n        });\n    });\n\nModules names can be specified as `ready` event handlers. When this is done\nCharlotte will automatically require the module and call it using the\nexecution context as `this`, and pass the `ready` handler callback as the only\nargument. The code below is equivalent to the above:\n\n    charlotte.ready('#{requestId}', 'foo/bar');\n  \n# charlotte\n\nIn addition to the common ones, the charlotte object has these properties and\nmethods:\n\n* **htmlBundleMode** - flag indicating whether charlotte is in [*html\n  bundle*][html_bundles] mode.\n\n* **cacheSeedLocation** - url of cache seed. should be relative to the app\n  location and will be resolved relative to the `www` directory in the native\n  app. defaults to `'./cache_seed'`.\n\n* **readyRegistryTimeToLive** - how long ready event handlers should live\n  before being purged, in milliseconds.  defaults to 15000.\n\n* **tempCacheSize** - the size, in characters, of the in-memory temp cache.\n  older entries in the cache will be purged when this size is exceeded to make\n  room for newer ones.\n\n* `define(name, [dependencies,] callback)`\n\n  * **name** - the name is required and should be a **fully-qualified** absolute url.\n\n  * **dependencies** - array of module names. relative names will be resolved\n    using the fully-qualified name of the module itself, and interpreted as\n    root-relative to that name. e.g. if the name of the module is\n    \"http://foo.bar/foo\", then a dependency with the name \"/bar\" will be\n    resolved as \"http://foo.bar/bar\".\n\n* `createBrowser(options)` - options to this method are discussed in detail in\n  the browser API section.\n\n* `clearFileCache(options, callback)` - clears the filesystem cache for a particular\n  `rootUrl`. options are:\n\n  * **rootUrl** - the root url of the cache to to clear; if not provided\n    rootUrl of browser instance will be used.\n\n  * **versionExceptions** - an array of version strings that should be\n    *not* be cleared.\n\n* `clearRamCache(options)` - clears the RAM cache for a particular `rootUrl`\n  (including the temp cache). options are the same as those for\n  `clearFileCache()`. this method is mainly used internally to clear the RAM\n  cache when a version change is detected.\n\n\n# browser\n\nIn addition to the common ones, a charlotte browser has the following methods.\n\n## createBrowser(options)\n\nThe `createBrowser()` method is actually on the `charlotte` object, but it\nplays the role of constructor for a browser instance so we discuss its details\nhere.\n\nThe `baseUrl`, `rootUrl`, and `assetUrl` can be provided as options. If not\nprovided, the browser instance will inherit those of the `charlotte` object\nthat created it. Other options are described below.\n\n### followRedirects\n\nWhether redirects on a `request()` should be followed. If false, a\n`charlotte.RedirectError` will be generated. Default is `true`.\n\n### layoutBody\n\nThe default layout body template.  Default is `'layout_body'`.\n\n### templateCompilers\n\nA hash of compilers for different template types.  Default is:\n\n    {\n      '.jade': function(text) {\n        return jade.compile(text);\n      }\n    }\n\n### defaultTemplateExtname\n\nTemplate extension to use for template paths that omit the filename extension.\nDefault is \".jade\".\n\n### helpers\n\nStatic helpers that will be available to templates. You'll want to use the\nsame ones here that you use on the server.\n\n### dynamicHelpers\n\nDynamic helpers that will be available to templates. You'll want to use the\nsame ones here that you use on the server.\n\nDynamic helpers that depend on the `res` argument are not supported. There is\nlimited support for dependence on the `req` argument -- basically just the\n`referer` and `viewOnly` properties and the `flash()` method, currently.\n\n### timeout\n\nTimeout value for any network operations. `charlotte.ServerUnavailableError`'s\nwill be generated when requests take longer than the timeout.\n\n### cachedBundles\n\nUsed to configure what [html bundle][html_bundles] resources (pages,\nessentially) will be cached and in what manner. Each of these options takes a\nset of matchers against which the url for a resource will be tested. A matcher\ncan be a regular expression or a function that returns a boolean. A matcher\nfunction takes two arguments:\n\n`function(url, parsedUrl)`:\n\n* **url** - the url as a string\n\n* **parsedUrl** - the url as a parsed object with\n  [attributes](http://dev.w3.org/html5/spec/urls.html#url-decomposition-idl-attributes).\n\nThe different cachedBundles options are:\n\n* **urlMatchers** - any array of matchers for resources to be cached\n  permanently.\n\n* **tempUrlMatchers** - any array matchers for resources to be cached in the\n  in-memory temp cache.\n\n* **viewOnlyUrlMatchers** - a hash of named matchers for view-only resources.\n  since many resources can share the same view-only representation we give\n  that representation its own name and store it under that name rather than\n  name of the resource itself, to avoid duplication. see the [charlotte\n  demo][demo] for examples.\n\n### errorHandlers\n\nError handler callbacks to be invoked when an error occurs while processing a\n`request()` or `tab.load()`.\n\n`global: function(err, tab)`\n\nThe global error handler *always* gets invoked for every error. You want to\nlog the error somewhere in this function.\n\n`default: function(err, tab, next)`\n\nThis is the default error handler for any `request()` calls or `tab.load()`\ncalls that do not specify an `onError` option. The `next` argument is a\ncallback that you should invoke if you'd like to continue processing and for\nthe error to be passed on to the request/load callback.\n\n### onCacheMiss(url, tab, afterViewLoad)\n\nCallback that is invoked if the network is accessed at any point while\nprocessing a `request()` or `tab.load()` call. Only invoked once per\nrequest/load even if multiple network accesses occur.\n\nThe `url` argument is of the *actual* resource on which the first cache miss\noccurred while processing the request, i.e. potentially a JavaScript file that\nhas to be downloaded if the html bundle was retrieved from the cache. Thus,\nthe url may not be the same as the url of the page that was being loaded.\n\nThe `afterViewLoad` argument indicates whether this cache miss occurred on a\nview-only load after the view has been completely loaded.\n\nThis callback will *not* be invoked if overridden at the request/load level.\n\n### onRequestEnd(settings, tab)\n\nCallback that is invoked when any `request()` (which is also used internally\nby `tab.load()`) is fully processed. One use case for this is to hide a\n\"loading\" status message that you displayed on cache miss.\n\nThis callback will *not* be invoked if overridden at the request/load level.\n\n### onVersionChange(localVersion, remoteVersion, callback)\n\nCallback that is invoked whenever a version change is detected while\nprocessing an html bundle request. `localVersion` is the current local version\nand `remoteVersion` is the new remote version returned from the server. Invoke\n`callback` if you'd like the processing of the request to continue, otherwise\ndon't.\n\n## createTab(options)\n\nThe options to this method are discussed in detail in the tab API section.\n\n## currentTab()\n\nReturns the currently selected tab.\n\n## switchTab(name)\n\nSwitches to the tab with the give `name`.\n\n## request(settings, callback[, renderWait])\n\nIssues an [html bundle][html_bundles] request.\n\nThe `settings` are the same settings accepted by a zepto `ajax()` request,\nplus:\n\n* **viewOnly** - whether this is a view-only request\n\n* **container** - the DOM container into which the page should be loaded.\n\n* **followRedirects** - override of the browser option with the same name.\n\n* **layoutBody** - \"\"\n\n* **onCacheMiss** - \"\"\n\n* **uploadOptions** - a PhoneGap\n  [FileUploadOptions](http://docs.phonegap.com/en/1.5.0/phonegap_file_file.md.html#FileUploadOptions)\n  object. should have a `fileUri` attribute in addition to the standard\n  PhoneGap attributes. when this is option is passed, an upload using the\n  PhoneGap\n  [FileTransfer](http://docs.phonegap.com/en/1.0.0/phonegap_file_file.md.html#FileTransfer)\n  object is done.\n\nThe `callback` is invoked when the request is complete and has this signature:\n\n`function(err, bundle, html, triggerReady)`\n\n* **bundle** - the html bundle object. \n\n* **html** - the html content that was loaded into the specified container.\n\n* **triggerReady** - a function to call to trigger the `ready` event on the\n  page. ready event handlers will not be executed until this function is\n  called. you can also pass a callback to this function to be invoked after\n  the execution of the ready event handler chain is complete, though you will\n  rarely need to do this.\n\nThe optional `renderWait` argument is a callback that can be used to delay the\nrendering of the bundle into HTML until some condition is met. If provided, it\nis given a callback to invoke when you're ready to render. (`tab.load()` uses\nthis internally to delay the rendering of the full page on view-only-first\nloads until the page transition is complete.)\n\n# tab\n\nIn addition to the common ones, a charlotte tab has the following  methods.\n\n## createTab(options)\n\nThe `baseUrl`, `rootUrl`, and `assetUrl` can be provided as options. If not\nprovided, the tab instance will inherit those of the browser object that\ncreated it.\n\nOther options are:\n\n* name - a unique name for the tab.\n\n* container - CSS selector identifying the container element for the tab.\n\n* contentContainer - CSS selector identifying the container element for the\n  content within the tab. Scoped to the tab container. Defaults to\n  '#content'.\n\n* createContentContainer - an optional callback that should be invoked when\n  creating a new content container to load a new page into.\n\nThe default createContentContainer function is:\n\n    function defaultCreateContentContainer() {\n      var container = document.createElement('div');\n      container.className = 'content-container';\n      container.style.display = 'none';\n      return container;\n    }\n\n## load(settings)\n\nLoads a new page into the tab. Accepts all the of the settings that zepto's\n`ajax()` method takes plus:\n\n* **followRedirects** - override of the browser option with the same name.\n\n* **onCacheMiss** - \"\"\n\n* **onViewLoad** - options for the view-only load event.\n\n* **onLoad** - options for the load event.\n\n* **onBack** - options for the back event (loaded page is popped off the\n  stack).\n\n* **onError** - override of the `errorHandler.default` browser option. \n\n`onViewLoad`, `onLoad`, and `onBack` all take the same options, both of\nwhich are optional.\n\n* **transition** - callback to handle the transition of the loaded content\n  from staging container to current content container.\n\n* **callback** - callback to be invoked when the processing of the load,\n  including optional transition, is complete.\n\nThe signature for the `onViewLoad` and `onLoad` callbacks looks like:\n\n`function(err, bundle, triggerReady)`\n\n* **err** - an error object if an error occurred while processing the load.\n  any errors passed to ready event handler callbacks will end up here, too.\n\n* **bundle** - html bundle response.\n\n* **triggerReady** - a function to call to trigger the `ready` event on the\n  page. ready event handlers will not be executed until this function is\n  called. you can also pass a callback to this function to be invoked after\n  the execution of the ready event handler chain is complete, though you will\n  rarely need to do this.\n\nIf the `callback` option is not provided for these events, `triggerReady()`\nwill be automatically executed.\n\nThe `onBack` callback looks like:\n\n`function(options)`\n\nThe `options` are user-defined, and are whatever was passed in the\n`tab.back()` call.\n\n### Transitions\n\nThe transition option is a function that takes a content container, a content\nstage container, and callback:\n\n`transition: function(contentCtr, contentStageCtr, callback)`\n\nIt causes the `contentStageCtr` to take over the viewing area currently\noccupied by the `contentCtr`, as well as *assume its identity*. It invokes the\n`callback` argument when the transition is complete. \n\nThe transition could involve moving the `contentCtr` out of the way, covering\nit, etc. It will be removed from the DOM when the callback is\ncalled.\n\nFor `on[View]Load` events, the `contentStageCtr` contains the newly loaded\npage content. For the `onBack` event, the `contentStageCtr` contains the\nprevious page in the tab history.\n\n### View-only first loads\n\nResponsive user interfaces require that some sort of view be displayed to the\nuser upon the touch of a button, even if some latency is involved in rendering\nthe full content of a page. The view-only-first mechanism helps to address\nthat need.\n\nWhen an `onViewLoad` setting is specified in a `load()` call, charlotte will\nactually coordinate the handling of 2 distinct html bundle requests: \n\n* one request with a `viewOnly=true` query string param appended to the url\n* one request with the provided url\n\nThe Express route for the url can detect this parameter with the\ncharlotte-provided `req.viewOnly` property and should render a response that\ndoes not block on any external IO and returns a response immediately:\n\n    app.get('/posts', function(req, res) {\n\n      if (req.viewOnly) {\n        res.render('posts/index', {\n          title: \"Post list\",\n          posts: [] \n        });\n      } else {\n        Posts.all(function(posts) {\n          res.render('posts/index', {\n            title: \"Post list\",\n            posts: posts\n          });      \n        });\n      }\n  \n    });\n\nCharlotte will fire off the two requests in parallel but it will always invoke\nthe `onViewLoad` callbacks first, even if for some reason the regular load\nreturns a response first. Also, it will not invoke the `onLoad` callback until\nthe `triggerReady` for `onViewLoad` is called, even if the regular load\nreturns while the `onViewLoad` callback is being executed.\n\nCaching of view-only responses, which is discussed in the **Caching and\nVersioning** section, will avoid network roundtrips and allow for minimal\nlatency between the touch of a button and the display of the view, and we can\ntypically cache them forever as they will generally be essentially static and\nhave no dynamic components.\n\n### Redirects\n\nThe `tab.load()` method has some special handling for redirects when the\n`followRedirects` option is `true` (the default). If the location being\nredirected to is the current page, the tab will automatically `reload()` the\ncurrent page. If the location being redirected to is equal to the previous\npage, the tab will automatically call `back()` on itself and then `reload()`\nthat previous page. This is useful, for instance, in a modal form when you\nwant the tab to automatically go back to the previous page after posting the\nform and refresh that page's contents.\n\nThere is some magic going on to make this happen as true redirects are\ntransparent to XHR clients. Charlotte monkeypatches the Express\n`res.redirect()` method to make these pseudo-redirects visible to the\ncharlotte client runtime. As long as `res.render()` is used to do redirects,\nthis behavior will be observed. Issuing a true redirect by setting a `302`\nstatus and setting a `Location` header will bypass this magic. (Note: for\nnon-html-bundle requests `res.redirect()` will continue to do the normal thing\nand send a `302` with a `Location` header)\n\nCurrently this is only enabled for posts and uploads. I don't remember why. If\nI come across a good reason to enable it for gets I will.\n\n### Posts\n\nThe `tab.load()` method also has some special handling for posts.\n\nOne kind of special handling is for posts that redirect back to the page that\nthe post was submitted from, or to the previous page. As mentioned above, the\ntab will automatically `reload()` those pages in such cases. When such loads\nthat are the result of redirects from posts occur, Charlotte will ignore the\ncache and always go to the server for the page (specifically, for the html\nbundle -- the cache will still be consulted for assets). It will also not\ncache the response. This allows any errors sent by the `req.flash()` method to\nbe displayed, and not cached. The cached page will still be used for initial\nget loads of the page with the form.\n\nAlso, posts that return a normal non-redirect response do not affect tab\nhistory. This fits the use case of a form that repeatedly returns errors to\nthe client until valid data is submitted. Going back in the tab history from\nthe point when a successful submit eventually occurs should not have to go\nthrough a series of error response pages. See the [charlotte demo][demo] for\nan example of this and it should be more clear why this special handling is a\ngood thing for native apps.\n\n## reload(callback)\n\nReloads the current page in the tab.\n\n## back(options)\n\nGoes back in the tab history, causing the previous page in the tab history to\nbe displayed. The `onBack` options -- `transition` and `callback` -- specified\nwhen the page was loaded will be invoked. The current page will be popped from\nthe stack and permanently removed from the DOM.\n\n## Error Handling\n\n## The Error Handler Chain\n\n## Error Types\n\n### charlotte.ServerUnavailableError\n\n### charlotte.ResourceNotFoundError\n\n### charlotte.RedirectError\n\n### charlotte.AssetLoadError\n\n### charlotte.util.VersionMismatchError\n\n## `completeBundleProcess`\n \n## charlotte.util\n\n* `propertyHelper()` this method can be used to create request scope\n  properties that can be set and accessed from templates. this allows a\n  template used to render the body of a response to set a property used by the\n  layout body that includes it, i.e. where the cancel link should point to in\n  the modal form layout body.\n\n## charlotte.pagetransitions\n\n# Caching and Versioning\n\n## Versioning\n\nCharlotte is very aggressive in its caching. It caches resources in the local\nfilesystem and in memory and will always consult caches before reaching across\nthe network for them. It only hits the network when it has to, and an\napp-level version change (more precisely, a `rootUrl`-level version change) is\nthe signal that tells it to do so. The assumption of this signal is also what\nallows it to avoid any network costs (i.e. even the relatively small cost of a\nconditional GET to check if particular resource has changed) most of the time\nfor cached data. It also allows for partial functionality in offline\nconditions.\n\n### onVersionChange\n\n## Filesystem Cache\n\nCharlotte uses the [PhoneGap File\nAPI](http://docs.phonegap.com/en/1.5.0/phonegap_file_file.md.html) to cache\nresources locally. The cache is organized by root url/version/resource host.\n\nHere's what the [charlotte demo][demo] cache directory tree looks like:\n\n    |-local.charlottedemo.com_3000_\n     |---1.0\n     |-----local-assets.charlottedemo.com_3000\n     |-------versions\n     |---------1.0\n     |-----------lib\n     |-------------charlotte\n     |-------------common\n     |-----------messages\n     |-----------posts\n     |-----------tab_menu\n     |-----------users\n     |-----local.charlottedemo.com_3000\n     |-------posts\n     |---------new\n     |-------tab_menu\n     |-------view_only_bundles\n\n\n## RAM Cache\n\n## Resource types\n\n### Templates\n\n### JavaScripts\n\n### Stylesheets\n\n### Images\n\n## Html Bundles\n\n## Disabling Caching for Development\n\n## Versioned Asset Deployment\n\n# Some general guidelines\n\n* use the charlotte asset helper methods to output script tags, link tags, and\n  image application assets.\n\n* view templates should be specified with full root-relative paths in\n  `res.render()` calls. charlotte will not apply the view lookup logic that\n  Express does.\n\n* view templates should only access locals, not session or global state.\n\n* locals should only be accessed in templates as pure data, no method calls.\n\n* be careful not to include any sensitive information in your template source\n  code as the source files will eventually be served statically, with no\n  authentication, for distribution to native apps.\n\n* `undefined` values do not get serialized in JSON. attributes with a value of\n  `undefined` are simply excluded. when rendering client-side in a native app,\n  attempts to access absent locals in your templates will result in reference\n  errors. make sure all locals are defined, setting them to an appropriate\n  default if necessary, before calling `res.render`. or, alternatively make\n  sure your template accounts for such potentially undefined values my testing\n  if `'undefined' === typeof myVar` before attempting to access them.\n  charlotte provides a helper method `isBlank(myVarName)` that will safely\n  check if the variable named myVarName is undefined, `null`, or an empty\n  string.\n\n* dynamic helpers that depend on the `res` argument are not supported. there\n  is limited support for dependence on the `req` argument -- basically just\n  the `referer` and `viewOnly` properties and the `flash()` method, currently.\n\n* the `flash()` method will work slightly differently when running in a native\n  app than it does when running in node. flash messages will only be\n  accessible in a native app on the immediately subsequent request, after\n  which they will be cleared even if not accessed during that request. that\n  also means they will not be accessible on the same request that they are\n  created. this fits with the general use case for the `flash()` method; your\n  app should not depend on support for other use cases.\n\n\n\n[demo]: https://github.com/danieldkim/charlotte_demo  \"Charlotte demo\"\n\n[html_bundles]: https://github.com/danieldkim/charlotte/wiki/Html-Bundles \"HTML Bundles\"\n","maintainers":[{"name":"danieldkim","email":"danieldkimster@gmail.com"}],"time":{"modified":"2022-06-13T05:53:48.721Z","created":"2012-04-18T23:04:46.684Z","0.1.0":"2012-04-18T23:04:47.156Z","0.1.1":"2012-04-21T20:56:51.655Z","0.1.2":"2012-04-21T21:01:38.774Z","0.1.3":"2012-04-23T17:10:39.521Z","0.1.4":"2012-04-23T19:39:22.836Z","0.1.5":"2012-04-23T20:29:44.132Z","0.1.6":"2012-04-23T22:45:25.590Z","0.1.7":"2012-05-03T03:10:15.832Z","0.1.8":"2012-05-20T00:04:34.089Z"},"author":{"name":"Daniel Kim","email":"danieldkimster@gmail.com"},"repository":{"type":"git","url":"git://github.com/danieldkim/charlotte.git"}}