adding prefs controller
M classes/controller.pike +2 -0
@@ 14,6 14,7 @@ Fins.FinsController archive;
 Fins.FinsController about;
 Fins.FinsController rpc;
 Fins.FinsController plugin;
+Fins.FinsController prefs;
 
 // used only for installing
 Fins.FinsController install;

          
@@ 49,6 50,7 @@ void start()
     archive = load_controller("archive_controller");
     about = load_controller("about_controller");
     plugin = load_controller("plugin_controller");
+    prefs = load_controller("preference_controller");
 
     around_filter(app->user_filter);
     _index = real_index;

          
M classes/plugin_controller.pike +6 -0
@@ 19,11 19,15 @@ static void start()
 
 public void index(Request id, Response response, mixed ... args)
 {
+CHECKADMIN()
+
   response->redirect("list");
 }
 
 public void list(Request id, Response response, mixed ... args)
 {
+    CHECKADMIN()
+
      object t = view->get_view("plugin/list");
 
      app->set_default_data(id, t);

          
@@ 43,6 47,8 @@ public void list(Request id, Response re
 
 public void toggle_enabled(Request id, Response response, mixed ... args)
 {
+CHECKADMIN()
+
   if(!id->variables->plugin)
   {
     response->flash("msg", LOCALE(299,"No plugin."));

          
A => classes/preference_controller.pike +180 -0
@@ 0,0 1,180 @@ 
+//<locale-token project="SpeedyDelivery">LOCALE</locale-token>
+
+#define LOCALE(X,Y) Locale.translate(app->config->app_name, id->get_lang(), X, Y)
+
+#define CHECKADMIN()  object user = id->misc->session_variables->user;  \
+if(!app->is_list_master(list, id->misc->session_variables->user)) \
+{response->set_data("You must be an admin user in order to access this function."); return;  }
+
+import Fins;
+import Tools.Logging;
+import Fins.Model;
+inherit Fins.FinsController;
+
+protected string vtype = "admin";
+
+int __quiet=1;
+
+static void start()
+{
+  around_filter(app->mandatory_user_filter);
+}
+
+
+protected string get_root(object id)
+{
+  return "";
+}
+
+public void index(Request id, Response response, mixed ... args)
+{
+CHECKADMIN()
+  response->redirect("list");
+}
+
+public void tree(Request id, Response response, mixed ... args)
+{
+CHECKADMIN()
+  string pr = get_root(id);
+  if(id->variables->action && id->variables->action == "getChildren")
+  {
+      array data = ({});
+    mapping d = Tools.JSON.deserialize(id->variables->data);
+    Log.debug("data: %O\n", d);
+    array prefixes = ({});
+    array nodes = ({});
+
+    if(d->node && d->node->widgetId && d->node->widgetId == "prefroot")
+    {
+
+      mapping prc = ([]);
+      if(pr && sizeof(pr)) prc->name = Fins.Model.LikeCriteria(pr + "%");
+      array x =  find.preferences(prc);
+      foreach(x;;object p)
+      {
+	array x = (p["name"][sizeof(pr)..]/".");
+        prefixes += ({x[0]});
+      }
+      prefixes = Array.uniq(prefixes);
+      prefixes -= ({"", 0});
+	foreach(prefixes;;string p)
+       data += ({ (["title":  p, "data": p, "widgetId": "tree_" + p, "isFolder": 1 ]) });
+
+    }
+    else if(d->node && d->node->widgetId)
+    {
+      array x;
+      if(!has_prefix(d->node->widgetId[5..], pr?(pr):"")) x = ({});
+      else x = find.preferences((["name": Fins.Model.LikeCriteria(d->node->widgetId[5..] + "%")]));
+      int q = sizeof(d->node->widgetId[5..] / ".");
+      multiset nodesadded = (<>);
+      foreach(x;;object p)
+      {
+        array x1 = p["name"]/".";
+        if(sizeof(x1)>(q))
+        {
+          if(nodesadded[x1[q]]) continue;
+          prefixes += ({ ({x1[q], (x1[..q] * ".")})});
+          nodesadded[x1[q]] = 1;
+        }
+        else
+          nodes += ({p});
+      }
+  
+//      prefixes = Array.uniq(prefixes);
+    
+
+      if(sizeof(prefixes))
+        foreach(prefixes;; array p)
+          data += ({ (["title":  p[0], "data": p[1], "widgetId": "tree_" + p[1], "isFolder": 1 ]) });
+      if(sizeof(nodes))foreach(nodes;; object pref)
+          data += ({ (["title":  pref["shortname"], "data": pref["name"], "widgetId": "treepref_" + pref["name"], "isFolder": 0 ]) });
+      
+}
+      response->set_data(Tools.JSON.serialize(data));
+      response->set_type("text/json");
+
+      werror("JSON: %O\n", Tools.JSON.serialize( data ));      
+  }
+}
+
+public void list(Request id, Response response, mixed ... args)
+{
+CHECKADMIN()
+    object t;
+  string pr = get_root(id);
+werror("list()\n");
+    if(id->variables->ajax)
+      t = view->get_view(vtype + "/prefs/_list");
+    else
+      t = view->get_view(vtype + "/prefs/list");
+werror("template: %O\n", t);
+    app->set_default_data(id, t);
+
+    mixed ul = ({});
+    mapping c = ([]);
+
+    array prefixes=({});
+
+    {
+      mapping prc = ([]);
+      if(pr && sizeof(pr)) prc->name = Fins.Model.LikeCriteria(pr + "%");
+      array x =  find.preferences(prc);
+      foreach(x;;object p)
+        prefixes += ({ (p["name"][sizeof(pr)..]/".")[0]});
+      prefixes -= ({"", 0});
+      prefixes = Array.uniq(prefixes);
+    }     
+
+    string startswith = id->variables->startswith;
+    if(startswith && !has_prefix(startswith, pr))
+    {
+      ul = ({});
+    }
+    else
+    {
+    if(startswith) c->name = Fins.Model.LikeCriteria(startswith + "%");
+    else if(pr) c->name = Fins.Model.LikeCriteria(pr + "%");
+    ul = find.preferences(c,  Fins.Model.Criteria("ORDER BY Name DESC"));
+    }
+werror("prefixes: %O\n", prefixes);
+werror("prefs:    %O\n", ul);
+
+    if(startswith)
+      t->add("startswith", (startswith||"")/".");
+    t->add("prefprefixes", prefixes);
+    t->add("preferences", ul);
+
+    response->set_view(t);
+}
+
+public void set(Request id, Response response, mixed ... args)
+{
+CHECKADMIN()
+  mixed e;
+  if (id->variables->key && id->variables->value && has_prefix(id->variables->key, (string)get_root(id))) {
+    object pref = app->get_sys_pref(id->variables->key);
+    if (pref) {
+      if(pref["type"] == SpeedyDelivery.BOOLEAN)
+      {
+        if(lower_case(id->variables->value) == "false" || id->variables->value == "0" || lower_case(id->variables->value) == "no")
+          pref["value"] = 0;
+        else
+        {
+          pref["value"] = 1;
+        }
+
+      }
+	  else
+      	pref["value"] = id->variables->value;
+      response->set_data(Tools.JSON.serialize(([ "set" : 1 ])));
+      response->set_type("text/javascript");
+    }
+  }
+  else {
+    response->set_data(Tools.JSON.serialize(([ "set" : 0 ])));
+    response->set_type("text/javascript");
+  }
+
+  if(e) Log.exception("an error occurred while setting a variable.", e);
+}

          
A => templates/prefs/_list.phtml +58 -0
@@ 0,0 1,58 @@ 
+Preferences:
+<b>
+<% implode var="$startswith" splice="</b> &gt; <b>" final="</b> &gt; <b>"%>
+</b>
+<script type="text/javascript">
+var editbox;
+</script>
+<p>
+<table>
+<% foreach var="$preferences" val="pref" %>
+<tr>
+<td>
+<%$pref.def.friendly_name %>: 
+</td>
+<td width="100">
+
+<% if data->pref["type"] == FinScribe.BOOLEAN %>
+  <span style="width:100px;" data-dojo-type="dijit.InlineEditBox" data-dojo-props="editor:'dijit.form.Select', autoSave:false, editorParams: 
+	{ options: [
+		{label: 'Yes', value: 'Yes' <%if (int)data->pref->value %>, selected: 1<%endif%>}, 
+		{label: 'No', value: 'No' <%if !(int)data->pref->value %>, selected: 1<%endif%>}
+		] 
+	}"
+      title="<%$pref.def.friendly_name%>" id="<%$pref.name%>" name="<%$pref.name%>"><script type="dojo/connect" event="onChange" args="value">
+	          console.log(this.id + " changed to value " + value);
+	 			saveValue(this.id, value);
+	     </script><%$pref.yesnovalue%></span>
+
+<%elseif data->pref["type"] == FinScribe.STRING && arrayp(data->pref["def"]["options"]) && sizeof(data->pref["def"]["options"]) %>
+  <span style="width:100px;" data-dojo-type="dijit.InlineEditBox" data-dojo-props="editor:'dijit.form.Select', autoSave:false, editorParams: 
+	{ options: [
+    <%foreach var="$pref.def.options" val="opt"%>
+		{label: '<%$opt.name%>', value: '<%$opt.value%>' <%if data->pref["value"] == data->opt["value"] %>, selected: 1<%endif%>}, 
+    <%end%>
+		] 
+	}"
+      title="<%$pref.def.friendly_name%>" id="<%$pref.name%>" name="<%$pref.name%>"><script type="dojo/connect" event="onChange" args="value">
+	          console.log(this.id + " changed to value " + value);
+	 			saveValue(this.id, value);
+	     </script><%val_from_options var="$pref.value" options="$pref.def.options"%></span>
+<% else %>
+  <span data-dojo-type="dijit.InlineEditBox" data-dojo-props="editor:'dijit.form.TextBox', autoSave:false"
+      title="quantity" width="70px" id="<%$pref.name%>" name="<%$pref.name%>"><script type="dojo/connect" event="onChange" args="value">
+	          console.log(this.id + " changed to value " + value);
+	 			saveValue(this.id, value);
+	     </script>
+	<%$pref.value%></span>
+
+<% endif %>
+</td>
+</tr>
+<tr>
+<td colspan="2"><i><%$pref.def.description%></i></td>
+</tr>
+<% end %>
+</table>
+<p><i>Click on a value to edit it.</i>
+</p>

          
A => templates/prefs/list.phtml +57 -0
@@ 0,0 1,57 @@ 
+     <script type="text/javascript">
+
+    function init()
+    {	
+    }
+	
+    function saveValue(pref, newVal) {
+      var bindArgs = {
+		url : '/admin/prefs/set',
+		mimetype : 'text/plain',
+		sync : false,
+		method : 'POST',
+		content : {
+		    key : pref,
+		    value : newVal
+		  	},
+		error : function(type, errObj) {
+			},
+		load : function(type, data, evt) {
+	       }
+      };
+      dojo.xhrGet(bindArgs);
+    }
+
+  </script>
+          <h3>Preferences</h3>
+
+<table cellpadding="10" valign="top">
+<tr>
+<td>
+<%if !data->startswith %>
+<% foreach var="$prefprefixes" val="prefix" %>
+<%action_link action="list" startswith="$prefix"%><%$prefix%></a>
+<% end%>
+<%else%>
+<%action_link action="list"%>&lt;&lt; root</a>
+<%endif%>
+</td>
+<td valign="top">
+<div id="prefpane" style="vertical-align : top;">
+  <%if data->startswith %>
+  <%@include file="prefs/_list.phtml"%>
+  <%endif %>
+</div>
+</td></tr>
+</table>
+
+<script type="text/javascript">
+    dojo.addOnLoad(init);
+</script>
+  <script type="text/javascript">
+    dojo.require("dijit.InlineEditBox");
+   dojo.require("dijit.Editor");
+	dojo.require("dijit.form.Textarea");
+	dojo.require("dijit.form.Select");
+  </script>
+