slickgrid added to third-party
[myslice.git] / third-party / slickgrid-2.1 / slick.editors.js
1 /***
2  * Contains basic SlickGrid editors.
3  * @module Editors
4  * @namespace Slick
5  */
6
7 (function ($) {
8   // register namespace
9   $.extend(true, window, {
10     "Slick": {
11       "Editors": {
12         "Text": TextEditor,
13         "Integer": IntegerEditor,
14         "Date": DateEditor,
15         "YesNoSelect": YesNoSelectEditor,
16         "Checkbox": CheckboxEditor,
17         "PercentComplete": PercentCompleteEditor,
18         "LongText": LongTextEditor
19       }
20     }
21   });
22
23   function TextEditor(args) {
24     var $input;
25     var defaultValue;
26     var scope = this;
27
28     this.init = function () {
29       $input = $("<INPUT type=text class='editor-text' />")
30           .appendTo(args.container)
31           .bind("keydown.nav", function (e) {
32             if (e.keyCode === $.ui.keyCode.LEFT || e.keyCode === $.ui.keyCode.RIGHT) {
33               e.stopImmediatePropagation();
34             }
35           })
36           .focus()
37           .select();
38     };
39
40     this.destroy = function () {
41       $input.remove();
42     };
43
44     this.focus = function () {
45       $input.focus();
46     };
47
48     this.getValue = function () {
49       return $input.val();
50     };
51
52     this.setValue = function (val) {
53       $input.val(val);
54     };
55
56     this.loadValue = function (item) {
57       defaultValue = item[args.column.field] || "";
58       $input.val(defaultValue);
59       $input[0].defaultValue = defaultValue;
60       $input.select();
61     };
62
63     this.serializeValue = function () {
64       return $input.val();
65     };
66
67     this.applyValue = function (item, state) {
68       item[args.column.field] = state;
69     };
70
71     this.isValueChanged = function () {
72       return (!($input.val() == "" && defaultValue == null)) && ($input.val() != defaultValue);
73     };
74
75     this.validate = function () {
76       if (args.column.validator) {
77         var validationResults = args.column.validator($input.val());
78         if (!validationResults.valid) {
79           return validationResults;
80         }
81       }
82
83       return {
84         valid: true,
85         msg: null
86       };
87     };
88
89     this.init();
90   }
91
92   function IntegerEditor(args) {
93     var $input;
94     var defaultValue;
95     var scope = this;
96
97     this.init = function () {
98       $input = $("<INPUT type=text class='editor-text' />");
99
100       $input.bind("keydown.nav", function (e) {
101         if (e.keyCode === $.ui.keyCode.LEFT || e.keyCode === $.ui.keyCode.RIGHT) {
102           e.stopImmediatePropagation();
103         }
104       });
105
106       $input.appendTo(args.container);
107       $input.focus().select();
108     };
109
110     this.destroy = function () {
111       $input.remove();
112     };
113
114     this.focus = function () {
115       $input.focus();
116     };
117
118     this.loadValue = function (item) {
119       defaultValue = item[args.column.field];
120       $input.val(defaultValue);
121       $input[0].defaultValue = defaultValue;
122       $input.select();
123     };
124
125     this.serializeValue = function () {
126       return parseInt($input.val(), 10) || 0;
127     };
128
129     this.applyValue = function (item, state) {
130       item[args.column.field] = state;
131     };
132
133     this.isValueChanged = function () {
134       return (!($input.val() == "" && defaultValue == null)) && ($input.val() != defaultValue);
135     };
136
137     this.validate = function () {
138       if (isNaN($input.val())) {
139         return {
140           valid: false,
141           msg: "Please enter a valid integer"
142         };
143       }
144
145       return {
146         valid: true,
147         msg: null
148       };
149     };
150
151     this.init();
152   }
153
154   function DateEditor(args) {
155     var $input;
156     var defaultValue;
157     var scope = this;
158     var calendarOpen = false;
159
160     this.init = function () {
161       $input = $("<INPUT type=text class='editor-text' />");
162       $input.appendTo(args.container);
163       $input.focus().select();
164       $input.datepicker({
165         showOn: "button",
166         buttonImageOnly: true,
167         buttonImage: "../images/calendar.gif",
168         beforeShow: function () {
169           calendarOpen = true
170         },
171         onClose: function () {
172           calendarOpen = false
173         }
174       });
175       $input.width($input.width() - 18);
176     };
177
178     this.destroy = function () {
179       $.datepicker.dpDiv.stop(true, true);
180       $input.datepicker("hide");
181       $input.datepicker("destroy");
182       $input.remove();
183     };
184
185     this.show = function () {
186       if (calendarOpen) {
187         $.datepicker.dpDiv.stop(true, true).show();
188       }
189     };
190
191     this.hide = function () {
192       if (calendarOpen) {
193         $.datepicker.dpDiv.stop(true, true).hide();
194       }
195     };
196
197     this.position = function (position) {
198       if (!calendarOpen) {
199         return;
200       }
201       $.datepicker.dpDiv
202           .css("top", position.top + 30)
203           .css("left", position.left);
204     };
205
206     this.focus = function () {
207       $input.focus();
208     };
209
210     this.loadValue = function (item) {
211       defaultValue = item[args.column.field];
212       $input.val(defaultValue);
213       $input[0].defaultValue = defaultValue;
214       $input.select();
215     };
216
217     this.serializeValue = function () {
218       return $input.val();
219     };
220
221     this.applyValue = function (item, state) {
222       item[args.column.field] = state;
223     };
224
225     this.isValueChanged = function () {
226       return (!($input.val() == "" && defaultValue == null)) && ($input.val() != defaultValue);
227     };
228
229     this.validate = function () {
230       return {
231         valid: true,
232         msg: null
233       };
234     };
235
236     this.init();
237   }
238
239   function YesNoSelectEditor(args) {
240     var $select;
241     var defaultValue;
242     var scope = this;
243
244     this.init = function () {
245       $select = $("<SELECT tabIndex='0' class='editor-yesno'><OPTION value='yes'>Yes</OPTION><OPTION value='no'>No</OPTION></SELECT>");
246       $select.appendTo(args.container);
247       $select.focus();
248     };
249
250     this.destroy = function () {
251       $select.remove();
252     };
253
254     this.focus = function () {
255       $select.focus();
256     };
257
258     this.loadValue = function (item) {
259       $select.val((defaultValue = item[args.column.field]) ? "yes" : "no");
260       $select.select();
261     };
262
263     this.serializeValue = function () {
264       return ($select.val() == "yes");
265     };
266
267     this.applyValue = function (item, state) {
268       item[args.column.field] = state;
269     };
270
271     this.isValueChanged = function () {
272       return ($select.val() != defaultValue);
273     };
274
275     this.validate = function () {
276       return {
277         valid: true,
278         msg: null
279       };
280     };
281
282     this.init();
283   }
284
285   function CheckboxEditor(args) {
286     var $select;
287     var defaultValue;
288     var scope = this;
289
290     this.init = function () {
291       $select = $("<INPUT type=checkbox value='true' class='editor-checkbox' hideFocus>");
292       $select.appendTo(args.container);
293       $select.focus();
294     };
295
296     this.destroy = function () {
297       $select.remove();
298     };
299
300     this.focus = function () {
301       $select.focus();
302     };
303
304     this.loadValue = function (item) {
305       defaultValue = !!item[args.column.field];
306       if (defaultValue) {
307         $select.attr("checked", "checked");
308       } else {
309         $select.removeAttr("checked");
310       }
311     };
312
313     this.serializeValue = function () {
314       return !!$select.attr("checked");
315     };
316
317     this.applyValue = function (item, state) {
318       item[args.column.field] = state;
319     };
320
321     this.isValueChanged = function () {
322       return (this.serializeValue() !== defaultValue);
323     };
324
325     this.validate = function () {
326       return {
327         valid: true,
328         msg: null
329       };
330     };
331
332     this.init();
333   }
334
335   function PercentCompleteEditor(args) {
336     var $input, $picker;
337     var defaultValue;
338     var scope = this;
339
340     this.init = function () {
341       $input = $("<INPUT type=text class='editor-percentcomplete' />");
342       $input.width($(args.container).innerWidth() - 25);
343       $input.appendTo(args.container);
344
345       $picker = $("<div class='editor-percentcomplete-picker' />").appendTo(args.container);
346       $picker.append("<div class='editor-percentcomplete-helper'><div class='editor-percentcomplete-wrapper'><div class='editor-percentcomplete-slider' /><div class='editor-percentcomplete-buttons' /></div></div>");
347
348       $picker.find(".editor-percentcomplete-buttons").append("<button val=0>Not started</button><br/><button val=50>In Progress</button><br/><button val=100>Complete</button>");
349
350       $input.focus().select();
351
352       $picker.find(".editor-percentcomplete-slider").slider({
353         orientation: "vertical",
354         range: "min",
355         value: defaultValue,
356         slide: function (event, ui) {
357           $input.val(ui.value)
358         }
359       });
360
361       $picker.find(".editor-percentcomplete-buttons button").bind("click", function (e) {
362         $input.val($(this).attr("val"));
363         $picker.find(".editor-percentcomplete-slider").slider("value", $(this).attr("val"));
364       })
365     };
366
367     this.destroy = function () {
368       $input.remove();
369       $picker.remove();
370     };
371
372     this.focus = function () {
373       $input.focus();
374     };
375
376     this.loadValue = function (item) {
377       $input.val(defaultValue = item[args.column.field]);
378       $input.select();
379     };
380
381     this.serializeValue = function () {
382       return parseInt($input.val(), 10) || 0;
383     };
384
385     this.applyValue = function (item, state) {
386       item[args.column.field] = state;
387     };
388
389     this.isValueChanged = function () {
390       return (!($input.val() == "" && defaultValue == null)) && ((parseInt($input.val(), 10) || 0) != defaultValue);
391     };
392
393     this.validate = function () {
394       if (isNaN(parseInt($input.val(), 10))) {
395         return {
396           valid: false,
397           msg: "Please enter a valid positive number"
398         };
399       }
400
401       return {
402         valid: true,
403         msg: null
404       };
405     };
406
407     this.init();
408   }
409
410   /*
411    * An example of a "detached" editor.
412    * The UI is added onto document BODY and .position(), .show() and .hide() are implemented.
413    * KeyDown events are also handled to provide handling for Tab, Shift-Tab, Esc and Ctrl-Enter.
414    */
415   function LongTextEditor(args) {
416     var $input, $wrapper;
417     var defaultValue;
418     var scope = this;
419
420     this.init = function () {
421       var $container = $("body");
422
423       $wrapper = $("<DIV style='z-index:10000;position:absolute;background:white;padding:5px;border:3px solid gray; -moz-border-radius:10px; border-radius:10px;'/>")
424           .appendTo($container);
425
426       $input = $("<TEXTAREA hidefocus rows=5 style='backround:white;width:250px;height:80px;border:0;outline:0'>")
427           .appendTo($wrapper);
428
429       $("<DIV style='text-align:right'><BUTTON>Save</BUTTON><BUTTON>Cancel</BUTTON></DIV>")
430           .appendTo($wrapper);
431
432       $wrapper.find("button:first").bind("click", this.save);
433       $wrapper.find("button:last").bind("click", this.cancel);
434       $input.bind("keydown", this.handleKeyDown);
435
436       scope.position(args.position);
437       $input.focus().select();
438     };
439
440     this.handleKeyDown = function (e) {
441       if (e.which == $.ui.keyCode.ENTER && e.ctrlKey) {
442         scope.save();
443       } else if (e.which == $.ui.keyCode.ESCAPE) {
444         e.preventDefault();
445         scope.cancel();
446       } else if (e.which == $.ui.keyCode.TAB && e.shiftKey) {
447         e.preventDefault();
448         args.grid.navigatePrev();
449       } else if (e.which == $.ui.keyCode.TAB) {
450         e.preventDefault();
451         args.grid.navigateNext();
452       }
453     };
454
455     this.save = function () {
456       args.commitChanges();
457     };
458
459     this.cancel = function () {
460       $input.val(defaultValue);
461       args.cancelChanges();
462     };
463
464     this.hide = function () {
465       $wrapper.hide();
466     };
467
468     this.show = function () {
469       $wrapper.show();
470     };
471
472     this.position = function (position) {
473       $wrapper
474           .css("top", position.top - 5)
475           .css("left", position.left - 5)
476     };
477
478     this.destroy = function () {
479       $wrapper.remove();
480     };
481
482     this.focus = function () {
483       $input.focus();
484     };
485
486     this.loadValue = function (item) {
487       $input.val(defaultValue = item[args.column.field]);
488       $input.select();
489     };
490
491     this.serializeValue = function () {
492       return $input.val();
493     };
494
495     this.applyValue = function (item, state) {
496       item[args.column.field] = state;
497     };
498
499     this.isValueChanged = function () {
500       return (!($input.val() == "" && defaultValue == null)) && ($input.val() != defaultValue);
501     };
502
503     this.validate = function () {
504       return {
505         valid: true,
506         msg: null
507       };
508     };
509
510     this.init();
511   }
512 })(jQuery);