Remoto - VFS: widget.js Source File
Remoto - VFS
widget.js
Go to the documentation of this file.
1 
2 define( [
3  'remoto!stdlib:js/include/utils.js',
4  'remoto!stdlib:js/include/preferences.js',
5  'remoto!stdlib:js/paneManager/arrowMessage.js',
6  'remoto!stdlib:js/widgets/widget.css',
7  'jquery/jquery',
8  ],
10  {
11  'use strict';
12 
73  function widget( d )
74  {
75  //if (arguments.length == 0) return; //base prototype setup
76  if (!d) return; //base prototype setup
77 
78  this._label = d.label || null; //label we see
79  this._variable = null; //set from the factory
80  this._value = ("value" in d) ? d.value : d.default; //the widget's value, or the default value (or undefined if neither)
81  this._options = d.options || {};
82  this._change = d.change //onChange callback
83  this._default = d.default; //used to decide if something is non-default, or to fail to
84  this._tip = d.tip || "";
85  this._id = utils.uuid();
86  this._activeUser = null;
87  this._validator = d.validator || null;
88 
89  this._changeTimer = null; //the timer used to release change events... many widgets release events too quickly.
90  this._immediate = false;
91 
92  this._hidden = false;
93  this._enabled = ("enabled" in this._options) ? this._options.enabled : true;
94  this._error = null;
95  //this._active = false;
96 
97  this._html = null;
98  this._widgetJq = null;
99  this._labelJq = null;
100 
101  this._arrowAt = null;
102  this._arrowMessage = null;
103  }
104 
105  widget.prototype = {
106 
117  createHTML: function()
118  {
119  if (this._html) return this._html;
120 
121  var a,g;
122 
123  this._html = $("<div class='widgetRow'>");
124  a = this._html;
125 
126  if (this._options["class"])
127  this._html.addClass(this._options["class"]);
128 
129  a.attr("title",this._tip);
130 
131  var cl = this.createLabel();
132  if (cl)
133  a.append( cl );
134 
135  var cw = this.createWidget();
136  if (cw)
137  {
138  var w = $("<div class='widgetField'>");
139  w.append( cw );
140  a.append( w );
141  }
142 
143  if (this._options["hidden"]===true)
144  this.hidden = true;
145 
146  if (this._widgetJq)
147  this._widgetJq.bind("keydown", function(e)
148  {
149  if (e.keyCode === 83 && (e.metaKey || e.ctrlKey))
150  { //apple-s or ctrl-s was attempted... prevent it.
151  return false;
152  }
153 
154  if (e.keyCode === 27)
155  {
156  this.blur();
157  return false;
158  }
159  });
160 
161  return this._html;
162  },
163 
173  createWidget: function()
174  {
175  if (this._widgetJq) return this._widgetJq;
176 
177  //this._widgetJq = $("<input class='widgetInputField' id='"+this._id+"' type='text' value=\""+this._value+"\"/>");
178  this._widgetJq = $("<input class='widgetInputField' id='' type='text' value=''/>");
179  this._widgetJq.attr( {id:this._id} );
180  this._widgetJq.val(this._value);
181 
182  if (this._options["spellcheck"]===false)
183  this._widgetJq.attr("spellcheck","false");
184 
185  if (this._options["enabled"]!==true || !this._enabled)
186  this.enabled = false;
187 
188  if (this._options["placeholder"])
189  this._widgetJq.attr("placeholder",this._options["placeholder"]);
190 
191  if (this._options["autofocus"])
192  this._widgetJq.attr("autofocus","");
193 
194  if (this._options.class)
195  this._widgetJq.addClass(this._options.class);
196 
197  //console.log(this._options);
198 
199  //this._widgetJq.attr("autocomplete","off");
200 
201  this._widgetJq.bind("contextmenu", function(e) { e.stopPropagation(); } ) //allow default context, like copy, paste, spellcheck, etc.
202 
203  return this._widgetJq;
204  },
205 
215  createLabel: function()
216  {
217  if (this._labelJq) return this._labelJq;
218 
219  this._labelJq = $("<label class='widgetLabel' for='"+this._id+"'>");
220 
221  if (this._options.hideLabel)
222  { this._labelJq.css("visibility","hidden");
223  this._labelJq.css({
224  padding:0,
225  // width:0,
226  height:0,
227  margin:0
228  });
229  }
230  else
231  this._labelJq.text(this._label || this._variable);
232 
233  return this._labelJq;
234  },
235 
246  activate: function()
247  {
248  if (this._widgetJq && this._change)
249  { this._widgetJq.unbind("change input");
250  this._widgetJq.bind("change input", this.sync.bind(this));
251  }
252 
253  //this._html.bind("mouseenter", this.postMessageHandler.bind(this));
254 
255  this.validate();
256  },
257 
266  deactivate: function()
267  {
268  if (this._widgetJq)
269  this._widgetJq.unbind("change input blur click");
270 
271  //if (this._html)
272  // this._html.unbind("mouseenter");
273  },
274 
285  sync: function()
286  {
287  var v = this._widgetJq ? this._widgetJq.val() : null;
288 
289  this.value = v;
290 
291  return false;
292  },
293 
294 
306  applyOptions: function(ops)
307  {
308  for (var o in ops)
309  {
310  var v = ops[o];
311 
312  //console.warn(o);
313 
314  switch(o)
315  {
316  case "enabled": this.enabled = v; break;
317  case "hidden": this.hidden = v; break;
318 
319  default: if (o in this._options)
320  this._options[o] = v;
321  break;
322 
323  }
324  }
325  },
326 
339  doChange: function()
340  {
341  if (this._changeTimer)
342  clearTimeout( this._changeTimer );
343 
344  if (this._change)
345  {
346  if (!this._immediate)
347  {
348  var THIS = this;
349  this._changeTimer = setTimeout( function() {
350  THIS._change(THIS._variable,THIS._value,THIS);
351  THIS._changeTimer = null;
352  }, preferences.fetch("uifrequency",100) );
353  }
354  else
355  this._change(this._variable,this._value,this);
356  }
357  },
358 
367  enable: function() { this.enabled = true; },
368 
379  disable: function() { this.enabled = false; },
380 
394  {
395  if (this._value !== v)
396  {
397  var i = this._immediate;
398  this._immediate = true;
399  this.value = v;
400  this._immediate = i; //return button value to its previous state (which may allow it to remain true, like for buttons)
401 
402  if (this._activeUser)
403  this.arrowMessage( this._activeUser );
404  }
405  },
406 
414  get value() {
415  return this._value;
416  },
417 
428  set value(v) {
429  var ov = this._value;
430 
431  this._value = v;
432 
433  if (ov !== v)
434  {
435  if (this._widgetJq && this._widgetJq.val()!==v)
436  this._widgetJq.val(v);
437 
438  var valid = this.validate();
439 
440  if (this._change && valid===true)
441  this.doChange(v);
442  }
443 
444  return this._value;
445  },
446 
453  get defaultValue() {
454  return this._default;
455  },
456 
463  set defaultValue(v) {
464  this._default = v;
465  return this._default;
466  },
467 
474  get visibleWidget() {
475  return this._widgetJq;
476  },
477 
486  get isDefault() {
487  return (this.value === this.defaultValue)
488  },
489 
496  get nonDefaultValue() {
497  if (!this.isDefault)
498  return this.value;
499 
500  return undefined;
501  },
502 
514  set validator(v) {
515  this._validator = v;
516  },
517 
527  set error(e) {
528  this._error = e;
529 
530  if (this._labelJq)
531  { if (e===false || e===undefined || e===null)
532  { this._labelJq.css("color","");
533  //this._labelJq.unbind("mouseover");
534  this._labelJq.removeAttr("title");
535  }
536  else
537  {
538  this._labelJq.css("color",widget.errorColor);
539  this._labelJq.attr("title",this._error);
540  //if (e!==true)
541  // this._labelJq.bind("mouseover", this.postErrorHandler.bind(this) );
542  }
543  }
544 
545  return e;
546  },
547 
554  get error() {
555  return this._error;
556  },
557 
568  set activeUser(u) {
569  this._activeUser = u;
570  },
571 
578  get enabled() { return this._enabled; },
579 
588  set enabled(e) {
589  this._enabled = e ? true : false;
590 
591  if (this._widgetJq)
592  {
593  if (this._enabled)
594  { this._widgetJq.removeAttr("disabled");
595  }
596  else
597  { this._widgetJq.attr("disabled","disabled");
598  }
599  }
600 
601  return this._enabled;
602  },
603 
610  get hidden() {
611  return this._hidden;
612  },
613 
622  set hidden(e) {
623  this._hidden = e;
624  if (this._html)
625  { if (this._hidden)
626  this._html.css("display","none");
627  else
628  this._html.css("display","");
629  }
630  else
631  console.log("no _html to hide!");
632 
633  },
634 
649  validate: function()
650  {
651  if (this._validator)
652  { var r = this._validator(this._value,this._options);
653  if (r===true)
654  this.error = false;
655  else
656  this.error = r;
657  return r;
658  }
659  else
660  {
661  this.error = false;
662  return true;
663  }
664  },
665 
673  arrowMessage: function(m)
674  {
675  if (preferences.fetch("arrowMessages",true) === false)
676  return;
677 
678  //FIXME: do we want some kind of stacking here? Or ability to add to an existing arrow message?
679  if (this._arrowMessage)
680  { return;
681  this._arrowMessage.destroy();
682  }
683 
684  var THIS = this;
685  this._arrowMessage = new arrowMessage(m, this.visibleWidget, this._arrowAt);
686  this._arrowMessage._completeCallback = function() { THIS._arrowMessage = null; };
687  },
688 
689  //save: function() //FIXME
690  // {
691  //
692  // },
693 
694  /*
695  postMessageHandler: function()
696  {
697  if (this._tip)
698  this.postMessage( this._tip,this._widgetJq );
699 
700  //return false; //this disables mouseover to set the current pane, which prevents the space bar from setting single pane mode properly.
701  },
702 
703  postErrorHandler: function()
704  {
705  if (this._error)
706  this.postMessage( "<span style='color:red'>"+this._error+"</span>" );
707 
708  return false;
709  },
710 
711  postMessage: function(m)
712  {
713  console.warn("Post message handler should be overwritten by some other function. Base functionality does nothing.");
714  console.log("Message: "+m);
715  },
716  */
717 
726  destroy: function()
727  {
728  this.deactivate();
729 
730  if (this._widgetJq) this._widgetJq.remove();
731  if (this._html) this._html.remove();
732 
733  this._widgetJq = null;
734  this._html = null;
735 
736  for (var i in this)
737  delete this[i];
738  }
739  };
740 
741  widget.errorColor = "#FF6400";
742 
743  return widget;
744  }
745 );
746 
Create a message with an arrow pointing to a DOM element.
arrowMessage(message, o, at, my, offset, persistent)
The arrowMessage constructor.
setter value
a setter DOCME
getter id
returns the number of milliseconds since midnight January 1, 1970 UTC
validate()
setter widget
a setter DOCME
deactivate()
Deactivate this element and call deactivate on all its children.
getter valid
a getter DOCME
fetch(v, _default)
createHTML()
Create the HTML contents of the pane.
Utility functions for javascript clients.
uuid()
Generate a universally unique identifier.
Base class for GUI form widgets.
createLabel()
Create the label jQuery object.
disable()
Disable this widget.
getter isDefault
Return whether or not this widget's value is its default value.
getter visibleWidget
Return the visible jQuery object for this widget.
setter error
Set the error value of this widget.
getter nonDefaultValue
Return the value of this widget, or return undefined if it contains the default value.
getter hidden
The hidden state of this widget.
setter immediateValue
Set the value of this widget, and trigger the doChange method without waiting.
doChange()
Collect changes to the value of this widget and call this widget's _change method,...
applyOptions()
Apply option changes to an existing widget, like from a diff.
getter defaultValue
Return the default value of this widget.
enable()
Enable this widget.
getter enabled
Return true or false based on _enabled state.
sync()
Sync the visible value with the internal value.
setter validator
Set this widget's validator function.
setter activeUser
Set the activeUser of this widget.
createWidget()
Create the widget jQuery object.