dev tools
authorphasefx <phasefx@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Sun, 11 Dec 2005 07:33:22 +0000 (07:33 +0000)
committerphasefx <phasefx@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Sun, 11 Dec 2005 07:33:22 +0000 (07:33 +0000)
git-svn-id: svn://svn.open-ils.org/ILS/trunk@2332 dcc99617-32d9-48b4-a31d-7c20da2025e4

Open-ILS/xul/staff_client/chrome/content/evergreen/util/filter_console.xul [new file with mode: 0644]
Open-ILS/xul/staff_client/chrome/content/evergreen/util/fm_view.xul [new file with mode: 0644]
Open-ILS/xul/staff_client/chrome/content/evergreen/util/shell.html [new file with mode: 0644]
Open-ILS/xul/staff_client/chrome/content/evergreen/util/xuledit.js [new file with mode: 0644]
Open-ILS/xul/staff_client/chrome/content/evergreen/util/xuledit.xul [new file with mode: 0644]

diff --git a/Open-ILS/xul/staff_client/chrome/content/evergreen/util/filter_console.xul b/Open-ILS/xul/staff_client/chrome/content/evergreen/util/filter_console.xul
new file mode 100644 (file)
index 0000000..2b8b9c3
--- /dev/null
@@ -0,0 +1,166 @@
+<?xml version="1.0"?>
+<!-- Application: Evergreen Staff Client -->
+<!-- Screen: About -->
+
+<!-- Stylesheets -->
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<?xml-stylesheet href="chrome://evergreen/skin/evergreen.css" type="text/css"?>
+
+<window id="filter_console_win" 
+       onload="try { my_init(); } catch(E) { alert(E); }"
+       xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+       <script>mw.sdump('D_TRACE','Loading filter_console.xul\n');</script>
+
+       <script>
+       <![CDATA[
+
+               var rows; var containing; var not_containing;
+
+               function my_init() {
+
+                       rows = document.getElementById('filter_console_grid_rows');
+                       containing = document.getElementById('filter_console_containing');
+                       not_containing = document.getElementById('filter_console_not_containing');
+                       
+                       mw.filter_console_init( {'observe_msg':observe_msg} );
+                       build_sdump_menu();
+               }
+
+               function build_sdump_menu() {
+                       try {
+                               var mp = document.getElementById('fcmp');
+                               for (var i in mw.sdump_levels) {
+                                       var m = document.createElement( 'menuitem' );
+                                       mp.appendChild(m);
+                                       m.setAttribute('type','checkbox');
+                                       m.setAttribute('label',i);
+                                       m.setAttribute('checked',mw.sdump_levels[i]);
+                                       m.setAttribute('oncommand',
+                                               "mw.sdump_levels."+i+"=!mw.sdump_levels."+i+
+                                               "; this.setAttribute('checked',mw.sdump_levels."+i+");");
+                               }
+                       } catch(E) {
+                               alert(E);
+                       }
+               }
+
+               function observe_msg(msg) {
+
+                       try {
+                               var row = document.createElement('row');
+                               rows.appendChild(row);
+
+                               var hbox = document.createElement('hbox');
+                               row.appendChild(hbox);
+                               hbox.flex = 1;
+
+                               var tb = document.createElement('textbox');
+                               hbox.appendChild(tb);
+                               tb.setAttribute('multiline','true');
+                               tb.setAttribute('readonly','true');
+                               tb.setAttribute('rows','5');
+                               tb.setAttribute('flex','1');
+                               tb.setAttribute('value',msg.message);
+
+                       } catch(E) { dump(E) }
+               }
+
+               function test_filter(msg) {
+                       var pass = true;
+                       var c_array = containing.value.split(' ');
+                       var nc_array = not_containing.value.split(' ');
+                       for (var i = 0; i < c_array.length; i++) {
+                               var term = c_array[i];
+                               if (term != '' && term != null && term != undefined)
+                                       if (! msg.match( term ) )
+                                               pass = false;
+                       }
+                       for (var i = 0; i < nc_array.length; i++) {
+                               var term = nc_array[i];
+                               if (term != '' && term != null && term != undefined)
+                                       if (msg.match( term ) )
+                                               pass = false;
+                       }
+                       return pass;
+               }
+
+               function clear_rows(prune) {
+                       var delete_these = [];
+                       for (var i = 0; i < rows.childNodes.length; i++) {
+                               var row = rows.childNodes[i];
+                               var tb = row.firstChild.firstChild;
+                               var delete_me = ! test_filter(tb.value);
+                               if (!prune) delete_me = true;
+                               if (delete_me) delete_these.push( row ); 
+                       }
+                       var row; while (row = delete_these.pop()) { rows.removeChild(row); }
+               }
+
+               function hide_rows() {
+                       for (var i = 0; i < rows.childNodes.length; i++) {
+                               var row = rows.childNodes[i];
+                               var tb = row.firstChild.firstChild;
+                               row.hidden = ! test_filter(tb.value);
+                       }
+               }
+
+               function calc_delta() {
+                       var first;
+                       var last;
+                       for (var i = 0; i < rows.childNodes.length; i++) {
+                               var row = rows.childNodes[i];
+                               if (! row.hidden ) {
+                                       var tb = row.firstChild.firstChild;
+                                       if (!first) first = parseInt( tb.value.split(' ')[0] );
+                                       last = parseInt( tb.value.split(' ')[0] );
+                               }
+                       }
+                       document.getElementById('fc_calc_delta_label').setAttribute('value',last-first);
+               }
+
+       ]]>
+       </script>
+
+       <popupset>
+               <menupopup id="fcmp" position="after_start">
+               </menupopup>
+       </popupset>
+
+       <vbox id="filter_console_vbox" flex="1">
+               <groupbox id="filter_console_groupbox" orient="vertical" flex="1">
+                       <caption id="fcgbc" label="Filterable Javascript Console"/>
+                       <grid id="filter_console_nav_grid">
+                               <columns id="fcnvc"><column id="fcnvc1"/><column id="fcnvc2" flex="1"/></columns>
+                               <rows id="fcnvr">
+                                       <row id="fcnvr1">
+                                               <label id="fcgbhb1l" value="Containing:" class="text_right" accesskey="o" control="filter_console_containing"/>
+                                               <textbox id="filter_console_containing" flex="1"/>
+                                       </row>
+                                       <row id="fcnvr2">
+                                               <label id="fcgbhb1l" value="Not Containing:" class="text_right" accesskey="N" control="filter_console_not_containing"/>
+                                               <textbox id="filter_console_not_containing" flex="1"/>
+                                       </row>
+                                       <row id="fcnvr3">
+                                               <spacer id="fcnvr3s1"/>
+                                               <hbox id="fcnvr3hb1" flex="1">
+                                                       <button id="fc_sdump_levels" popup="fcmp" label="Set SDUMP Logging" accesskey="S"/>
+                                                       <button id="fc_filter_view" label="View with Filters" accesskey="V" oncommand="hide_rows();"/>
+                                                       <button id="fc_calc_delta" label="Delta (Last-1st sdump)" accesskey="D" oncommand="calc_delta();"/>
+                                                       <label id="fc_calc_delta_label" />
+                                                       <spacer id="fcnvr3hb1s1" flex="1"/>
+                                                       <button id="fc_filter_prune" label="Prune Hidden" accesskey="P" oncommand="clear_rows(true);"/>
+                                                       <button id="fc_clear" label="Clear" accesskey="C" oncommand="clear_rows(false);"/>
+                                               </hbox>
+                                       </row>
+                               </rows>
+                       </grid>
+                       <grid id="filter_console_grid" flex="1" style="overflow: auto;">
+                               <columns id="fcgc"><column id="fcgc1" flex="1"/></columns>
+                               <rows id="filter_console_grid_rows"/>
+                       </grid>
+               </groupbox>
+       </vbox>
+
+</window>
+
diff --git a/Open-ILS/xul/staff_client/chrome/content/evergreen/util/fm_view.xul b/Open-ILS/xul/staff_client/chrome/content/evergreen/util/fm_view.xul
new file mode 100644 (file)
index 0000000..ddbd561
--- /dev/null
@@ -0,0 +1,159 @@
+<?xml version="1.0"?>
+<!-- Application: Evergreen Staff Client -->
+<!-- Screen: About -->
+
+<!-- Stylesheets -->
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<?xml-stylesheet href="chrome://evergreen/skin/evergreen.css" type="text/css"?>
+
+<window id="fm_view_win" 
+       onload="try { my_init(); } catch(E) { alert(E); }"
+       xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+       <script>mw.sdump('D_TRACE','Loading fm_view.xul\n');</script>
+
+       <script>
+       <![CDATA[
+               var tree;
+
+               function my_init() {
+                       var treechildren = window.document.getElementById('tc');
+                       var fm = mw.user_request('open-ils.actor','opensrf.open-ils.system.fieldmapper',[])[0];
+                       var fma = []; var fmh = {} ; 
+                       for (var i in fm) { fmh[ fm[i].hint ] = fm[i]; fma.push( [ fm[i].hint, i ] ); }
+                       fma.sort();
+                       for (var i = 0; i < fma.length; i++) {
+                               var hint = fma[i][0]; var name = fma[i][1]; var o = fmh[ hint ];
+                               var ti = window.document.createElement('treeitem');
+                               treechildren.appendChild( ti );
+                               ti.setAttribute( 'container', 'true' );
+                               var tr = window.document.createElement('treerow');
+                               ti.appendChild( tr );
+                               var tc = window.document.createElement('treecell');
+                               tr.appendChild( tc );
+                               tc.setAttribute('label',hint);
+                               tc = window.document.createElement('treecell');
+                               tr.appendChild( tc );
+                               tc.setAttribute('label', name );
+                               var _treechildren = window.document.createElement( 'treechildren' );
+                               ti.appendChild( _treechildren );
+                               for (var j in o.fields) {
+                                       var _ti = window.document.createElement( 'treeitem' );
+                                       _treechildren.appendChild( _ti );
+                                       _ti.setAttribute('fm_class',hint);
+                                       _ti.setAttribute('fm_field',j);
+                                       _ti.setAttribute('fm_virtual',o.fields[j].virtual);
+                                       _ti.setAttribute('fm_position',o.fields[j].position);
+                                       var _tr = window.document.createElement( 'treerow' );
+                                       _ti.appendChild( _tr );
+                                       var _tc = window.document.createElement( 'treecell' );
+                                       _tr.appendChild( _tc );
+                                       _tc.setAttribute('label',j);
+                                       _tc = window.document.createElement( 'treecell' );
+                                       _tr.appendChild( _tc );
+                                       _tc.setAttribute('label','\t         Position: ' + o.fields[j].position + '  Virtual: ' + o.fields[j].virtual);
+                               }
+                       }
+                       tree = window.document.getElementById('t');
+                       tree.view.selection.select( 0 ); tree.focus();
+               }
+
+               function gen_cols() {
+                       var data_url = 'data:application/vnd.mozilla.xul+xml,<?xml version="1.0"?><window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"><?xml-stylesheet href="chrome://global/skin" type="text/css"?><vbox flex="1"><textbox id="desc" multiline="true" flex="1"/></vbox></window>';
+                       var w = mw.SafeWindowOpen(data_url,'paged_tree cols','chrome,resizable,width=800,height=600');
+                       var css = '<?xml-stylesheet href="data:text/css,#a{-moz-box-flex:1;}"?>';
+                       var treeitems = mw.get_list_from_tree_selection( tree );
+                       setTimeout(
+                               function() {
+                                       var tb = w.document.getElementById('desc');
+                                       for (var i = 0; i < treeitems.length; i++) {
+                                               var hint = treeitems[i].getAttribute('fm_class');
+                                               var field = treeitems[i].getAttribute('fm_field');
+                                               var text = (
+                                                       "{\n\t'id' : '" + field + "', 'label' : getString('" + hint + "_" + 
+                                                       field + "_label'), 'flex' : 1,\n" + 
+                                                       "\t'primary' : false, 'hidden' : false, 'fm_class' : '" + hint + 
+                                                       "', 'fm_field_render' : '." + field + "()'\n},\n"
+                                               );
+                                               tb.value += text;
+                                       }
+                                       dump(tb.value + '\n');
+                               }, 0
+                       );
+               }
+
+               function gen_properties() {
+                       var data_url = 'data:application/vnd.mozilla.xul+xml,<?xml version="1.0"?><window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"><?xml-stylesheet href="chrome://global/skin" type="text/css"?><vbox flex="1"><textbox id="desc" multiline="true" flex="1"/></vbox></window>';
+                       var w = mw.SafeWindowOpen(data_url,'paged_tree cols','chrome,resizable,width=800,height=600');
+                       var css = '<?xml-stylesheet href="data:text/css,#a{-moz-box-flex:1;}"?>';
+                       var treeitems = mw.get_list_from_tree_selection( tree );
+                       setTimeout(
+                               function() {
+                                       var tb = w.document.getElementById('desc');
+                                       for (var i = 0; i < treeitems.length; i++) {
+                                               var hint = treeitems[i].getAttribute('fm_class');
+                                               var field = treeitems[i].getAttribute('fm_field');
+                                               var pretty = mw.map_list(
+                                                       field.split('_'),
+                                                       function (s) {
+                                                               return s.substr(0,1).toUpperCase() + s.substr(1);
+                                                       }
+                                               ).join(' ');
+                                               var text = (
+                                                       hint + '_' + field + '_label=' + pretty + '\n'
+                                               );
+                                               tb.value += text;
+                                       }
+                                       dump(tb.value + '\n');
+                               }, 0
+                       );
+               }
+
+               function gen_wikitable() {
+                       var data_url = 'data:application/vnd.mozilla.xul+xml,<?xml version="1.0"?><window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"><?xml-stylesheet href="chrome://global/skin" type="text/css"?><vbox flex="1"><textbox id="desc" multiline="true" flex="1"/></vbox></window>';
+                       var w = mw.SafeWindowOpen(data_url,'paged_tree cols','chrome,resizable,width=800,height=600');
+                       var css = '<?xml-stylesheet href="data:text/css,#a{-moz-box-flex:1;}"?>';
+                       var treeitems = mw.get_list_from_tree_selection( tree );
+                       setTimeout(
+                               function() {
+                                       var tb = w.document.getElementById('desc');
+                                       for (var i = 0; i < treeitems.length; i++) {
+                                               var hint = treeitems[i].getAttribute('fm_class');
+                                               var field = treeitems[i].getAttribute('fm_field');
+                                               var text = (
+                                                       '|' + hint + '|' + field
+                                               );
+                                       
+                                               if (treeitems[i].getAttribute('fm_virtual') == '1') text += ' * ';
+                                               text += '|\n'
+                                               tb.value += text;
+                                       }
+                                       dump(tb.value + '\n');
+                               }, 0
+                       );
+               }
+
+
+       ]]>
+       </script>
+
+       <vbox flex="1" class="my_overflow">
+               <groupbox orient="vertical" flex="1">
+                       <caption label="Fieldmapper Class Viewer"/>
+                       <hbox>
+                               <button label="Generate paged_tree cols for selected fields" accesskey="G" oncommand="gen_cols();"/>
+                               <button label="Generate string bundle properties for selected fields" accesskey="P" oncommand="gen_properties();"/>
+                               <button label="Generate dokuwiki table for selected fields" accesskey="P" oncommand="gen_wikitable();"/>
+                       </hbox>
+                       <tree id="t" flex="1">
+                               <treecols>
+                                       <treecol id="tcol1" label="opensrf.open-ils.system.fieldmapper" primary="true" flex="0"/>
+                                       <treecol id="tcol2" label="" flex="1"/>
+                               </treecols>
+                               <treechildren id="tc"/>
+                       </tree>
+               </groupbox>
+       </vbox>
+
+</window>
+
diff --git a/Open-ILS/xul/staff_client/chrome/content/evergreen/util/shell.html b/Open-ILS/xul/staff_client/chrome/content/evergreen/util/shell.html
new file mode 100644 (file)
index 0000000..ca5a215
--- /dev/null
@@ -0,0 +1,690 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+
+<html onclick="keepFocusInTextbox(event)">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<title>JavaScript Shell 1.3.1</title>
+
+<script type="text/javascript">
+// Modified by Jason for Evergreen
+var 
+histList = [""], 
+histPos = 0, 
+_scope = {}, 
+_win, // a top-level context
+question,
+_in,
+_out,
+tooManyMatches = null,
+lastError = null;
+
+function refocus()
+{
+  _in.blur(); // Needed for Mozilla to scroll correctly.
+  _in.focus();
+}
+
+function init()
+{
+  _in = document.getElementById("input");
+  _out = document.getElementById("output");
+
+  _win = window;
+
+  if (opener && !opener.closed)
+  {
+    println("Using bookmarklet version of shell: commands will run in opener's context.", "message");
+    _win = opener;
+  }
+
+  initTarget();
+
+  recalculateInputHeight();
+  refocus();
+}
+
+function initTarget()
+{
+  _win.Shell = window;
+  _win.print = shellCommands.print;
+}
+
+
+// Unless the user is selected something, refocus the textbox.
+// (requested by caillon, brendan, asa)
+function keepFocusInTextbox(e) 
+{
+  var g = e.srcElement ? e.srcElement : e.target; // IE vs. standard
+  
+  while (!g.tagName)
+    g = g.parentNode;
+  var t = g.tagName.toUpperCase();
+  if (t=="A" || t=="INPUT")
+    return;
+    
+  if (window.getSelection) {
+    // Mozilla
+    if (String(window.getSelection()))
+      return;
+  }
+  else if (document.getSelection) {
+    // Opera? Netscape 4?
+    if (document.getSelection())
+      return;
+  }
+  else {
+    // IE
+    if ( document.selection.createRange().text )
+      return;
+  }
+  
+  refocus();
+}
+
+function inputKeydown(e) {
+  // Use onkeydown because IE doesn't support onkeypress for arrow keys
+
+  //alert(e.keyCode + " ^ " + e.keycode);
+
+  if (e.shiftKey && e.keyCode == 13) { // shift-enter
+    // don't do anything; allow the shift-enter to insert a line break as normal
+  } else if (e.keyCode == 13) { // enter
+    // execute the input on enter
+    try { go(); } catch(er) { alert(er); };
+    setTimeout(function() { _in.value = ""; }, 0); // can't preventDefault on input, so clear it later
+  } else if (e.keyCode == 38) { // up
+    // go up in history if at top or ctrl-up
+    if (e.ctrlKey || _in.selectionStart == null || _in.selectionStart == 0)
+      hist(true);
+  } else if (e.keyCode == 40) { // down
+    // go down in history if at end or ctrl-down
+    if (e.ctrlKey || _in.selectionStart == null || _in.selectionEnd == _in.textLength)
+      hist(false);
+  } else if (e.keyCode == 9) { // tab
+    tabcomplete();
+    setTimeout(function() { refocus(); }, 0); // refocus because tab was hit
+  } else { }
+
+  setTimeout(recalculateInputHeight, 0);
+  
+  //return true;
+};
+
+function recalculateInputHeight()
+{
+  var rows = _in.value.split(/\n/).length
+    + 1 // prevent scrollbar flickering in Mozilla
+    + (window.opera ? 1 : 0); // leave room for scrollbar in Opera
+  
+  if (_in.rows != rows) // without this check, it is impossible to select text in Opera 7.60 or Opera 8.0.
+    _in.rows = rows;
+}
+
+function println(s, type)
+{
+  if((s=String(s)))
+  {
+    var newdiv = document.createElement("div");
+    newdiv.appendChild(document.createTextNode(s));
+    newdiv.className = type;
+    _out.appendChild(newdiv);
+    return newdiv;
+  }
+}
+
+function printWithRunin(h, s, type)
+{
+  var div = println(s, type);
+  var head = document.createElement("strong");
+  head.appendChild(document.createTextNode(h + ": "));
+  div.insertBefore(head, div.firstChild);
+}
+
+
+var shellCommands = 
+{
+load : function load(url)
+{
+  var s = _win.document.createElement("script");
+  s.type = "text/javascript";
+  s.src = url;
+  _win.document.getElementsByTagName("head")[0].appendChild(s);
+  println("Loading " + url + "...", "message");
+},
+
+print : function print(s) { println(s, "print"); },
+
+// the normal function, "print", shouldn't return a value
+// (suggested by brendan; later noticed it was a problem when showing others)
+pr : function pr(s) 
+{ 
+  shellCommands.print(s); // need to specify shellCommands so it doesn't try window.print()!
+  return s;
+},
+
+props : function props(e)
+{
+  var ns = ["Methods", "Fields", "Unreachables"];
+  var as = [[], [], []]; // array of (empty) arrays of arrays!
+  var p, j, i; // loop variables, several used multiple times
+
+  var protoLevels = 0;
+
+  for (p = e; p; p = p.__proto__)
+  {
+    for (i=0; i<ns.length; ++i)
+      as[i][protoLevels] = [];
+    ++protoLevels;
+  }
+
+  for(var a in e)
+  {
+    // Shortcoming: doesn't check that VALUES are the same in object and prototype.
+
+    var protoLevel = -1;
+    try
+    {
+      for (p = e; p && (a in p); p = p.__proto__)
+        ++protoLevel;
+    }
+    catch(er) { protoLevel = 0; } // "in" operator throws when param to props() is a string
+
+    var type = 1;
+    try
+    {
+      if ((typeof e[a]) == "function")
+        type = 0;
+    }
+    catch (er) { type = 2; }
+
+    as[type][protoLevel].push(a);
+  }
+
+  function times(s, n) { return n ? s + times(s, n-1) : ""; }
+
+  for (j=0; j<protoLevels; ++j)
+    for (i=0;i<ns.length;++i)
+      if (as[i][j].length) 
+        printWithRunin(ns[i] + times(" of prototype", j), as[i][j].join(", "), "propList");
+},
+
+blink : function blink(node)
+{
+  if (!node)                     throw("blink: argument is null or undefined.");
+  if (node.nodeType == null)     throw("blink: argument must be a node.");
+  if (node.nodeType == 3)        throw("blink: argument must not be a text node");
+  if (node.documentElement)      throw("blink: argument must not be the document object");
+
+  function setOutline(o) { 
+    return function() {
+      if (node.style.outline != node.style.bogusProperty) {
+        // browser supports outline (Firefox 1.1 and newer, CSS3, Opera 8).
+        node.style.outline = o;
+      }
+      else if (node.style.MozOutline != node.style.bogusProperty) {
+        // browser supports MozOutline (Firefox 1.0.x and older)
+        node.style.MozOutline = o;
+      }
+      else {
+        // browser only supports border (IE). border is a fallback because it moves things around.
+        node.style.border = o;
+      }
+    }
+  } 
+  
+  function focusIt(a) {
+    return function() {
+      a.focus(); 
+    }
+  }
+
+  if (node.ownerDocument) {
+    var windowToFocusNow = (node.ownerDocument.defaultView || node.ownerDocument.parentWindow); // Moz vs. IE
+    if (windowToFocusNow)
+      setTimeout(focusIt(windowToFocusNow.top), 0);
+  }
+
+  for(var i=1;i<7;++i)
+    setTimeout(setOutline((i%2)?'3px solid red':'none'), i*100);
+
+  setTimeout(focusIt(window), 800);
+  setTimeout(focusIt(_in), 810);
+},
+
+scope : function scope(sc)
+{
+  if (!sc) sc = {};
+  _scope = sc;
+  println("Scope is now " + sc + ".  If a variable is not found in this scope, window will also be searched.  New variables will still go on window.", "message");
+},
+
+mathHelp : function mathHelp()
+{
+  printWithRunin("Math constants", "E, LN2, LN10, LOG2E, LOG10E, PI, SQRT1_2, SQRT2", "propList");
+  printWithRunin("Math methods", "abs, acos, asin, atan, atan2, ceil, cos, exp, floor, log, max, min, pow, random, round, sin, sqrt, tan", "propList");
+},
+
+ans : undefined,
+
+cls : function cls()
+{
+       while (_out.lastChild) { _out.removeChild( _out.lastChild ); }
+}
+};
+
+
+function hist(up)
+{
+  // histList[0] = first command entered, [1] = second, etc.
+  // type something, press up --> thing typed is now in "limbo"
+  // (last item in histList) and should be reachable by pressing 
+  // down again.
+
+  var L = histList.length;
+
+  if (L == 1)
+    return;
+
+  if (up)
+  {
+    if (histPos == L-1)
+    {
+      // Save this entry in case the user hits the down key.
+      histList[histPos] = _in.value;
+    }
+
+    if (histPos > 0)
+    {
+      histPos--;
+      // Use a timeout to prevent up from moving cursor within new text
+      // Set to nothing first for the same reason
+      setTimeout(
+        function() {
+          _in.value = ''; 
+          _in.value = histList[histPos]; 
+          if (_in.setSelectionRange) 
+            _in.setSelectionRange(0, 0);
+        },
+        0
+      );
+    }
+  } 
+  else // down
+  {
+    if (histPos < L-1)
+    {
+      histPos++;
+      _in.value = histList[histPos];
+    }
+    else if (histPos == L-1)
+    {
+      // Already on the current entry: clear but save
+      if (_in.value)
+      {
+        histList[histPos] = _in.value;
+        ++histPos;
+        _in.value = "";
+      }
+    }
+  }
+}
+
+function tabcomplete()
+{
+  /*
+   * Working backwards from s[from], find the spot
+   * where this expression starts.  It will scan
+   * until it hits a mismatched ( or a space,
+   * but it skips over quoted strings.
+   * If stopAtDot is true, stop at a '.'
+   */
+  function findbeginning(s, from, stopAtDot)
+  {
+    /*
+     *  Complicated function.
+     *
+     *  Return true if s[i] == q BUT ONLY IF
+     *  s[i-1] is not a backslash.
+     */
+    function equalButNotEscaped(s,i,q)
+    {
+      if(s.charAt(i) != q) // not equal go no further
+        return false;
+
+      if(i==0) // beginning of string
+        return true;
+
+      if(s.charAt(i-1) == '\\') // escaped?
+        return false;
+
+      return true;
+    }
+
+    var nparens = 0;
+    var i;
+    for(i=from; i>=0; i--)
+    {
+      if(s.charAt(i) == ' ')
+        break;
+
+      if(stopAtDot && s.charAt(i) == '.')
+        break;
+        
+      if(s.charAt(i) == ')')
+        nparens++;
+      else if(s.charAt(i) == '(')
+        nparens--;
+
+      if(nparens < 0)
+        break;
+
+      // skip quoted strings
+      if(s.charAt(i) == '\'' || s.charAt(i) == '\"')
+      {
+        //dump("skipping quoted chars: ");
+        var quot = s.charAt(i);
+        i--;
+        while(i >= 0 && !equalButNotEscaped(s,i,quot)) {
+          //dump(s.charAt(i));
+          i--;
+        }
+        //dump("\n");
+      }
+    }
+    return i;
+  }
+
+  function getcaretpos(inp)
+  {
+    if(inp.selectionEnd)
+      return inp.selectionEnd;
+
+    if(inp.createTextRange)
+    {
+      //dump('using createTextRange\n');
+      var docrange = _win.Shell.document.selection.createRange();
+      var inprange = inp.createTextRange();
+      inprange.setEndPoint('EndToStart', docrange);
+      return inprange.text.length;
+    }
+
+    return inp.value.length; // sucks, punt
+  }
+
+  function setselectionto(inp,pos)
+  {
+    if(inp.selectionStart) {
+      inp.selectionStart = inp.selectionEnd = pos;
+    }
+    else if(inp.createTextRange) {
+      var docrange = _win.Shell.document.selection.createRange();
+      var inprange = inp.createTextRange();
+      inprange.move('character',pos);
+      inprange.select();
+    }
+    else { // err...
+    /*
+      inp.select();
+      if(_win.Shell.document.getSelection())
+        _win.Shell.document.getSelection() = "";
+        */
+    }
+  }
+    // get position of cursor within the input box
+    var caret = getcaretpos(_in);
+
+    if(caret) {
+      //dump("----\n");
+      var dotpos, spacepos, complete, obj;
+      //dump("caret pos: " + caret + "\n");
+      // see if there's a dot before here
+      dotpos = findbeginning(_in.value, caret-1, true);
+      //dump("dot pos: " + dotpos + "\n");
+      if(dotpos == -1 || _in.value.charAt(dotpos) != '.') {
+        dotpos = caret;
+//dump("changed dot pos: " + dotpos + "\n");
+      }
+
+      // look backwards for a non-variable-name character
+      spacepos = findbeginning(_in.value, dotpos-1, false);
+      //dump("space pos: " + spacepos + "\n");
+      // get the object we're trying to complete on
+      if(spacepos == dotpos || spacepos+1 == dotpos || dotpos == caret)
+      {
+        // try completing function args
+        if(_in.value.charAt(dotpos) == '(' ||
+ (_in.value.charAt(spacepos) == '(' && (spacepos+1) == dotpos))
+        {
+          var fn,fname;
+  var from = (_in.value.charAt(dotpos) == '(') ? dotpos : spacepos;
+          spacepos = findbeginning(_in.value, from-1, false);
+
+          fname = _in.value.substr(spacepos+1,from-(spacepos+1));
+  //dump("fname: " + fname + "\n");
+          try {
+            with(_win.Shell._scope)
+              with(_win)
+                with(Shell.shellCommands)
+                  fn = eval(fname);
+          }
+          catch(er) {
+            //dump('fn is not a valid object\n');
+            return;
+          }
+          if(fn == undefined) {
+             //dump('fn is undefined');
+             return;
+          }
+          if(fn instanceof Function)
+          {
+            // Print function definition, including argument names, but not function body
+            if(!fn.toString().match(/function .+?\(\) +\{\n +\[native code\]\n\}/))
+              println(fn.toString().match(/function .+?\(.*?\)/), "tabcomplete");
+          }
+
+          return;
+        }
+        else
+          obj = _win;
+      }
+      else
+      {
+        var objname = _in.value.substr(spacepos+1,dotpos-(spacepos+1));
+        //dump("objname: |" + objname + "|\n");
+        try {
+          with(_win.Shell._scope)
+            with(_win)
+                obj = eval(objname);
+        }
+        catch(er) {
+          printError(er); 
+          return;
+        }
+        if(obj == undefined) {
+          // sometimes this is tabcomplete's fault, so don't print it :(
+          // e.g. completing from "print(document.getElements"
+          // println("Can't complete from null or undefined expression " + objname, "error");
+          return;
+        }
+      }
+      //dump("obj: " + obj + "\n");
+      // get the thing we're trying to complete
+      if(dotpos == caret)
+      {
+        if(spacepos+1 == dotpos || spacepos == dotpos)
+        {
+          // nothing to complete
+          //dump("nothing to complete\n");
+          return;
+        }
+
+        complete = _in.value.substr(spacepos+1,dotpos-(spacepos+1));
+      }
+      else {
+        complete = _in.value.substr(dotpos+1,caret-(dotpos+1));
+      }
+      //dump("complete: " + complete + "\n");
+      // ok, now look at all the props/methods of this obj
+      // and find ones starting with 'complete'
+      var matches = [];
+      var bestmatch = null;
+      for(var a in obj)
+      {
+        //a = a.toString();
+        //XXX: making it lowercase could help some cases,
+        // but screws up my general logic.
+        if(a.substr(0,complete.length) == complete) {
+          matches.push(a);
+          ////dump("match: " + a + "\n");
+          // if no best match, this is the best match
+          if(bestmatch == null)
+          {
+            bestmatch = a;
+          }
+          else {
+            // the best match is the longest common string
+            function min(a,b){ return ((a<b)?a:b); }
+            var i;
+            for(i=0; i< min(bestmatch.length, a.length); i++)
+            {
+              if(bestmatch.charAt(i) != a.charAt(i))
+                break;
+            }
+            bestmatch = bestmatch.substr(0,i);
+            ////dump("bestmatch len: " + i + "\n");
+          }
+          ////dump("bestmatch: " + bestmatch + "\n");
+        }
+      }
+      bestmatch = (bestmatch || "");
+      ////dump("matches: " + matches + "\n");
+      var objAndComplete = (objname || obj) + "." + bestmatch;
+      //dump("matches.length: " + matches.length + ", tooManyMatches: " + tooManyMatches + ", objAndComplete: " + objAndComplete + "\n");
+      if(matches.length > 1 && (tooManyMatches == objAndComplete || matches.length <= 10)) {
+
+        printWithRunin("Matches: ", matches.join(', '), "tabcomplete");
+        tooManyMatches = null;
+      }
+      else if(matches.length > 10)
+      {
+        println(matches.length + " matches.  Press tab again to see them all", "tabcomplete");
+        tooManyMatches = objAndComplete;
+      }
+      else {
+        tooManyMatches = null;
+      }
+      if(bestmatch != "")
+      {
+        var sstart;
+        if(dotpos == caret) {
+          sstart = spacepos+1;
+        }
+        else {
+          sstart = dotpos+1;
+        }
+        _in.value = _in.value.substr(0, sstart)
+                  + bestmatch
+                  + _in.value.substr(caret);
+        setselectionto(_in,caret + (bestmatch.length - complete.length));
+      }
+    }
+}
+
+function printQuestion(q)
+{
+  println(q, "input");
+}
+
+function printAnswer(a)
+{
+  if (a !== undefined) {
+    println(a, "normalOutput");
+    shellCommands.ans = a;
+  }
+}
+
+function printError(er)
+{ 
+  var lineNumberString;
+
+  lastError = er; // for debugging the shell
+  if (er.name)
+  {
+    // lineNumberString should not be "", to avoid a very wacky bug in IE 6.
+    lineNumberString = (er.lineNumber != undefined) ? (" on line " + er.lineNumber + ": ") : ": ";
+    println(er.name + lineNumberString + er.message, "error"); // Because IE doesn't have error.toString.
+  }
+  else
+    println(er, "error"); // Because security errors in Moz /only/ have toString.
+}
+
+function go(s)
+{
+  _in.value = question = s ? s : _in.value;
+
+  if (question == "")
+    return;
+
+  histList[histList.length-1] = question;
+  histList[histList.length] = "";
+  histPos = histList.length - 1;
+  
+  // Unfortunately, this has to happen *before* the JavaScript is run, so that 
+  // print() output will go in the right place.
+  _in.value='';
+  recalculateInputHeight();
+  printQuestion(question);
+
+  if (_win.closed) {
+    printError("Target window has been closed.");
+    return;
+  }
+  
+  try { ("Shell" in _win) }
+  catch(er) {
+    printError("The JavaScript Shell cannot access variables in the target window.  The most likely reason is that the target window now has a different page loaded and that page has a different hostname than the original page.");
+    return;
+  }
+
+  if (!("Shell" in _win))
+    initTarget(); // silent
+
+  // Evaluate Shell.question using _win's eval (this is why eval isn't in the |with|, IIRC).
+  _win.location.href = "javascript:try{ Shell.printAnswer(eval('with(Shell._scope) with(Shell.shellCommands) {' + Shell.question + String.fromCharCode(10) + '}')); } catch(er) { Shell.printError(er); }; setTimeout(Shell.refocus, 0); void 0";
+}
+
+</script>
+
+<!-- for http://ted.mielczarek.org/code/mozilla/extensiondev/ -->
+<script type="text/javascript" src="chrome://extensiondev/content/rdfhistory.js"></script>
+<script type="text/javascript" src="chrome://extensiondev/content/chromeShellExtras.js"></script>
+
+<style type="text/css">
+body { background: white; color: black; }
+
+#output { white-space: pre; white-space: -moz-pre-wrap; } /* Preserve line breaks, but wrap too if browser supports it */
+h3 { margin-top: 0; margin-bottom: 0em; }
+h3 + div { margin: 0; }
+
+form { margin: 0; padding: 0; }
+#input { width: 100%; border: none; padding: 0; }
+
+.input { color: blue; background: white; font: inherit; font-weight: bold; margin-top: .5em; /* background: #E6E6FF; */ }
+.normalOutput { color: black; background: white; }
+.print { color: brown; background: white; }
+.error { color: red; background: white; }
+.propList { color: green; background: white; }
+.message { color: green; background: white; }
+.tabcomplete { color: purple; background: white; }
+</style>
+</head>
+
+<body onload="params.w = window; params.app = 'Shell'; mw.OpenILS_init(params); init();" onunload="mw.OpenILS_exit(params);">
+
+ <div id="output"><h3>JavaScript Shell 1.3.1</h3><div>Features: autocompletion of property names with Tab, multiline input with Shift+Enter, input history with (Ctrl+) Up/Down, <a accesskey=M href="javascript:go('scope(Math); mathHelp();');">Math</a>, <a accesskey=H href="http://www.squarefree.com/shell/?ignoreReferrerFrom=shell1.3.1">help</a></div><div>Values and functions: ans, print(string), <a accesskey=P href="javascript:go('props(ans)')">props(object)</a>, <a accesskey=B href="javascript:go('blink(ans)')">blink(node)</a>, load(scriptURL), scope(object), cls()</div></div>
+
+<div><textarea id="input" class="input" wrap="off" onkeydown="inputKeydown(event)" rows="1"></textarea></div>
+
+</body>
+
+</html>
diff --git a/Open-ILS/xul/staff_client/chrome/content/evergreen/util/xuledit.js b/Open-ILS/xul/staff_client/chrome/content/evergreen/util/xuledit.js
new file mode 100644 (file)
index 0000000..ca0df4e
--- /dev/null
@@ -0,0 +1,65 @@
+// From Ted's Mozilla page: http://ted.mielczarek.org/code/mozilla/index.html 
+// Modified by Jason for Evergreen to push in the main (auth) window reference
+var old = '';
+var timeout = -1;
+var xwin = null;
+var newwin = false;
+
+function init()
+{
+  if(xwin)  // for some reason onload gets called when the browser refreshes???
+    return;
+
+  update();
+  document.getElementById('ta').select();
+}
+
+function openwin()
+{
+  toggleBrowser(false);
+  xwin = window.open('about:blank', 'xulwin', 'chrome,all,resizable=yes,width=400,height=400');
+  newwin = true;
+  update();
+}
+
+function toggleBrowser(show)
+{
+  document.getElementById("split").collapsed = !show;
+  document.getElementById("content").collapsed = !show;
+  document.getElementById("open").collapsed = !show;
+}
+
+function update()
+{
+  var textarea = document.getElementById("ta");
+
+  // either this is the first time, or
+  // they closed the window
+  if(xwin == null || (xwin instanceof Window && xwin.document == null)) {
+    toggleBrowser(true);
+    xwin = document.getElementById("content");
+    newwin = true;
+  }
+
+  if (old != textarea.value || newwin) {
+    old = textarea.value;
+    newwin = false;
+    var dataURI = "data:application/vnd.mozilla.xul+xml," + encodeURIComponent(old);
+    if(xwin instanceof Window)
+      xwin.document.location = dataURI;
+    else
+      xwin.setAttribute("src",dataURI);
+  }
+  try { xwin.contentWindow.mw = mw; } catch(E) {}
+  try { xwin.mw = mw; } catch(E) {}
+
+  timeout = window.setTimeout(update, 500);
+}
+
+function resetTimeout()
+{
+  if(timeout != -1)
+    window.clearTimeout(timeout);
+
+  timeout = window.setTimeout(update, 500);
+}
diff --git a/Open-ILS/xul/staff_client/chrome/content/evergreen/util/xuledit.xul b/Open-ILS/xul/staff_client/chrome/content/evergreen/util/xuledit.xul
new file mode 100644 (file)
index 0000000..8057b3f
--- /dev/null
@@ -0,0 +1,15 @@
+<?xml version="1.0"?>
+<!-- From Ted's Mozilla page: http://ted.mielczarek.org/code/mozilla/index.html -->
+<!-- Edited by Jason for Evergreen -->
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<window id="xuledit" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" title="Live XUL Editor"
+onload="try { init(); } catch(E) { dump(E+'\n'); alert(E); }">
+<script type="application/x-javascript" src="xuledit.js"/>
+<vbox flex="1">
+<textbox id="ta" multiline="true" wrap="true" flex="1" onkeydown="resetTimeout()"
+value='&lt;?xml version="1.0"?&gt;&#x0A;&lt;?xml-stylesheet href="chrome://global/skin/" type="text/css"?&gt;&#x0A;&lt;window id="yourwindow" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"&gt;&#x0A;&lt;label value="Put your XUL here!"/&gt;&#x0A;&lt;/window&gt;'/>
+<splitter id="split"/>
+<iframe id="content" src="about:blank" flex="1"/>
+<hbox><button id="open" label="Open preview in new window" onclick="openwin()"/><spacer flex="1"/></hbox>
+</vbox>
+</window>