123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283 |
- /* appjet:version 0.1 */
- /* appjet:library */
- // Copyright (c) 2009, Herbert Vojčík
- // Licensed by MIT license (http://www.opensource.org/licenses/mit-license.php)
- var _ = import({}, "lib-support/useful");
- var _testView, _showNoCode, _tabs, _code;
- /**
- * Call this to say you will use the harness.
- * Enables autodispatch with dispatchPlus, showNoCode and testView,
- * as well as prepares harness components.
- * You should call harness(path) afterwards to actually fill it with contents.
- @param fb if evaluates to true, uses facebook tags to build harness
- for facebook views.
- */
- function prepareHarness(fb) {
- import(_, "lib-app/mvp", "lib-app/dispatch-plus", "lib-app/liveui");
- if (fb) import(_, "lib-app/facebook-ext");
- var _canvas, _prints = DIV();
- page.setView(fb ? _.box(
- _tabs = _.box(_.lazy(_renderFbTabs)),
- _canvas = _.box(DIV({style:"margin-top: 3em"},
- _.data("view")
- )),
- _code = _.box(
- DIV(HR(), P("Code of scenario: "), CODE(_.data()))
- )
- ) : _.box(TABLE({cellspacing:0, cellpadding:0, style:"width: 100%"},
- TR(
- _tabs = _.box(
- TD({rowspan:2,style:"width: 150px; vertical-align: top"}, _.lazy(_renderTabs))
- ),
- _canvas = _.box(TD({style:_.seq(
- "padding:20px;",
- "vertical-align:top;",
- "background-color:", _.outerdata("col")
- )}, _.data("view")))
- ),
- TR(
- _code = _.box(
- TD({style:"padding:20px"}, HR(), P("Code of scenario: "), CODE(_.data()))
- )
- )
- )));
- _canvas.given({view:_prints});
- page.setPresenter(_.dispatchPlus);
- page.setViewModel({col:"inherit"});
- // var _oldPageBodyWrite = page.body.write;
- /**@ignore*/
- /* page.body.write = function(text) {
- _prints.push(html(text));
- };*/
- _testView = function(v) {
- _canvas.model.view = v;
- // page.body.write = _oldPageBodyWrite;
- };
- _showNoCode = function() { _code[0].length = 0; };
- }
- function _renderTabs(model) {
- var list = DIV();
- model.forEach(function(x, i) {
- list.push(DIV({style: "padding: 10px; background-color: "+x.col},
- link(x.link, x.text)
- ));
- });
- return list;
- }
- function _renderFbTabs(model) {
- var inputs = model.map(function(x){
- return x.link+"_"+x.text;
- });
- return fb.ui.tabs(inputs);
- }
- function _toLink(fname) {
- return fname.split("_")[1].split("$").join("-");
- }
- function _toText(fname) {
- return fname.split("_")[1].split("$").join(" ");
- }
- /**
- * When you use view/content object that you manipulate,
- * not the print functions, call this to show it.
- */
- function testView(v) {
- if (!_testView) throw "prepareHarness not called.";
- _testView(v);
- }
- /**
- * Suppresses showing code of the scenario. Effectively turns
- * the UI harness to simple tabbed-page-view application.
- */
- function showNoCode() {
- if (!_showNoCode) throw "prepareHarness not called.";
- _showNoCode();
- }
- /**
- * This function creates the harness.
- * In non-fb case, it is called automatically.
- * In fb case, you should call it manually.
- @param uiPath "path" to ui scenario (/name-of-scenario).
- When using lib-dispatch-plus, it is request.pathTail.
- */
- function harness(uiPath) {
- page.setPresenter(function() {});
- var prefix = request.method.toLowerCase()+"ui_";
- var getuis = keys(appjet._internal.global).filter(function(x) {
- return x !== "getui_main" && x.substring(0, prefix.length) === prefix;
- });
- var step = Math.floor(getuis.length / 2);
- var oddNumber = 2*step+1;
- function nthColour(i) {
- function _rem(x) { return x - Math.floor(x); }
- var c = 1;
- _.hsv2rgb(_rem(i*step/oddNumber), 0.05, 0.95).
- forEach(function(x) { c = (c<<8)+x; });
- return "#" + c.toString(16).substring(1);
- }
- var tabsInfo = getuis.map(function(x, i) {
- var result = {
- link:_toLink(x),
- text: _toText(x),
- col: nthColour(i)
- };
- if ("/"+result.link === uiPath) {
- _.extend(page.viewModel, result);
- }
- return result;
- });
- _tabs.given(tabsInfo);
- request.fullPath = "ui" + uiPath;
- var prefix = _.dispatchPlus[request.method]+"ui_";
- var fname = prefix+uiPath.substring(1).replace(/-/g, '$$');
- _code.given((fname !== prefix && appjet._internal.global[fname]) || "");
- _.dispatchPlus();
- }
- /**@ignore*/
- function getui_() {
- print(
- H1("Scenario '", request.pathTail, "' not found!"),
- P("Select from scenarios in the tabs, or create some ",
- "by creating functions with names of the form ",
- "getui_name$of$scenario"
- )
- );
- }
- /**@ignore*/
- function postui_() {
- print(
- H1("Scenario '", request.pathTail, "' not found!"),
- P("Select from scenarios in the tabs, or create some ",
- "by creating functions with names of the form ",
- "postui_name$of$scenario"
- )
- );
- }
- /* appjet:server */
- import("lib-support/ui-harness");
- // ====== Simulated import(appjet.appName) ======
- import("lib-app/liveui");
- var _lorem = "Lorem ipsum dolor amet. ";
- /**@ignore*/
- function renderUsingPrint(text) {
- print(H1("Using print functions"));
- printp("<",text,">; entity: &");
- }
- /**@ignore*/
- function getView() {
- return box(
- H1("Using testView function"),
- P("<",data(),">; entity: &")
- );
- }
- // ====== End of simulated import(appjet.appName) ======
- /**@ignore*/
- function getui_main() {
- printp(
- "This is harness for UIs. It is useful in scenario, ",
- "where you put UI of your application in a separate library, ",
- "because it's right to separate the domain (data and computation) ",
- "from the presentation (UI)."
- );
- printp(
- "You use this harness by importing it in /*appjet:server*/ part ",
- "of the UI library, then importing the library itself. ",
- "Then, you create scenarios of using the parts of your UI, ",
- "each in a function of form getui_name$of$scenario. ",
- "The harness automatically finds them and presents tabs ",
- "for selecting them. This way, you can develop UI ",
- "without resorting to real application running ",
- "and see how UI use cases look immediately without clicking through the app itself."
- );
- printp(
- "Though primarily aimed at testing UIs, you can use it ",
- "as simple tabbing interface, if your app only shows pages. ",
- "In this case, call showNoCode() to suppress showing code."
- );
- printp(
- "Create getui_main function to show the initial screen ",
- "(like this one). It is not included in tabs, ",
- "it is only used for the main screen."
- );
- }
- /**@ignore*/
- function getui_using$print() {
- renderUsingPrint(_lorem);
- }
- /**@ignore*/
- function getui_using$print$longer() {
- renderUsingPrint(_lorem+_lorem);
- }
- /**@ignore*/
- function getui_setting$test$view() {
- var v = getView();
- testView(v);
- v.given(_lorem+" && "+_lorem);
- }
- /* appjet:disabled */
- // In case you want to use harness only in some cases,
- // inspire by this code:
- import("lib-dispatch-plus");
- // for path /no-harness
- /**@ignore*/
- function get_no$harness() {
- print(H1("This is normal output"));
- printp("No harness code is intervening.");
- }
- // for other paths, including /
- /**@ignore*/
- function get_() {
- prepareHarness();
- harness(request.pathTail);
- }
- dispatchPlus();
- /* appjet:server */
- import("lib-app/patches");
- dispatchShouldSearchHere();
- prepareHarness();
- // prepareHarness includes mvp with autodispatch and dispatchPlus
- // so only creating get_ function is enough.
- /**@ignore*/
- function get_() {
- harness(request.pathTail);
- }
- import({}, "lib-app/mvp").mvp();
|