Remoto - VFS: formListEditor.js Source File
Remoto - VFS
formListEditor.js
Go to the documentation of this file.
1 
2 define( [
3  'require',
4  'remoto!stdlib:js/panes/pane.js',
5  'remoto!stdlib:js/panes/panes/form.js',
6  'remoto!stdlib:js/paneManager/paneManager.js',
7  "remoto!stdlib:js/paneManager/paneMenu.js",
8  'remoto!stdlib:js/include/objectRegistry.js',
9  'include/modal/modal',
10  'remoto!stdlib:js/include/utils.js',
11  'remoto!stdlib:js/panes/panes/formListEditor.css',
12  'jquery/ui/jquery.ui.sortable',
13  ],
14  function(require,pane,form,paneManager,menuManager,objectRegistry,modal,utils)
15  {
16  'use strict';
17 
37  formListEditor.prototype = new pane;
38  function formListEditor(layout)
39  {
40  //console.log("NEW formlistEditor");
41  //console.log(layout);
42 
43  pane.call(this, layout);
44 
45  if (!layout) return;
46 
47  this._type = "formListEditor";
48 
49  this._saveFields = { showItemList:"_showItemList", showHeaderWidgets:"_showHeaderWidgets" };
50  this._showItemList = layout.showItemList===false ? false : true;
51  this._showHeaderWidgets = layout.showHeaderWidgets===true ? true : false;
52  this._showAddRemoveButtons = layout.showAddRemoveButtons===false ? false : true;
53 
54  this._widgets = {}; //for the header
55  this._forms = {}; //the forms/nodes we've subscribed to
56  this._context = layout.metadata ? (layout.metadata.context || {}) : {};
57  this._selection = {}; //to know what is selected
58  this._lastSelected = null; //for shift-select ranges
59 
60  this._formListJq = null;
61  this._itemListJq = null;
62 
63  this._objectLoader = null;
64 
65  this.createHTML();
66  }
67 
77  formListEditor.prototype.createHTML = function()
78  {
79  if (this._html) return this._html;
80 
81  pane.prototype.createHTML.call(this,this._showHeaderWidgets);
82 
83  //this._content.append("form list!");
84 
85  if (this._showItemList)
86  { this._formListJq = $("<div class='formListForms'>").appendTo(this._content);
87 
88  this._itemListJq = $("<div class='formListItemList'>").appendTo(this._content);
89  //this._itemListJq.on("touchstart mousedown", ".formListItemListItem", this.selectItem.bind(this) );
90  this._itemListJq.on("pointerdown", ".formListItemListItem", this.selectItem.bind(this) );
91  //this._itemListJq.bind("touchstart mousedown", this.selectItem.bind(this,"deselectAll") );
92  this._itemListJq.bind("pointerdown", this.selectItem.bind(this,"deselectAll") );
93 
94  var w = this._itemListWidgetJq = $("<div class='formListItemListWidget'>").appendTo(this._content);
95  var add = $("<button>").html("+").appendTo(w).bind("click", this.newFormItemClick.bind(this)).attr("disabled","disabled");
96  var del = $("<button>").html("−").appendTo(w).bind("click", this.deleteFormItemsClick.bind(this)).attr("disabled","disabled");
97  var num = $("<span class='formListCount'>").html("0 items").appendTo(w);
98 
99  this._itemListWidgetAddJq = add;
100  this._itemListWidgetDelJq = del;
101  this._itemListWidgetNumJq = num;
102  }
103  else
104  this._formListJq = this._content;
105 
106  return this._html;
107  }
108 
118  formListEditor.prototype.createHeader = function()
119  {
120  if (this._header) return this._header;
121 
122  pane.prototype.createHeader.call(this);
123 
124  var b;
125  var THIS = this;
126  var h = this._header;
127 
128  //h.append("header!");
129 
130  /*
131  h.css( { left:"5px", top: "3px" } );
132 
133  b = $("<button style='margin-right:3px;'>").text("Clear").appendTo(h);
134 
135  b = this._widgets["mi"] = $("<input title='Max Items' type='number' name='mi' value='10' step='1' min='1' max='10'/>").appendTo(h);
136  b.bind("change", function(e) {
137  var v = $(this).val();
138  THIS._maxItems = v;
139  paneManager.saveLayout();
140  } );
141  b.val( this._maxItems );
142  */
143 
144  return this._header;
145  }
146 
157  formListEditor.prototype.applySubscription = function(data,metadata)
158  {
159  //console.log("formlistEditor subscription",arguments);
160  //console.log(this);
161  //console.log( this._forms );
162 
163  //var base = this._path;
164 
165  // if ("context" in metadata)
166  // this._context = metadata.context;
167 
168  if (!this._objectLoader)
169  this._objectLoader = new objectRegistry.objectLoader(metadata.nodeMenu || "");
170 
171  var FF = Object.keys(this._forms);
172  var __p;
173  for (var p in data)
174  {
175  //console.log(p);
176  __p = this._path+"/"+p;
177  //console.warn("SUB: "+__p);
178 
179  if (!(__p in this._forms))
180  {
181  this._forms[__p] = new formLoader( __p, this );
182 
183  //FIXME: do we need to add a timer here in case of disconnect?
184  }
185  else
186  { //console.error("path "+__p+" already exists.");
187  FF = FF.filter(function(e) { return e !== __p });
188  }
189  }
190 
191  if (FF.length)
192  {
193  console.warn("Remove items during subscribe",FF);
194  var DD = {};
195  FF.map( function(key) { DD[key] = null; } );
196  this.applyDiff(DD);
197  }
198 
199  if (metadata.creators)
200  {
201  var c = metadata.creators;
202 
203  var menu = menuManager.getMenu("__formListEditor_creators_"+this._id) ||
204  menuManager.createMenu("__formListEditor_creators_"+this._id);
205 
206  for (var n in c)
207  {
208  if (menu && !menu.hasItemWithLabel(n))
209  menu.addItem( { //path
210  label: n,
211  callback: this.newFormItem.bind(this,c[n].action),
212  //data
213  test: true,
214  icon: "<img height=16 width=16 src='"+c[n].icon+"' style='position:relative; top:2px; left:-1px'/>",
215  //icon: "<span class='ui-icon ui-icon-circle-plus' style='display:inline-block; position:relative; top:2px; left:-1px' />",
216  } );
217  }
218 
219  if (utils.keyCount(c))
220  this._itemListWidgetAddJq.show().removeAttr("disabled");
221  else
222  this._itemListWidgetAddJq.hide();
223  }
224  else
225  this._itemListWidgetAddJq.hide();
226 
227  if (metadata.deletors)
228  {
229  var d = metadata.deletors;
230 
231  var menu = menuManager.getMenu("__formListEditor_deletors_"+this._id) ||
232  menuManager.createMenu("__formListEditor_deletors_"+this._id);
233 
234  for (var n in d)
235  {
236  if (menu && !menu.hasItemWithLabel(n))
237  menu.addItem( { //path
238  label: n,
239  callback: this.deleteFormItems.bind(this,d[n].action),
240  //data
241  test: true,
242  icon: "<img height=16 width=16 src='"+d[n].icon+"' style='position:relative; top:2px; left:-1px'/>",
243  //icon: "<span class='ui-icon ui-icon-circle-plus' style='display:inline-block; position:relative; top:2px; left:-1px' />",
244  } );
245  }
246 
247  if (utils.keyCount(d))
248  this._itemListWidgetDelJq.show().removeAttr("disabled");
249  else
250  this._itemListWidgetDelJq.hide();
251  }
252  else
253  this._itemListWidgetDelJq.hide();
254 
255  this._subscribed = true;
256 
257  this.syncItemList();
258  }
259 
269  formListEditor.prototype.applyDiff = function(diff,user)
270  {
271  //console.log("formList apply diff!",arguments);
272  //console.log(diff);
273 
274  //hide all the showing forms
275  //this._formListJq.children(".formListForm").hide();
276 
277  if (diff === null)
278  return;
279 
280  var d,__p,f;
281  for (var p in diff)
282  {
283  d = diff[p];
284  //console.log( d );
285 
286  __p = p.substr(0,this._path.length) === this._path ? p : this._path+"/"+p;
287  if (d!==null && !(__p in this._forms)) //does it need to be created?
288  {
289  //console.error("Creating: "+__p);
290  //console.error("For: "+p);
291  //console.error("Path: "+this._path);
292 
293  //create or delete forms here...
294  this._forms[__p] = new formLoader( __p, this, d.diff, user);
295  }
296  else if (d === null)
297  {
298  //console.log("delete form: "+p+" / "+__p);
299  //console.log(this._forms);
300 
301  f = this._forms[__p];
302  if (f)
303  {
304  if (f._wrapper)
305  f._wrapper.wrapper.remove();
306  objectRegistry.unregisterObject( f._path, f );
307  f.destroy();
308  delete this._forms[__p];
309  }
310  }
311 
312  /*
313  else if ("_nodeClass" in d) //we assume it's a fully formed object, not a diff indicating a node to create or destroy
314  {
315  console.log("show: "+p);
316 
317  //show only the selected forms
318  if ("_wrapper" in this._forms[p])
319  this._forms[p]._wrapper.wrapper.show();
320  }
321  */
322  }
323 
324  this.syncItemList();
325  }
326 
335  formListEditor.prototype.applySettings = function(settings)
336  {
337  /*
338  if (!("maxItems" in settings))
339  settings.maxItems = 0
340 
341  if (settings.maxItems && this._widgets["mi"])
342  { this._widgets["mi"].val(settings.maxItems);
343  this._maxItems = settings.maxItems;
344  }
345  */
346  //else
347  //{ console.error("No maxItems in settings, or widgets['mi'] hasn't been created!");
348  // console.log(settings);
349  // console.log(this._widgets);
350  // console.log(this._header);
351  //}
352  }
353 
354 
362  formListEditor.prototype.destroy = function()
363  {
364  pane.prototype.destroy.call(this);
365 
366  this._forms = null;
367  this._selection = null;
368  this._widgets = null;
369 
370  this._objectLoader = null;
371  }
372 
384  formListEditor.prototype.addForm = function(path,form,icon)
385  {
386  var THIS = this;
387 
388  this._forms[path] = form;
389 
390  icon = icon || require.toUrl('include/loader/loader-contrast.gif');
391 
392  var html = form.createHTML();
393 
394  var f = $( "<div class='formListForm'>" ).appendTo( this._formListJq ).attr("path",path);
395  var h = $( "<div class='formListFormHeader'>").appendTo(f);
396  var c = $( "<div class='formListFormContent'>").appendTo(f);
397 
398  //by default forms are hidden until selected in the editor list.
399  f.hide();
400 
401  //var hi = $("<img class='formListFormHeaderIcon' src='"+require.toUrl('./nodeCanvas/nodePropertiesIcons/node.png')+"'/>").appendTo(h);
402  var hi = $("<img class='formListFormHeaderIcon' width='16' src='"+icon+"'/>").appendTo(h);
403 
404  var ht = $("<div class='formListFormHeaderTitle'>").appendTo(h);
405  ht.text("Loading '"+form._path+"'");
406 
407  var b = $( "<div class='formListFormHeaderButtons'>").appendTo(h);
408  var bh = $("<div class='formListFormHeaderButton' title='Help Text'>?</div>").appendTo(b);
409  var bm = $("<div class='formListFormHeaderButton' title='Collapse / Expand'>&boxH;</div>").appendTo(b);
410  var bc = $("<div class='formListFormHeaderButton' title='Close'>&#x2715;</div>").appendTo(b);
411 
412  form._formJq.appendTo(c);
413 
414  bh.bind("click", function()
415  {
416  modal.alert( form._help, null, "Help" );
417  } );
418 
419  bh.hover( function() //put in hover because the help won't be known until the form is fully loaded
420  {
421  //bh.attr("title", form._help);
422  bh.attr("title", form._help.replace(/<br>/i,"\n") );
423  } );
424  //bh.attr("title", form._help.replace(/<br>/i,"\n") );
425 
426  function toggler()
427  {
428  c.toggle();
429  if ( c.is(":visible") ) bm.html("&boxH;");
430  else bm.html("&plus;");
431  }
432 
433  h.bind("dblclick", toggler );
434  bm.bind("click", toggler );
435 
436  bc.bind("click", function()
437  {
438  //f.toggle();
439  THIS._selection[ f.attr("path") ] = false;
440  THIS.syncSelection();
441  } );
442 
443  form._wrapper = {
444  wrapper: f,
445  header: h,
446  content: c,
447  icon: hi,
448  title: ht,
449  buttons: b,
450  help: bh,
451  minimize: bm,
452  close: bc,
453  selector: null,
454  selectorName: null,
455  }
456 
457  //console.log(html);
458 
459  this.makeSortable();
460  this.syncItemList();
461  }
462 
471  formListEditor.prototype.makeSortable = function()
472  {
473  this._formListJq.sortable( {
474  handle: '.formListFormHeader',
475  axis: 'y',
476  containment: 'parent',
477  cursor: 'move',
478  items: '.formListForm',
479  opacity: 0.7,
480  } );
481  }
482 
491  formListEditor.prototype.syncItemList = function()
492  {
493  if (!this._itemListJq) return;
494 
495  var depth = 0;
496  var list = this._itemListJq;
497  var chop = this._path.length+1; //chop this path off the child item paths
498 
499  //FIXME: add hierarchy support for this!
500 
501  //console.log(this._path);
502  list.empty();
503  var keys = Object.keys(this._forms).sort();
504  for (var j=0;j<keys.length;j++)
505  {
506  var p = keys[j];
507 
508  //console.log(p);
509  var i = $("<div class='formListItemListItem' path='"+p+"'>").appendTo(list);
510 
511  var n;
512  var f = this._forms[p];
513  if (f._attributes && f._attributes.name)
514  n = f._attributes.name.value;
515  else
516  n = p.substr(chop);
517  //n = "...";
518  //var ns = n;
519  n = $("<span>").text(n);
520 
521  i.append("&nbsp;");
522  i.append(n);
523 
524  if (f._wrapper)
525  { //i.prepend(f._wrapper.icon.clone());
526  f._wrapper.selector = i;
527  f._wrapper.selectorName = n;
528 
529  var _icon = $("<span class='formListItemListItemIcon'>");
530  _icon.css( "-webkit-mask-box-image", "url(\""+f._wrapper.icon.attr("src").replace(/[\"']/g,"\\\"")+"\")" );
531  i.prepend( _icon );
532  }
533  else
534  { //i.prepend("<img class='formListFormHeaderIcon' src='"+f._icon+"'/>");
535  var _icon = $("<span class='formListItemListItemIcon'>");
536  _icon.css( "-webkit-mask-box-image", "url(\""+f._icon.replace(/[\"']/g,"\\\"")+"\")" );
537  i.prepend( _icon );
538  }
539 
540  //FIXME: this is too specific to the provisioner, but I don't have a good place to put it right now.
541  if (f._attributes)
542  {
543  if (f._attributes.active)
544  if (!f._attributes.active.value)
545  i.addClass( "formListItemListItemInactive" );
546 
547  if (f._attributes.status)
548  i.addClass("formListItemListItemStatus_"+f._attributes.status.value);
549  }
550  }
551 
552  var alphabetical = list.find(".formListItemListItem").sort( function (a, b) {
553  if ( $(a).text() < $(b).text() ) return -1;
554  if ( $(a).text() > $(b).text() ) return 1;
555  return 0;
556  });
557  //for (var ii=0;ii<alphabetical.length;ii++)
558  // list.append(alphabetical[ii]);
559  //console.log(alphabetical);
560  list.html(alphabetical);
561 
562  // console.trace("SYNCED LIST!");
563 
564  this._itemListWidgetNumJq.html( keys.length+" item"+(keys.length!==1?"s":"") ); //for some reason, zero items is plural in english.
565  }
566 
575  formListEditor.prototype.syncSelection = function()
576  {
577  for (var p in this._forms)
578  {
579  if (this._selection[p])
580  { this._forms[p]._wrapper.wrapper.show();
581  this._itemListJq.children(".formListItemListItem[path='"+p+"']").addClass("formListItemListItemSelected");
582  }
583  else
584  { this._forms[p]._wrapper.wrapper.hide();
585  this._itemListJq.children(".formListItemListItem[path='"+p+"']").removeClass("formListItemListItemSelected");
586  }
587  }
588  }
589 
600  formListEditor.prototype.selectItem = function(e)
601  {
602  //console.log(arguments);
603 
604  //shift = create span of selection
605  //alt = toggle selection item
606  //meta = add selection item
607 
608  if (e==="deselectAll")
609  {
610  this._selection = {};
611  this._lastSelected = null;
612  this.syncSelection();
613  return false;
614  }
615 
616  var p = $(e.currentTarget);
617  var shift = e.shiftKey;
618  var alt = e.altKey;
619  var meta = e.metaKey;
620  var path = p.attr("path");
621 
622  //alt = false;
623  meta = alt || meta;
624 
625  //console.log(path);
626  //var keys = Object.keys( this._forms ).sort();
627  //var index = keys.indexOf(path);
628 
629  var list = this._itemListJq;
630  var items = list.find(".formListItemListItem");
631  var index = p.index();
632  var keys = jQuery.map( items, function( n, i ) { return $(n).attr("path"); } );
633 
634  if (index>-1)
635  {
636  if (!shift || this._lastSelected === null)
637  this._lastSelected = index;
638  }
639  else
640  { this._lastSelected = null;
641  return;
642  }
643  //console.log("LAST: "+this._lastSelected);
644 
645  if (!alt && !meta)
646  this._selection = {};
647 
648  var s = shift ? this._lastSelected : index;
649  var ee = index;
650  var start = Math.min(s,ee);
651  var end = Math.max(s,ee);
652 
653  //console.log(index+" s:"+s+" e:"+e+" shift:"+shift+" alt:"+alt+" meta:"+meta);
654 
655  for (var i = start; i<=end; i++)
656  {
657  //console.log( i+": "+keys[i] );
658  //if (alt) this._selection[ keys[i] ] = true;
659  //else if (meta) this._selection[ keys[i] ] = this._selection[ keys[i] ] ? false : true;
660  if (meta) this._selection[ keys[i] ] = this._selection[ keys[i] ] ? false : true;
661  else this._selection[ keys[i] ] = true;
662  }
663 
664  //console.log(this._selection);
665 
666  this.syncSelection();
667 
668  return false;
669  }
670 
681  formListEditor.prototype.newFormItemClick = function(e)
682  {
683  //console.log("new item!");
684  //console.log(this._id);
685 
686  var menu = menuManager.getMenu("__formListEditor_creators_"+this._id);
687 
688  if (menu)
689  {
690  if (menu._items.length == 1)
691  menu._items[0]._callback.call();
692  else
693  menuManager.openMenu( "__formListEditor_creators_"+this._id, this._itemListWidgetAddJq, "T" );
694  }
695  else
696  console.warn("formListEditor: no creator menu!");
697 
698  return false;
699  }
700 
710  formListEditor.prototype.newFormItem = function(action)
711  {
712  //console.log(action);
713 
714  var metadata = { where:"modalForm" };
715  var context = {};
716  context.sourcefile = utils.fileNameFromPath( this._path, true );
717  context.sourcepath = this._path;
718  context.sourcedir = utils.dirNameFromPath( this._path );
719 
720  this._content.trigger( "openApplicationLayout", [ context, action, metadata ] );
721  }
722 
733  formListEditor.prototype.deleteFormItemsClick = function(e)
734  {
735  var menu = menuManager.getMenu("__formListEditor_deletors_"+this._id);
736 
737  if (menu)
738  {
739  if (menu._items.length == 1)
740  menu._items[0]._callback.call();
741  else
742  menuManager.openMenu( "__formListEditor_deletors_"+this._id, this._itemListWidgetDelJq, "T" );
743  }
744  else
745  console.warn("formListEditor: no deletors menu!");
746 
747  return false;
748  }
749 
759  formListEditor.prototype.deleteFormItems = function(action)
760  {
761  //console.log(action);
762 
763  if ( !Object.keys( this._selection ).length )
764  return;
765 
766  if (action.confirm)
767  {
768  var m = action.confirmMessage || "You are about to delete the selected items.<br><br>Are you sure?";
769 
770  modal.confirm( m, this.deleteFormItemsConfirmed.bind(this,action), false, "Delete" );
771  }
772  else
773  this.deleteFormItemsConfirmed(action);
774 
775  }
776 
786  formListEditor.prototype.deleteFormItemsConfirmed = function(action)
787  {
788  //console.log("WOULD DO DELETE:");
789  //console.log(action);
790 
791  var rm = {};
792 
793  for (var s in this._selection)
794  rm[s] = true;
795 
796  //console.log(rm);
797 
798  this.postDeleteCallback( rm );
799 
800  this._selection = {};
801  }
802 
803  formListEditor.prototype.applyRequestSuccess = function(command,id,data,metadata)
804  {
805  console.log("formListEditor applyRequestSuccess!");
806  }
807 
808  formListEditor.prototype.applyRequestError = function(command,id,reason)
809  {
810  console.log("formListEditor applyRequestError");
811  }
812 
813 
815  // FormLoader
817 
841  function formLoader(path,_formList,diff,user)
842  {
844 
845  //console.log("New formloader: "+path);
846  //console.log(diff);
847 
848  this._path = path;
849  this._icon = require.toUrl('include/loader/loader-contrast.gif');
850  this._formList = _formList;
851  this._context = {};
852 
854 
855  this._timeout = setTimeout( this.timeout.bind(this), 5000 );
856 
857  if (diff)
858  { console.log("DIFF IN CTOR!");
859  return this.applyDiff(diff); //returning different object than the 'new' call would indicate!!!
860  //this.applyDiff(diff,user);
861  }
862  }
863 
864  formLoader.prototype = {
865 
874  timeout: function()
875  {
876  console.warn( "Timeout on "+this._path );
877  console.log(this);
878  this._timeout = null;
879  },
880 
892  applySubscription: function(data,metadata)
893  {
894  //console.log("formLoader applySubscription: "+this._path,arguments);
895 
896  if (this._subscribed)
897  return;
898 
899  this._subscribed = true;
900 
901  if (metadata.context)
902  { this._context = metadata.context;
903  //console.log(this._context);
904  data = utils.resolveContextValues(data,metadata.context);
905  }
906 
907  if (metadata.icon)
908  this._icon = metadata.icon;
909 
910  return this._formList._objectLoader.fetchDefinition( data.base, data, this.applyDiff.bind(this) );
911  },
912 
924  applyDiff: function(diff,user)
925  {
926  //console.log("form loader apply diff",arguments);
927 
928  //FIXME: add loader spinner
929  //...
930 
931  //diff = utils.resolveContextValues(diff,this._context);
932 
933  //load definition data...
934  return this._formList._objectLoader.fetchDefinition( diff.base, {}, this.createForm.bind(this,diff) );
935 
936  //objectRegistry.unregisterObject( this._path, this );
937  },
938 
950  createForm: function( diff, definition )
951  {
952  //console.log("CREATE NODE FORM!",arguments);
953  //console.log(diff);
954  //console.log(definition);
955  //console.log(arguments);
956 
957  var spec = this._formList._objectLoader.applyValues( diff, definition );
958  //console.log(spec);
959 
960  spec = utils.resolveContextValues(spec,this._formList._context);
961 
962  //console.log("new form: "+this._path);
963  var f = new form( { path:this._path, parent:this._formList } );
964  this._formList.addForm( this._path, f, this._icon );
965  //objectRegistry._noresubscribe[this._path] = true;
966 
967  var THIS = this;
968 
969  //monkey patch for now... just to get it working.
970  var addedChanges = {};
971  var oAD = f.applyDiff;
972  f.applyDiff = function(diff,user)
973  {
974  if ("help" in diff)
975  { f._help = diff.help;
976  f._wrapper.help.show();
977  }
978  //else
979  // f._wrapper.help.hide();
980 
981  if ("attributes" in diff)
982  {
983  oAD.call(this,diff.attributes,user);
984 
985  if ("name" in diff.attributes)
986  {
987  f._wrapper.title.text( diff.attributes.name.value );
988  f._wrapper.selectorName.text( diff.attributes.name.value )
989 
990  if (!addedChanges.name)
991  {
992  var ocn = f._attributes.name._change;
993  f._attributes.name._change = function(variable,value,widget)
994  {
995  f._wrapper.title.text( value );
996  f._wrapper.selectorName.text( value );
997  ocn.call(f,variable,value,widget);
998  }
999 
1000  addedChanges.name = true;
1001  THIS._formList.syncItemList();
1002  }
1003  }
1004 
1005  if ("active" in diff.attributes)
1006  {
1007  //console.log("changed active!");
1008 
1009  if (diff.attributes.active.value)
1010  f._wrapper.selector.removeClass( "formListItemListItemInactive" );
1011  else f._wrapper.selector.addClass( "formListItemListItemInactive" );
1012 
1013  if (!addedChanges.active)
1014  {
1015  var oca = f._attributes.active._change;
1016  f._attributes.active._change = function(variable,value,widget)
1017  {
1018  if (value) f._wrapper.selector.removeClass( "formListItemListItemInactive" );
1019  else f._wrapper.selector.addClass( "formListItemListItemInactive" );
1020 
1021  oca.call(f,variable,value,widget);
1022  }
1023 
1024  addedChanges.active = true;
1025  }
1026  }
1027 
1028  if ("status" in diff.attributes)
1029  {
1030  f._wrapper.selector.removeClass( function(index, css) {
1031  return (css.match( /(^|\s)formListItemListItemStatus_[^\s]+/g) || []).join(' ');
1032  } );
1033 
1034  f._wrapper.selector.addClass( "formListItemListItemStatus_"+diff.attributes.status.value );
1035 
1036  if (!addedChanges.status)
1037  {
1038  if (false)
1039  //if ("active" in f._attributes)
1040  {
1041  var ocs = f._attributes.active._change;
1042  f._attributes.active._change = function(variable,value,widget)
1043  {
1044  f._wrapper.selector.removeClass( function(index, css) {
1045  return (css.match( /(^|\s)formListItemListStatus_.*/g) || []).join(' ');
1046  } );
1047 
1048  f._wrapper.selector.addClass( "formListItemListStatus_"+value );
1049 
1050  ocs.call(f,variable,value,widget);
1051  }
1052  }
1053 
1054  addedChanges.status = true;
1055  }
1056  }
1057  }
1058 
1059  }
1060 
1061  /*
1062  var oCF = f.changeField;
1063  f.changeField = function(variable, value, field)
1064  {
1065  var v = {};
1066  v[variable] = value;
1067 
1068  //return oCF.call(this, "attributes", v, field);
1069  return oCF.call(this, "attributes."+variable, value, field);
1070  };
1071  */
1072 
1073  var oPU = f.postUpdate;
1074  f.postUpdate = function(u)
1075  {
1076  u = { attributes: u };
1077 
1078  //console.log(u);
1079 
1080  //this should already be in the form postUpdate code!
1081  objectRegistry.applyDiff( this._path, u, null, f ); //propagate to any other instance of this form or node
1082 
1083  return oPU.call(this, u);
1084  };
1085 
1086  //must be after monkey patch
1087  f.applyDiff(spec);
1088 
1089  //objectRegistry.registerObject( this._path, f, true );
1090  objectRegistry.registerObject( this._path, f );
1091  f._subscribed = true;
1092 
1093  this.destroy();
1094 
1095  return f;
1096  },
1097 
1106  destroy: function()
1107  {
1108  objectRegistry.unregisterObject( this._path, this );
1109 
1110  //console.log(objectRegistry);
1111 
1112  if (this._timeout)
1113  { clearTimeout( this._timeout );
1114  this._timeout = null;
1115  }
1116  },
1117  };
1118 
1119  return formListEditor;
1120  }
1121 );
applySubscription(data, metadata)
getter html
Get the html color representation of this object.
setter value
a setter DOCME
getter id
returns the number of milliseconds since midnight January 1, 1970 UTC
setter user
a setter DOCME
Form renderer.
form(layout)
createHTML()
Create the jquery content object, or return it if it exists.
applySettings(settings)
deleteFormItems(action)
deleteFormItemsConfirmed(action)
newFormItem(action)
formListEditor(layout)
applyDiff(diff, user)
applySubscription(data, metadata)
addForm(path, form, icon)
formLoader(path, _formList, diff, user)
createForm(diff, definition)
setter widget
a setter DOCME
Manages context menus or any other menu.
createMenu(m, p, subscribe)
Create a paneMenu(). You will want to use paneMenu.addItem() on the resulting object.
openMenu(m, b, p, d, c)
Open a menu.
applyDiff(id, diff, user, except)
registerObject(id, o, nosubscribe)
Register an object in the registry, and call the pathAddedCallback.
unregisterObject(id, o, silent, nounsubscribe, now)
Unregister an object from the registry.
postDeleteCallback()
Create a pane which will be mounted into a paneManager layout.
applyRequestSuccess(command, id, data, metadata)
applyRequestError(command, id, reason)
getter help
A getter that will return a pane object's help message, or a default message indicating that no help ...
destroy()
DOCME.
createHTML()
pane(layout, object)
The paneManager manages panes in a user layout.
getter path
a getter DOCME
applyDiff(diff, user)
createHTML()
Create the HTML contents of the pane.
Utility functions for javascript clients.
cleanPath(path)
Clean and normalize a resource path.
fileNameFromPath(p, orDirIfNeeded)
Retrieve the last part of a file path.
keyCount(o)
Return the number of keys in an object.
dirNameFromPath(p)
Retrieve the directory portion of a path.
resolveContextValues(o, ctx)
Recursively resolve any context values in an object.
text(value, options)
metadata(paths)
Base class for GUI form widgets.