rails_slickgrid 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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);