s c h e m a t i c s : c o o k b o o k

/ Cookbook.RecipeWebSettingsPanel

This Web


WebHome 
WebChanges 
TOC (with recipes)
NewRecipe 
WebTopicList 
WebStatistics 

Other Webs


Chicken
Cookbook
Erlang
Know
Main
Plugins
Sandbox
Scm
TWiki  

Schematics


Schematics Home
Sourceforge Page
SchemeWiki.org
Original Cookbook
RSS

Scheme Links


Schemers.org
Scheme FAQ
R5RS
SRFIs
Scheme Cross Reference
PLT Scheme SISC
Scheme48 SCM
MIT Scheme scsh
JScheme Kawa
Chicken Guile
Bigloo Tiny
Gambit LispMe
GaucheChez

Lambda the Ultimate
TWiki.org

Building settings panels for the web

Problem

We want to make settings panels without an Apply button so that changes take effect immediately, just as in most GNOME apps. We want to do this on the web.

Solution

First, using a template toolkit, let's describe the UI like this:

<html>
 <head>
  <script type="text/javascript" src="/utils.js"/>
 </head>
 <body>
  <h1>Settings</h1>
  <input type="checkbox" id="show-email"
     onclick="javascript:void(httpGetText('<? show-email?-toggle-url ?>'))"/> 
   Show email<br/>
 </body>
</html>

The <? and ?> markers begin and end mzpp escapes, and httpGetText is a wrapper around mozilla's/IE's/Opera's XMLHttpRequest object. Then we hook it up like this:

  ; start : request -> response
  (define (start initial-request)
    (send/suspend/dispatch
      (lambda (embed/url)
        (translate "settings.shtml"
                   `([show-email?-toggle-url
                        ,(embed/url
                           (lambda (req)
                             (printf "toggle show-email~n")
                             `(html (body "toggled"))))])))))

where the translate function takes a template file and its environment to produce the finished document.

Discussion

We need some support libraries: one in Scheme to handle the templating, and another in JavaScript? to provide httpGetText.

(Note: I'll move the Scheme code into its own recipe or PLaneT in a bit)

template.ss:

(module template mzscheme
  (provide translate translate/print translate/str)
  
  (require (lib "mzpp.ss" "preprocessor")
           (lib "xml.ss" "xml")
           (lib "etc.ss")
           (lib "string.ss"))
  
  (define (translate/print filename bindings)
    (parameterize ([current-namespace (make-namespace 'initial)]
                   [beg-mark "<?"]
                   [end-mark "?>"])
      (for-each (lambda (binding)
                  (namespace-set-variable-value! (car binding) (cadr binding)))
                bindings)
      (preprocess filename)))
  
  (define (translate/str filename bindings)
    (define os (open-output-string))
    (parameterize ([current-output-port os])
      (translate/print filename bindings))
    (get-output-string os))
  
  (define (translate filename bindings)
    (define-values (in out) (make-pipe))
    (thread (lambda ()
              (parameterize ([current-output-port out])
                (translate/print filename bindings))
              (close-output-port out)))
    (xml->xexpr (document-element (read-xml in))))
  )

utils.js:

function makeReqObj() { return new XMLHttpRequest(); }
  
function httpSendGeneric(method, url, content, errorHandler) {
  try {
    netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
  } catch (e) {
    softError("httpSendGeneric",
               e.toString() + " Could not enable UniversalBrowserRead privilege.");
  }

  try {
    var http = makeReqObj();
    if (!http) {
      if (errorHandler) errorHandler("httpSendGeneric", "could not create http object");
      else softError("httpSendGeneric", "could not create http object");
    }
    http.open(method, url, false);
    http.send(content);
    httpCheckOK(http, errorHandler);
    return http;
  } catch (e) {
    if (errorHandler) errorHandler("httpSendGeneric", e.toString());
    else softError("httpSendGeneric", e.toString());
      return null;
  }
}
  
function httpGetGeneric(url, errorHandler) {
  return httpSendGeneric("GET", url, null, errorHandler);
}

function httpPostGeneric(url, content, errorHandler) {
  return httpSendGeneric("POST", url, content, errorHandler);
}

function httpGetGenericK(url, k, errorHandler) {
  var http = makeReqObj();
  http.open("GET", url, true);
  http.onreadystatechange = function () {
    // 4 means loaded
    if (http.readyState == 4) {
      httpCheckOK(http, errorHandler);
      k(http);
    }
  }
}

function softError(callerName, msg) {
  alert(msg);
}
  
function httpCheckOK(http, errorHandler) {
  if (http.status == 200) {
    //alert("looks ok");
    return;
  } else if (errorHandler) {
    errorHandler(http);
  }else {
    softError("http", http.statusText);
  }
}

function httpGetK(url, k, errorHandler) {
  httpGetGenericK(url,
                  function (http) {k(http.responseXML);},
                  errorHandler);
}

function httpGetKText(url, k, errorHandler) {
  httpGetGenericK(url,
                  function (http) {k(http.responseText);},
                  errorHandler);
}

function DOMParseText(str, contentType, errorHandler) {
  try {
    return (new DOMParser()).parseFromString(str, contentType);
  } catch (e) {
    if (errorHandler) errorHandler("DOMParseText", e);
    else softError("DOMParseText", e);
    return null;
  }
}

function httpGetHTML(url,errorHandler) {
  return DOMParseText(httpGetText(url, errorHandler),
                      "text/html", errorHandler);
}

function httpGetXML(url,errorHandler) {
  return DOMParseText(httpGetText(url, errorHandler),
                      "text/xml", errorHandler);
}

function httpGetText(url, errorHandler) {
  return httpGetGeneric(url, errorHandler).responseText;
}

function httpPost(url, content, errorHandler) {
  return httpPostGeneric(url, content, errorHandler).responseXML;
}


Comments about this recipe

Contributors

-- DanielSilva - 11 Jan 2005

CookbookForm
TopicType: Recipe
ParentTopic:
TopicOrder: 999

 
 
Copyright © 2004 by the contributing authors. All material on the Schematics Cookbook web site is the property of the contributing authors.
The copyright for certain compilations of material taken from this website is held by the SchematicsEditorsGroup - see ContributorAgreement & LGPL.
Other than such compilations, this material can be redistributed and/or modified under the terms of the GNU Lesser General Public License (LGPL), version 2.1, as published by the Free Software Foundation.
Ideas, requests, problems regarding Schematics Cookbook? Send feedback.
/ You are Main.guest