rails_slickgrid 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2011 Joe Martinez
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,24 @@
1
+ # Rails Slickgrid #
2
+
3
+ Rails Slickgrid is an effort to make the fast javascript grid/spreadsheet [SlickGrid](https://github.com/mleibman/SlickGrid) easier to use in rails.
4
+
5
+ It currently only generates the static assets into your `javascripts` and `stylesheets` but automatic grid generation is under development.
6
+
7
+ ## Installation
8
+
9
+ 1. Add `gem 'rails_slickgrid'` to your Gemfile
10
+ 2. `bundle install`
11
+ 3. `rails generate rails_slickgrid:install`
12
+ 4. In your layout or view call `slickgrid_assets`
13
+
14
+ ## TODO
15
+ 1. Automatic grid generation
16
+ 2. Column Detection
17
+ 3. Editable Grids
18
+ 4. Client side filters
19
+ 5. Server side filters
20
+
21
+ ## Copyright
22
+
23
+ SlickGrid itself is Copyright (c) 2010 Michael Leibman, http://github.com/mleibman/slickgrid
24
+ Rails Slickgrid is Copyright (c) 2011 Joe Martinez, https://github.com/capitalist/rails_slickgrid
data/Rakefile ADDED
@@ -0,0 +1,58 @@
1
+ # encoding: UTF-8
2
+ $LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
3
+ require 'rubygems'
4
+ require 'awesome_print'
5
+
6
+ begin require 'bundler/setup'
7
+ rescue LoadError
8
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
9
+ end
10
+
11
+ require 'rake'
12
+ require 'rake/rdoctask'
13
+
14
+ require 'rspec/core'
15
+ require 'rspec/core/rake_task'
16
+
17
+ RSpec::Core::RakeTask.new(:spec)
18
+
19
+ task :default => :spec
20
+
21
+ Rake::RDocTask.new(:rdoc) do |rdoc|
22
+ rdoc.rdoc_dir = 'rdoc'
23
+ rdoc.title = 'Rails Slickgrid'
24
+ rdoc.options << '--line-numbers' << '--inline-source'
25
+ rdoc.rdoc_files.include('README.rdoc')
26
+ rdoc.rdoc_files.include('lib/**/*.rb')
27
+ end
28
+
29
+ require "rails_slickgrid/version"
30
+ task :build do
31
+ system "gem build rails_slickgrid.gemspec"
32
+ end
33
+
34
+ task :release => :build do
35
+ system "gem push rails_slickgrid-#{RailsSlickgrid::VERSION}.gem"
36
+ end
37
+
38
+ require 'rails_slickgrid/utils'
39
+ desc 'Download slickgrid assets'
40
+ task :download_slickgrid do
41
+ stylesheets = {
42
+ 'https://github.com/mleibman/SlickGrid/raw/1.4.3/slick.columnpicker.css' => 'lib/generators/rails_slickgrid/install/stylesheets/:name',
43
+ 'https://github.com/mleibman/SlickGrid/raw/1.4.3/slick.grid.css' => 'lib/generators/rails_slickgrid/install/stylesheets/:name',
44
+ 'https://github.com/mleibman/SlickGrid/raw/1.4.3/slick.pager.css' => 'lib/generators/rails_slickgrid/install/stylesheets/:name',
45
+ }
46
+
47
+ javascripts = {
48
+ 'https://github.com/mleibman/SlickGrid/raw/1.4.3/slick.columnpicker.js' => 'lib/generators/rails_slickgrid/install/javascripts/:name',
49
+ 'https://github.com/mleibman/SlickGrid/raw/1.4.3/slick.editors.js' => 'lib/generators/rails_slickgrid/install/javascripts/:name',
50
+ 'https://github.com/mleibman/SlickGrid/raw/1.4.3/slick.model.js' => 'lib/generators/rails_slickgrid/install/javascripts/:name',
51
+ 'https://github.com/mleibman/SlickGrid/raw/1.4.3/slick.grid.js' => 'lib/generators/rails_slickgrid/install/javascripts/:name',
52
+ 'https://github.com/mleibman/SlickGrid/raw/1.4.3/slick.pager.js' => 'lib/generators/rails_slickgrid/install/javascripts/:name',
53
+ }
54
+
55
+ stylesheets.merge(javascripts).each do |url,path|
56
+ RailsSlickgrid::Utils.curl url, '-o', path.gsub(/:name/,url.split('/').last)
57
+ end
58
+ end
@@ -0,0 +1,17 @@
1
+ module RailsSlickgrid
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+ source_root File.expand_path("..", __FILE__)
5
+ desc "Copies Slickgrid assets into your public directory."
6
+
7
+ def copy_stylesheets
8
+ directory 'stylesheets', 'public/stylesheets/slickgrid'
9
+ end
10
+
11
+ def copy_javascripts
12
+ directory 'javascripts', 'public/javascripts/slickgrid'
13
+ end
14
+ end
15
+ end
16
+ end
17
+
@@ -0,0 +1,105 @@
1
+ (function($) {
2
+ function SlickColumnPicker(columns,grid,options)
3
+ {
4
+ var $menu;
5
+
6
+ var defaults = {
7
+ fadeSpeed: 250
8
+ };
9
+
10
+ function init() {
11
+ grid.onHeaderContextMenu = displayContextMenu;
12
+ options = $.extend({}, defaults, options);
13
+
14
+ $menu = $("<span class='slick-columnpicker' style='display:none;position:absolute;z-index:20;' />").appendTo(document.body);
15
+
16
+ $menu.bind("mouseleave", function(e) { $(this).fadeOut(options.fadeSpeed) });
17
+ $menu.bind("click", updateColumn);
18
+
19
+ }
20
+
21
+ function displayContextMenu(e)
22
+ {
23
+ $menu.empty();
24
+
25
+ var visibleColumns = grid.getColumns();
26
+ var $li, $input;
27
+ for (var i=0; i<columns.length; i++) {
28
+ $li = $("<li />").appendTo($menu);
29
+
30
+ $input = $("<input type='checkbox' />")
31
+ .attr("id", "columnpicker_" + i)
32
+ .data("id", columns[i].id)
33
+ .appendTo($li);
34
+
35
+ if (grid.getColumnIndex(columns[i].id) != null)
36
+ $input.attr("checked","checked");
37
+
38
+ $("<label for='columnpicker_" + i + "' />")
39
+ .text(columns[i].name)
40
+ .appendTo($li);
41
+ }
42
+
43
+ $("<hr/>").appendTo($menu);
44
+ $li = $("<li />").appendTo($menu);
45
+ $input = $("<input type='checkbox' id='autoresize' />").appendTo($li);
46
+ $("<label for='autoresize'>Force Fit Columns</label>").appendTo($li);
47
+ if (grid.getOptions().forceFitColumns)
48
+ $input.attr("checked", "checked");
49
+
50
+ $li = $("<li />").appendTo($menu);
51
+ $input = $("<input type='checkbox' id='syncresize' />").appendTo($li);
52
+ $("<label for='syncresize'>Synchronous Resizing</label>").appendTo($li);
53
+ if (grid.getOptions().syncColumnCellResize)
54
+ $input.attr("checked", "checked");
55
+
56
+ $menu
57
+ .css("top", e.pageY - 10)
58
+ .css("left", e.pageX - 10)
59
+ .fadeIn(options.fadeSpeed);
60
+ }
61
+
62
+ function updateColumn(e)
63
+ {
64
+ if (e.target.id == 'autoresize') {
65
+ if (e.target.checked) {
66
+ grid.setOptions({forceFitColumns: true});
67
+ grid.autosizeColumns();
68
+ } else {
69
+ grid.setOptions({forceFitColumns: false});
70
+ }
71
+ return;
72
+ }
73
+
74
+ if (e.target.id == 'syncresize') {
75
+ if (e.target.checked) {
76
+ grid.setOptions({syncColumnCellResize: true});
77
+ } else {
78
+ grid.setOptions({syncColumnCellResize: false});
79
+ }
80
+ return;
81
+ }
82
+
83
+ if ($(e.target).is(":checkbox")) {
84
+ if ($menu.find(":checkbox:checked").length == 0) {
85
+ $(e.target).attr("checked","checked");
86
+ return;
87
+ }
88
+
89
+ var visibleColumns = [];
90
+ $menu.find(":checkbox[id^=columnpicker]").each(function(i,e) {
91
+ if ($(this).is(":checked")) {
92
+ visibleColumns.push(columns[i]);
93
+ }
94
+ });
95
+ grid.setColumns(visibleColumns);
96
+ }
97
+ }
98
+
99
+
100
+ init();
101
+ }
102
+
103
+ // Slick.Controls.ColumnPicker
104
+ $.extend(true, window, { Slick: { Controls: { ColumnPicker: SlickColumnPicker }}});
105
+ })(jQuery);
@@ -0,0 +1,608 @@
1
+ /* THESE FORMATTERS & EDITORS ARE JUST SAMPLES! */
2
+
3
+ (function($) {
4
+
5
+ var SlickEditor = {
6
+
7
+ SelectorCellFormatter : function(row, cell, value, columnDef, dataContext) {
8
+ return (!dataContext ? "" : row);
9
+ },
10
+
11
+ PercentCompleteCellFormatter : function(row, cell, value, columnDef, dataContext) {
12
+ if (value == null || value === "")
13
+ return "-";
14
+ else if (value < 50)
15
+ return "<span style='color:red;font-weight:bold;'>" + value + "%</span>";
16
+ else
17
+ return "<span style='color:green'>" + value + "%</span>";
18
+ },
19
+
20
+ GraphicalPercentCompleteCellFormatter : function(row, cell, value, columnDef, dataContext) {
21
+ if (value == null || value === "")
22
+ return "";
23
+
24
+ var color;
25
+
26
+ if (value < 30)
27
+ color = "red";
28
+ else if (value < 70)
29
+ color = "silver";
30
+ else
31
+ color = "green";
32
+
33
+ return "<span class='percent-complete-bar' style='background:" + color + ";width:" + value + "%'></span>";
34
+ },
35
+
36
+ YesNoCellFormatter : function(row, cell, value, columnDef, dataContext) {
37
+ return value ? "Yes" : "No";
38
+ },
39
+
40
+ BoolCellFormatter : function(row, cell, value, columnDef, dataContext) {
41
+ return value ? "<img src='../images/tick.png'>" : "";
42
+ },
43
+
44
+ TaskNameFormatter : function(row, cell, value, columnDef, dataContext) {
45
+ // todo: html encode
46
+ var spacer = "<span style='display:inline-block;height:1px;width:" + (2 + 15 * dataContext["indent"]) + "px'></span>";
47
+ return spacer + " <img src='../images/expand.gif'>&nbsp;" + value;
48
+ },
49
+
50
+ ResourcesFormatter : function(row, cell, value, columnDef, dataContext) {
51
+ var resources = dataContext["resources"];
52
+
53
+ if (!resources || resources.length == 0)
54
+ return "";
55
+
56
+ if (columnDef.width < 50)
57
+ return (resources.length > 1 ? "<center><img src='../images/user_identity_plus.gif' " : "<center><img src='../images/user_identity.gif' ") +
58
+ " title='" + resources.join(", ") + "'></center>";
59
+ else
60
+ return resources.join(", ");
61
+ },
62
+
63
+ StarFormatter : function(row, cell, value, columnDef, dataContext) {
64
+ return (value) ? "<img src='../images/bullet_star.png' align='absmiddle'>" : "";
65
+ },
66
+
67
+
68
+ TextCellEditor : function(args) {
69
+ var $input;
70
+ var defaultValue;
71
+ var scope = this;
72
+
73
+ this.init = function() {
74
+ $input = $("<INPUT type=text class='editor-text' />")
75
+ .appendTo(args.container)
76
+ .bind("keydown.nav", function(e) {
77
+ if (e.keyCode === $.ui.keyCode.LEFT || e.keyCode === $.ui.keyCode.RIGHT) {
78
+ e.stopImmediatePropagation();
79
+ }
80
+ })
81
+ .focus()
82
+ .select();
83
+ };
84
+
85
+ this.destroy = function() {
86
+ $input.remove();
87
+ };
88
+
89
+ this.focus = function() {
90
+ $input.focus();
91
+ };
92
+
93
+ this.loadValue = function(item) {
94
+ defaultValue = item[args.column.field] || "";
95
+ $input.val(defaultValue);
96
+ $input[0].defaultValue = defaultValue;
97
+ $input.select();
98
+ };
99
+
100
+ this.serializeValue = function() {
101
+ return $input.val();
102
+ };
103
+
104
+ this.applyValue = function(item,state) {
105
+ item[args.column.field] = state;
106
+ };
107
+
108
+ this.isValueChanged = function() {
109
+ return (!($input.val() == "" && defaultValue == null)) && ($input.val() != defaultValue);
110
+ };
111
+
112
+ this.validate = function() {
113
+ if (args.column.validator) {
114
+ var validationResults = args.column.validator($input.val());
115
+ if (!validationResults.valid)
116
+ return validationResults;
117
+ }
118
+
119
+ return {
120
+ valid: true,
121
+ msg: null
122
+ };
123
+ };
124
+
125
+ this.init();
126
+ },
127
+
128
+ IntegerCellEditor : function(args) {
129
+ var $input;
130
+ var defaultValue;
131
+ var scope = this;
132
+
133
+ this.init = function() {
134
+ $input = $("<INPUT type=text class='editor-text' />");
135
+
136
+ $input.bind("keydown.nav", function(e) {
137
+ if (e.keyCode === $.ui.keyCode.LEFT || e.keyCode === $.ui.keyCode.RIGHT) {
138
+ e.stopImmediatePropagation();
139
+ }
140
+ });
141
+
142
+ $input.appendTo(args.container);
143
+ $input.focus().select();
144
+ };
145
+
146
+ this.destroy = function() {
147
+ $input.remove();
148
+ };
149
+
150
+ this.focus = function() {
151
+ $input.focus();
152
+ };
153
+
154
+ this.loadValue = function(item) {
155
+ defaultValue = item[args.column.field];
156
+ $input.val(defaultValue);
157
+ $input[0].defaultValue = defaultValue;
158
+ $input.select();
159
+ };
160
+
161
+ this.serializeValue = function() {
162
+ return parseInt($input.val(),10) || 0;
163
+ };
164
+
165
+ this.applyValue = function(item,state) {
166
+ item[args.column.field] = state;
167
+ };
168
+
169
+ this.isValueChanged = function() {
170
+ return (!($input.val() == "" && defaultValue == null)) && ($input.val() != defaultValue);
171
+ };
172
+
173
+ this.validate = function() {
174
+ if (isNaN($input.val()))
175
+ return {
176
+ valid: false,
177
+ msg: "Please enter a valid integer"
178
+ };
179
+
180
+ return {
181
+ valid: true,
182
+ msg: null
183
+ };
184
+ };
185
+
186
+ this.init();
187
+ },
188
+
189
+ DateCellEditor : function(args) {
190
+ var $input;
191
+ var defaultValue;
192
+ var scope = this;
193
+ var calendarOpen = false;
194
+
195
+ this.init = function() {
196
+ $input = $("<INPUT type=text class='editor-text' />");
197
+ $input.appendTo(args.container);
198
+ $input.focus().select();
199
+ $input.datepicker({
200
+ showOn: "button",
201
+ buttonImageOnly: true,
202
+ buttonImage: "../images/calendar.gif",
203
+ beforeShow: function() { calendarOpen = true },
204
+ onClose: function() { calendarOpen = false }
205
+ });
206
+ $input.width($input.width() - 18);
207
+ };
208
+
209
+ this.destroy = function() {
210
+ $.datepicker.dpDiv.stop(true,true);
211
+ $input.datepicker("hide");
212
+ $input.datepicker("destroy");
213
+ $input.remove();
214
+ };
215
+
216
+ this.show = function() {
217
+ if (calendarOpen) {
218
+ $.datepicker.dpDiv.stop(true,true).show();
219
+ }
220
+ };
221
+
222
+ this.hide = function() {
223
+ if (calendarOpen) {
224
+ $.datepicker.dpDiv.stop(true,true).hide();
225
+ }
226
+ };
227
+
228
+ this.position = function(position) {
229
+ if (!calendarOpen) return;
230
+ $.datepicker.dpDiv
231
+ .css("top", position.top + 30)
232
+ .css("left", position.left);
233
+ };
234
+
235
+ this.focus = function() {
236
+ $input.focus();
237
+ };
238
+
239
+ this.loadValue = function(item) {
240
+ defaultValue = item[args.column.field];
241
+ $input.val(defaultValue);
242
+ $input[0].defaultValue = defaultValue;
243
+ $input.select();
244
+ };
245
+
246
+ this.serializeValue = function() {
247
+ return $input.val();
248
+ };
249
+
250
+ this.applyValue = function(item,state) {
251
+ item[args.column.field] = state;
252
+ };
253
+
254
+ this.isValueChanged = function() {
255
+ return (!($input.val() == "" && defaultValue == null)) && ($input.val() != defaultValue);
256
+ };
257
+
258
+ this.validate = function() {
259
+ return {
260
+ valid: true,
261
+ msg: null
262
+ };
263
+ };
264
+
265
+ this.init();
266
+ },
267
+
268
+ YesNoSelectCellEditor : function(args) {
269
+ var $select;
270
+ var defaultValue;
271
+ var scope = this;
272
+
273
+ this.init = function() {
274
+ $select = $("<SELECT tabIndex='0' class='editor-yesno'><OPTION value='yes'>Yes</OPTION><OPTION value='no'>No</OPTION></SELECT>");
275
+ $select.appendTo(args.container);
276
+ $select.focus();
277
+ };
278
+
279
+ this.destroy = function() {
280
+ $select.remove();
281
+ };
282
+
283
+ this.focus = function() {
284
+ $select.focus();
285
+ };
286
+
287
+ this.loadValue = function(item) {
288
+ $select.val((defaultValue = item[args.column.field]) ? "yes" : "no");
289
+ $select.select();
290
+ };
291
+
292
+ this.serializeValue = function() {
293
+ return ($select.val() == "yes");
294
+ };
295
+
296
+ this.applyValue = function(item,state) {
297
+ item[args.column.field] = state;
298
+ };
299
+
300
+ this.isValueChanged = function() {
301
+ return ($select.val() != defaultValue);
302
+ };
303
+
304
+ this.validate = function() {
305
+ return {
306
+ valid: true,
307
+ msg: null
308
+ };
309
+ };
310
+
311
+ this.init();
312
+ },
313
+
314
+ YesNoCheckboxCellEditor : function(args) {
315
+ var $select;
316
+ var defaultValue;
317
+ var scope = this;
318
+
319
+ this.init = function() {
320
+ $select = $("<INPUT type=checkbox value='true' class='editor-checkbox' hideFocus>");
321
+ $select.appendTo(args.container);
322
+ $select.focus();
323
+ };
324
+
325
+ this.destroy = function() {
326
+ $select.remove();
327
+ };
328
+
329
+ this.focus = function() {
330
+ $select.focus();
331
+ };
332
+
333
+ this.loadValue = function(item) {
334
+ defaultValue = item[args.column.field];
335
+ if (defaultValue)
336
+ $select.attr("checked", "checked");
337
+ else
338
+ $select.removeAttr("checked");
339
+ };
340
+
341
+ this.serializeValue = function() {
342
+ return $select.attr("checked");
343
+ };
344
+
345
+ this.applyValue = function(item,state) {
346
+ item[args.column.field] = state;
347
+ };
348
+
349
+ this.isValueChanged = function() {
350
+ return ($select.attr("checked") != defaultValue);
351
+ };
352
+
353
+ this.validate = function() {
354
+ return {
355
+ valid: true,
356
+ msg: null
357
+ };
358
+ };
359
+
360
+ this.init();
361
+ },
362
+
363
+ PercentCompleteCellEditor : function(args) {
364
+ var $input, $picker;
365
+ var defaultValue;
366
+ var scope = this;
367
+
368
+ this.init = function() {
369
+ $input = $("<INPUT type=text class='editor-percentcomplete' />");
370
+ $input.width($(args.container).innerWidth() - 25);
371
+ $input.appendTo(args.container);
372
+
373
+ $picker = $("<div class='editor-percentcomplete-picker' />").appendTo(args.container);
374
+ $picker.append("<div class='editor-percentcomplete-helper'><div class='editor-percentcomplete-wrapper'><div class='editor-percentcomplete-slider' /><div class='editor-percentcomplete-buttons' /></div></div>");
375
+
376
+ $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>");
377
+
378
+ $input.focus().select();
379
+
380
+ $picker.find(".editor-percentcomplete-slider").slider({
381
+ orientation: "vertical",
382
+ range: "min",
383
+ value: defaultValue,
384
+ slide: function(event, ui) {
385
+ $input.val(ui.value)
386
+ }
387
+ });
388
+
389
+ $picker.find(".editor-percentcomplete-buttons button").bind("click", function(e) {
390
+ $input.val($(this).attr("val"));
391
+ $picker.find(".editor-percentcomplete-slider").slider("value", $(this).attr("val"));
392
+ })
393
+ };
394
+
395
+ this.destroy = function() {
396
+ $input.remove();
397
+ $picker.remove();
398
+ };
399
+
400
+ this.focus = function() {
401
+ $input.focus();
402
+ };
403
+
404
+ this.loadValue = function(item) {
405
+ $input.val(defaultValue = item[args.column.field]);
406
+ $input.select();
407
+ };
408
+
409
+ this.serializeValue = function() {
410
+ return parseInt($input.val(),10) || 0;
411
+ };
412
+
413
+ this.applyValue = function(item,state) {
414
+ item[args.column.field] = state;
415
+ };
416
+
417
+ this.isValueChanged = function() {
418
+ return (!($input.val() == "" && defaultValue == null)) && ((parseInt($input.val(),10) || 0) != defaultValue);
419
+ };
420
+
421
+ this.validate = function() {
422
+ if (isNaN(parseInt($input.val(),10)))
423
+ return {
424
+ valid: false,
425
+ msg: "Please enter a valid positive number"
426
+ };
427
+
428
+ return {
429
+ valid: true,
430
+ msg: null
431
+ };
432
+ };
433
+
434
+ this.init();
435
+ },
436
+
437
+ StarCellEditor : function(args) {
438
+ var $input;
439
+ var defaultValue;
440
+ var scope = this;
441
+
442
+ function toggle(e) {
443
+ if (e.type == "keydown" && e.which != 32) return;
444
+
445
+ if ($input.css("opacity") == "1")
446
+ $input.css("opacity", 0.5);
447
+ else
448
+ $input.css("opacity", 1);
449
+
450
+ e.preventDefault();
451
+ e.stopPropagation();
452
+ return false;
453
+ }
454
+
455
+ this.init = function() {
456
+ $input = $("<IMG src='../images/bullet_star.png' align=absmiddle tabIndex=0 title='Click or press Space to toggle' />")
457
+ .bind("click keydown", toggle)
458
+ .appendTo(args.container)
459
+ .focus();
460
+ };
461
+
462
+ this.destroy = function() {
463
+ $input.unbind("click keydown", toggle);
464
+ $input.remove();
465
+ };
466
+
467
+ this.focus = function() {
468
+ $input.focus();
469
+ };
470
+
471
+ this.loadValue = function(item) {
472
+ defaultValue = item[args.column.field];
473
+ $input.css("opacity", defaultValue ? 1 : 0.2);
474
+ };
475
+
476
+ this.serializeValue = function() {
477
+ return ($input.css("opacity") == "1");
478
+ };
479
+
480
+ this.applyValue = function(item,state) {
481
+ item[args.column.field] = state;
482
+ };
483
+
484
+ this.isValueChanged = function() {
485
+ return defaultValue != ($input.css("opacity") == "1");
486
+ };
487
+
488
+ this.validate = function() {
489
+ return {
490
+ valid: true,
491
+ msg: null
492
+ };
493
+ };
494
+
495
+ this.init();
496
+ },
497
+
498
+ /*
499
+ * An example of a "detached" editor.
500
+ * The UI is added onto document BODY and .position(), .show() and .hide() are implemented.
501
+ * KeyDown events are also handled to provide handling for Tab, Shift-Tab, Esc and Ctrl-Enter.
502
+ */
503
+ LongTextCellEditor : function (args) {
504
+ var $input, $wrapper;
505
+ var defaultValue;
506
+ var scope = this;
507
+
508
+ this.init = function() {
509
+ var $container = $("body");
510
+
511
+ $wrapper = $("<DIV style='z-index:10000;position:absolute;background:white;padding:5px;border:3px solid gray; -moz-border-radius:10px; border-radius:10px;'/>")
512
+ .appendTo($container);
513
+
514
+ $input = $("<TEXTAREA hidefocus rows=5 style='backround:white;width:250px;height:80px;border:0;outline:0'>")
515
+ .appendTo($wrapper);
516
+
517
+ $("<DIV style='text-align:right'><BUTTON>Save</BUTTON><BUTTON>Cancel</BUTTON></DIV>")
518
+ .appendTo($wrapper);
519
+
520
+ $wrapper.find("button:first").bind("click", this.save);
521
+ $wrapper.find("button:last").bind("click", this.cancel);
522
+ $input.bind("keydown", this.handleKeyDown);
523
+
524
+ scope.position(args.position);
525
+ $input.focus().select();
526
+ };
527
+
528
+ this.handleKeyDown = function(e) {
529
+ if (e.which == $.ui.keyCode.ENTER && e.ctrlKey) {
530
+ scope.save();
531
+ }
532
+ else if (e.which == $.ui.keyCode.ESCAPE) {
533
+ e.preventDefault();
534
+ scope.cancel();
535
+ }
536
+ else if (e.which == $.ui.keyCode.TAB && e.shiftKey) {
537
+ e.preventDefault();
538
+ grid.navigatePrev();
539
+ }
540
+ else if (e.which == $.ui.keyCode.TAB) {
541
+ e.preventDefault();
542
+ grid.navigateNext();
543
+ }
544
+ };
545
+
546
+ this.save = function() {
547
+ args.commitChanges();
548
+ };
549
+
550
+ this.cancel = function() {
551
+ $input.val(defaultValue);
552
+ args.cancelChanges();
553
+ };
554
+
555
+ this.hide = function() {
556
+ $wrapper.hide();
557
+ };
558
+
559
+ this.show = function() {
560
+ $wrapper.show();
561
+ };
562
+
563
+ this.position = function(position) {
564
+ $wrapper
565
+ .css("top", position.top - 5)
566
+ .css("left", position.left - 5)
567
+ };
568
+
569
+ this.destroy = function() {
570
+ $wrapper.remove();
571
+ };
572
+
573
+ this.focus = function() {
574
+ $input.focus();
575
+ };
576
+
577
+ this.loadValue = function(item) {
578
+ $input.val(defaultValue = item[args.column.field]);
579
+ $input.select();
580
+ };
581
+
582
+ this.serializeValue = function() {
583
+ return $input.val();
584
+ };
585
+
586
+ this.applyValue = function(item,state) {
587
+ item[args.column.field] = state;
588
+ };
589
+
590
+ this.isValueChanged = function() {
591
+ return (!($input.val() == "" && defaultValue == null)) && ($input.val() != defaultValue);
592
+ };
593
+
594
+ this.validate = function() {
595
+ return {
596
+ valid: true,
597
+ msg: null
598
+ };
599
+ };
600
+
601
+ this.init();
602
+ }
603
+
604
+ };
605
+
606
+ $.extend(window, SlickEditor);
607
+
608
+ })(jQuery);