in_place_edit_with_datepicker 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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 71091b6f9913d5cef546bfbc8fc9a052b2593d08
4
+ data.tar.gz: c33ba645faa7b55b314a7bcd63a70bcdd8039988
5
+ SHA512:
6
+ metadata.gz: a6a45e8ce37580aa70aa5ba05a39636eb753159731c8a025bfa8c3b9820734519fed9a4943c74656554e6956d0bb4344fa81a79b356aa282d4babbb6faa7815e
7
+ data.tar.gz: 0116203acfdbb1255a068888063963866e8984acc1b3659072c68e3dc52f2965967103691a2905d0492a713bf09f11f8e0575df21f762888dd47f788e2ed8802
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in in_place_edit_with_datepicker.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Aastha Kesarwani-TCS
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,31 @@
1
+ # InPlaceEditWithDatepicker
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'in_place_edit_with_datepicker'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install in_place_edit_with_datepicker
20
+
21
+ ## Usage
22
+
23
+ TODO: Write usage instructions here
24
+
25
+ ## Contributing
26
+
27
+ 1. Fork it ( https://github.com/[my-github-username]/in_place_edit_with_datepicker/fork )
28
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
29
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
30
+ 4. Push to the branch (`git push origin my-new-feature`)
31
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'in_place_edit_with_datepicker/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "in_place_edit_with_datepicker"
8
+ spec.version = InPlaceEditWithDatepicker::VERSION
9
+ spec.authors = ["Aastha Kesarwani","Ekta Verma"]
10
+ spec.email = ["aastha.baloda@gmail.com","eku4evr@gmail.com"]
11
+ spec.summary = %q{"This gem extends best_in_place gem to include a datepicker"}
12
+ spec.description = %q{"It uses javascript to invoke jquery ui datepicker and timepicker to inline edit datetime fields"}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.7"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ spec.add_development_dependency "best_in_place", "~> 3.0.1"
24
+ end
@@ -0,0 +1,58 @@
1
+ /*
2
+ * BestInPlace 3.0.0.alpha (2014)
3
+ *
4
+ * Depends:
5
+ * best_in_place.js
6
+ * jquery.ui.datepicker.js
7
+ */
8
+ /*global BestInPlaceEditor */
9
+ BestInPlaceEditor.forms.date = {
10
+ activateForm: function () {
11
+ 'use strict';
12
+ var that = this,
13
+ output = jQuery(document.createElement('form'))
14
+ .addClass('form_in_place')
15
+ .attr('action', 'javascript:void(0);')
16
+ .attr('style', 'display:inline'),
17
+ input_elt = jQuery(document.createElement('input'))
18
+ .attr('type', 'text')
19
+ .attr('name', this.attributeName)
20
+ .attr('value', this.sanitizeValue(this.display_value));
21
+
22
+ if (this.inner_class !== null) {
23
+ input_elt.addClass(this.inner_class);
24
+ }
25
+ output.append(input_elt);
26
+
27
+ this.element.html(output);
28
+ this.setHtmlAttributes();
29
+ this.element.find('input')[0].select();
30
+ this.element.find("form").bind('submit', {editor: this}, BestInPlaceEditor.forms.input.submitHandler);
31
+ this.element.find("input").bind('keyup', {editor: this}, BestInPlaceEditor.forms.input.keyupHandler);
32
+
33
+ this.element.find('input')
34
+ .datepicker({
35
+ onClose: function () {
36
+ that.update();
37
+ }
38
+ })
39
+ .datepicker('show');
40
+ },
41
+
42
+ getValue: function () {
43
+ 'use strict';
44
+ return this.sanitizeValue(this.element.find("input").val());
45
+ },
46
+
47
+ submitHandler: function (event) {
48
+ 'use strict';
49
+ event.data.editor.update();
50
+ },
51
+
52
+ keyupHandler: function (event) {
53
+ 'use strict';
54
+ if (event.keyCode === 27) {
55
+ event.data.editor.abort();
56
+ }
57
+ }
58
+ }
@@ -0,0 +1,663 @@
1
+ /*
2
+ * BestInPlace (for jQuery)
3
+ * version: 3.0.0.alpha (2014)
4
+ *
5
+ * By Bernat Farrero based on the work of Jan Varwig.
6
+ * Examples at http://bernatfarrero.com
7
+ *
8
+ * Licensed under the MIT:
9
+ * http://www.opensource.org/licenses/mit-license.php
10
+ *
11
+ * @requires jQuery
12
+ *
13
+ * Usage:
14
+ *
15
+ * Attention.
16
+ * The format of the JSON object given to the select inputs is the following:
17
+ * [["key", "value"],["key", "value"]]
18
+ * The format of the JSON object given to the checkbox inputs is the following:
19
+ * ["falseValue", "trueValue"]
20
+
21
+ */
22
+ //= require jquery.autosize
23
+
24
+ function BestInPlaceEditor(e) {
25
+ 'use strict';
26
+ this.element = e;
27
+ this.initOptions();
28
+ this.bindForm();
29
+ this.initPlaceHolder();
30
+ jQuery(this.activator).bind('click', {editor: this}, this.clickHandler);
31
+ }
32
+
33
+ BestInPlaceEditor.prototype = {
34
+ // Public Interface Functions //////////////////////////////////////////////
35
+
36
+ activate: function () {
37
+ 'use strict';
38
+ var to_display;
39
+ if (this.isPlaceHolder()) {
40
+ to_display = "";
41
+ } else if (this.original_content) {
42
+ to_display = this.original_content;
43
+ } else {
44
+ switch (this.formType) {
45
+ case 'input':
46
+ case 'textarea':
47
+ if (this.display_raw) {
48
+ to_display = this.element.html().replace(/&/gi, '&');
49
+ }
50
+ else {
51
+ var value = this.element.data('bipValue');
52
+ if (typeof value === 'undefined') {
53
+ to_display = '';
54
+ } else if (typeof value === 'string') {
55
+ to_display = this.element.data('bipValue').replace(/&/gi, '&');
56
+ } else {
57
+ to_display = this.element.data('bipValue');
58
+ }
59
+ }
60
+ break;
61
+ case 'select':
62
+ to_display = this.element.html();
63
+
64
+ }
65
+ }
66
+
67
+ this.oldValue = this.isPlaceHolder() ? "" : this.element.html();
68
+ this.display_value = to_display;
69
+ jQuery(this.activator).unbind("click", this.clickHandler);
70
+ this.activateForm();
71
+ this.element.trigger(jQuery.Event("best_in_place:activate"));
72
+ },
73
+
74
+ abort: function () {
75
+ 'use strict';
76
+ this.activateText(this.oldValue);
77
+ jQuery(this.activator).bind('click', {editor: this}, this.clickHandler);
78
+ this.element.trigger(jQuery.Event("best_in_place:abort"));
79
+ this.element.trigger(jQuery.Event("best_in_place:deactivate"));
80
+ },
81
+
82
+ abortIfConfirm: function () {
83
+ 'use strict';
84
+ if (!this.useConfirm) {
85
+ this.abort();
86
+ return;
87
+ }
88
+
89
+ if (confirm(BestInPlaceEditor.defaults.locales[''].confirmMessage)) {
90
+ this.abort();
91
+ }
92
+ },
93
+
94
+ update: function () {
95
+ 'use strict';
96
+ var editor = this,
97
+ value = this.getValue();
98
+
99
+ // Avoid request if no change is made
100
+ if (this.formType in {"input": 1, "textarea": 1} && value === this.oldValue) {
101
+ this.abort();
102
+ return true;
103
+ }
104
+
105
+ editor.ajax({
106
+ "type": BestInPlaceEditor.defaults.ajaxMethod,
107
+ "dataType": BestInPlaceEditor.defaults.ajaxDataType,
108
+ "data": editor.requestData(),
109
+ "success": function (data, status, xhr) {
110
+ editor.loadSuccessCallback(data, status, xhr);
111
+ },
112
+ "error": function (request, error) {
113
+ editor.loadErrorCallback(request, error);
114
+ }
115
+ });
116
+
117
+
118
+ switch (this.formType) {
119
+ case "select":
120
+ this.previousCollectionValue = value;
121
+
122
+ // search for the text for the span
123
+ $.each(this.values, function(index, arr){ if (String(arr[0]) === String(value)) editor.element.html(arr[1]); });
124
+ break;
125
+
126
+ case "checkbox":
127
+ $.each(this.values, function(index, arr){ if (String(arr[0]) === String(value)) editor.element.html(arr[1]); });
128
+ break;
129
+
130
+ default:
131
+ if (value !== "") {
132
+ if (this.display_raw) {
133
+ editor.element.html(value);
134
+ } else {
135
+ editor.element.text(value);
136
+ }
137
+ } else {
138
+ editor.element.html(this.placeHolder);
139
+ }
140
+ }
141
+
142
+ editor.element.data('bipValue', value);
143
+ editor.element.attr('data-bip-value', value);
144
+
145
+ editor.element.trigger(jQuery.Event("best_in_place:update"));
146
+
147
+
148
+ },
149
+
150
+ activateForm: function () {
151
+ 'use strict';
152
+ alert(BestInPlaceEditor.defaults.locales[''].uninitializedForm);
153
+ },
154
+
155
+ activateText: function (value) {
156
+ 'use strict';
157
+ this.element.html(value);
158
+ if (this.isPlaceHolder()) {
159
+ this.element.html(this.placeHolder);
160
+ }
161
+ },
162
+
163
+ // Helper Functions ////////////////////////////////////////////////////////
164
+
165
+ initOptions: function () {
166
+ // Try parent supplied info
167
+ 'use strict';
168
+ var self = this;
169
+ self.element.parents().each(function () {
170
+ var $parent = jQuery(this);
171
+ self.url = self.url || $parent.data("bipUrl");
172
+ self.activator = self.activator || $parent.data("bipActivator");
173
+ self.okButton = self.okButton || $parent.data("bipOkButton");
174
+ self.okButtonClass = self.okButtonClass || $parent.data("bipOkButtonClass");
175
+ self.cancelButton = self.cancelButton || $parent.data("bipCancelButton");
176
+ self.cancelButtonClass = self.cancelButtonClass || $parent.data("bipCancelButtonClass");
177
+ self.skipBlur = self.skipBlur || $parent.data("bipSkipBlur");
178
+ });
179
+
180
+ // Load own attributes (overrides all others)
181
+ self.url = self.element.data("bipUrl") || self.url || document.location.pathname;
182
+ self.collection = self.element.data("bipCollection") || self.collection;
183
+ self.formType = self.element.data("bipType") || "input";
184
+ self.objectName = self.element.data("bipObject") || self.objectName;
185
+ self.attributeName = self.element.data("bipAttribute") || self.attributeName;
186
+ self.activator = self.element.data("bipActivator") || self.element;
187
+ self.okButton = self.element.data("bipOkButton") || self.okButton;
188
+ self.okButtonClass = self.element.data("bipOkButtonClass") || self.okButtonClass || BestInPlaceEditor.defaults.okButtonClass;
189
+ self.cancelButton = self.element.data("bipCancelButton") || self.cancelButton;
190
+ self.cancelButtonClass = self.element.data("bipCancelButtonClass") || self.cancelButtonClass || BestInPlaceEditor.defaults.cancelButtonClass;
191
+ self.skipBlur = self.element.data("bipSkipBlur") || self.skipBlur || BestInPlaceEditor.defaults.skipBlur;
192
+
193
+ // Fix for default values of 0
194
+ if (self.element.data("bipPlaceholder") == null) {
195
+ self.placeHolder = BestInPlaceEditor.defaults.locales[''].placeHolder;
196
+ } else {
197
+ self.placeHolder = self.element.data("bipPlaceholder");
198
+ }
199
+
200
+ self.inner_class = self.element.data("bipInnerClass");
201
+ self.html_attrs = self.element.data("bipHtmlAttrs");
202
+ self.original_content = self.element.data("bipOriginalContent") || self.original_content;
203
+
204
+ // if set the input won't be satinized
205
+ self.display_raw = self.element.data("bip-raw");
206
+
207
+ self.useConfirm = self.element.data("bip-confirm");
208
+
209
+ if (self.formType === "select" || self.formType === "checkbox") {
210
+ self.values = self.collection;
211
+ self.collectionValue = self.element.data("bipValue") || self.collectionValue;
212
+ }
213
+ },
214
+
215
+ bindForm: function () {
216
+ 'use strict';
217
+ this.activateForm = BestInPlaceEditor.forms[this.formType].activateForm;
218
+ this.getValue = BestInPlaceEditor.forms[this.formType].getValue;
219
+ },
220
+
221
+
222
+ initPlaceHolder: function () {
223
+ 'use strict';
224
+ // TODO add placeholder for select and checkbox
225
+ if (this.element.html() === "") {
226
+ this.element.html(this.placeHolder);
227
+ }
228
+ },
229
+
230
+ isPlaceHolder: function () {
231
+ 'use strict';
232
+ // TODO: It only work when form is deactivated.
233
+ // Condition will fail when form is activated
234
+ return this.element.html() === "" || this.element.html() === this.placeHolder;
235
+ },
236
+
237
+ getValue: function () {
238
+ 'use strict';
239
+ alert(BestInPlaceEditor.defaults.locales[''].uninitializedForm);
240
+ },
241
+
242
+ // Trim and Strips HTML from text
243
+ sanitizeValue: function (s) {
244
+ 'use strict';
245
+ return jQuery.trim(s);
246
+ },
247
+
248
+ /* Generate the data sent in the POST request */
249
+ requestData: function () {
250
+ 'use strict';
251
+ // To prevent xss attacks, a csrf token must be defined as a meta attribute
252
+ var csrf_token = jQuery('meta[name=csrf-token]').attr('content'),
253
+ csrf_param = jQuery('meta[name=csrf-param]').attr('content');
254
+
255
+ var data = "_method=" + BestInPlaceEditor.defaults.ajaxMethod;
256
+ data += "&" + this.objectName + '[' + this.attributeName + ']=' + encodeURIComponent(this.getValue());
257
+
258
+ if (csrf_param !== undefined && csrf_token !== undefined) {
259
+ data += "&" + csrf_param + "=" + encodeURIComponent(csrf_token);
260
+ }
261
+ return data;
262
+ },
263
+
264
+ ajax: function (options) {
265
+ 'use strict';
266
+ options.url = this.url;
267
+ options.beforeSend = function (xhr) {
268
+ xhr.setRequestHeader("Accept", "application/json");
269
+ };
270
+ return jQuery.ajax(options);
271
+ },
272
+
273
+ // Handlers ////////////////////////////////////////////////////////////////
274
+
275
+ loadSuccessCallback: function (data, status, xhr) {
276
+ 'use strict';
277
+ data = jQuery.trim(data);
278
+ //Update original content with current text.
279
+ if (this.display_raw) {
280
+ this.original_content = this.element.html();
281
+ } else {
282
+ this.original_content = this.element.text();
283
+ }
284
+
285
+ if (data && data !== "") {
286
+ var response = jQuery.parseJSON(data);
287
+ if (response !== null && response.hasOwnProperty("display_as")) {
288
+ this.element.data('bip-original-content', this.element.text());
289
+ this.element.html(response.display_as);
290
+ }
291
+ }
292
+
293
+ this.element.trigger(jQuery.Event("best_in_place:success"), [data, status, xhr]);
294
+ this.element.trigger(jQuery.Event("ajax:success"), [data, status, xhr]);
295
+
296
+ // Binding back after being clicked
297
+ jQuery(this.activator).bind('click', {editor: this}, this.clickHandler);
298
+ this.element.trigger(jQuery.Event("best_in_place:deactivate"));
299
+
300
+ if (this.collectionValue !== null && this.formType === "select") {
301
+ this.collectionValue = this.previousCollectionValue;
302
+ this.previousCollectionValue = null;
303
+ }
304
+ },
305
+
306
+ loadErrorCallback: function (request, error) {
307
+ 'use strict';
308
+ this.activateText(this.oldValue);
309
+
310
+ this.element.trigger(jQuery.Event("best_in_place:error"), [request, error]);
311
+ this.element.trigger(jQuery.Event("ajax:error"), request, error);
312
+
313
+ // Binding back after being clicked
314
+ jQuery(this.activator).bind('click', {editor: this}, this.clickHandler);
315
+ this.element.trigger(jQuery.Event("best_in_place:deactivate"));
316
+ },
317
+
318
+ clickHandler: function (event) {
319
+ 'use strict';
320
+ event.preventDefault();
321
+ event.data.editor.activate();
322
+ },
323
+
324
+ setHtmlAttributes: function () {
325
+ 'use strict';
326
+ var formField = this.element.find(this.formType);
327
+
328
+ if (this.html_attrs) {
329
+ var attrs = this.html_attrs;
330
+ $.each(attrs, function (key, val) {
331
+ formField.attr(key, val);
332
+ });
333
+ }
334
+ },
335
+
336
+ placeButtons: function (output, field) {
337
+ 'use strict';
338
+ if (field.okButton) {
339
+ output.append(
340
+ jQuery(document.createElement('input'))
341
+ .attr('type', 'submit')
342
+ .attr('class', field.okButtonClass)
343
+ .attr('value', field.okButton)
344
+ );
345
+ }
346
+ if (field.cancelButton) {
347
+ output.append(
348
+ jQuery(document.createElement('input'))
349
+ .attr('type', 'button')
350
+ .attr('class', field.cancelButtonClass)
351
+ .attr('value', field.cancelButton)
352
+ );
353
+ }
354
+ }
355
+ };
356
+
357
+
358
+ // Button cases:
359
+ // If no buttons, then blur saves, ESC cancels
360
+ // If just Cancel button, then blur saves, ESC or clicking Cancel cancels (careful of blur event!)
361
+ // If just OK button, then clicking OK saves (careful of blur event!), ESC or blur cancels
362
+ // If both buttons, then clicking OK saves, ESC or clicking Cancel or blur cancels
363
+ BestInPlaceEditor.forms = {
364
+ "input": {
365
+ activateForm: function () {
366
+ 'use strict';
367
+ var output = jQuery(document.createElement('form'))
368
+ .addClass('form_in_place')
369
+ .attr('action', 'javascript:void(0);')
370
+ .attr('style', 'display:inline');
371
+ var input_elt = jQuery(document.createElement('input'))
372
+ .attr('type', 'text')
373
+ .attr('name', this.attributeName)
374
+ .val(this.display_value);
375
+
376
+ // Add class to form input
377
+ if (this.inner_class) {
378
+ input_elt.addClass(this.inner_class);
379
+ }
380
+
381
+ output.append(input_elt);
382
+ this.placeButtons(output, this);
383
+
384
+ this.element.html(output);
385
+ this.setHtmlAttributes();
386
+
387
+ this.element.find("input[type='text']")[0].select();
388
+ this.element.find("form").bind('submit', {editor: this}, BestInPlaceEditor.forms.input.submitHandler);
389
+ if (this.cancelButton) {
390
+ this.element.find("input[type='button']").bind('click', {editor: this}, BestInPlaceEditor.forms.input.cancelButtonHandler);
391
+ }
392
+ if (!this.okButton) {
393
+ this.element.find("input[type='text']").bind('blur', {editor: this}, BestInPlaceEditor.forms.input.inputBlurHandler);
394
+ }
395
+ this.element.find("input[type='text']").bind('keyup', {editor: this}, BestInPlaceEditor.forms.input.keyupHandler);
396
+ this.blurTimer = null;
397
+ this.userClicked = false;
398
+ },
399
+
400
+ getValue: function () {
401
+ 'use strict';
402
+ return this.sanitizeValue(this.element.find("input").val());
403
+ },
404
+
405
+ // When buttons are present, use a timer on the blur event to give precedence to clicks
406
+ inputBlurHandler: function (event) {
407
+ 'use strict';
408
+ if (event.data.editor.okButton) {
409
+ event.data.editor.blurTimer = setTimeout(function () {
410
+ if (!event.data.editor.userClicked) {
411
+ event.data.editor.abort();
412
+ }
413
+ }, 500);
414
+ } else {
415
+ if (event.data.editor.cancelButton) {
416
+ event.data.editor.blurTimer = setTimeout(function () {
417
+ if (!event.data.editor.userClicked) {
418
+ event.data.editor.update();
419
+ }
420
+ }, 500);
421
+ } else {
422
+ event.data.editor.update();
423
+ }
424
+ }
425
+ },
426
+
427
+ submitHandler: function (event) {
428
+ 'use strict';
429
+ event.data.editor.userClicked = true;
430
+ clearTimeout(event.data.editor.blurTimer);
431
+ event.data.editor.update();
432
+ },
433
+
434
+ cancelButtonHandler: function (event) {
435
+ 'use strict';
436
+ event.data.editor.userClicked = true;
437
+ clearTimeout(event.data.editor.blurTimer);
438
+ event.data.editor.abort();
439
+ event.stopPropagation(); // Without this, click isn't handled
440
+ },
441
+
442
+ keyupHandler: function (event) {
443
+ 'use strict';
444
+ if (event.keyCode === 27) {
445
+ event.data.editor.abort();
446
+ event.stopImmediatePropagation();
447
+ }
448
+ }
449
+ },
450
+
451
+ "select": {
452
+ activateForm: function () {
453
+ 'use strict';
454
+ var output = jQuery(document.createElement('form'))
455
+ .attr('action', 'javascript:void(0)')
456
+ .attr('style', 'display:inline'),
457
+ selected = '',
458
+ select_elt = jQuery(document.createElement('select'))
459
+ .attr('class', this.inner_class !== null ? this.inner_class : ''),
460
+ currentCollectionValue = this.collectionValue,
461
+ key, value,
462
+ a = this.values;
463
+
464
+ $.each(a, function(index, arr){
465
+ key = arr[0];
466
+ value = arr[1];
467
+ var option_elt = jQuery(document.createElement('option'))
468
+ .val(key)
469
+ .html(value);
470
+ if (String(key) === String(currentCollectionValue)) option_elt.attr('selected', 'selected');
471
+ select_elt.append(option_elt);
472
+ });
473
+ output.append(select_elt);
474
+
475
+ this.element.html(output);
476
+ this.setHtmlAttributes();
477
+ this.element.find("select").bind('change', {editor: this}, BestInPlaceEditor.forms.select.blurHandler);
478
+ this.element.find("select").bind('blur', {editor: this}, BestInPlaceEditor.forms.select.blurHandler);
479
+ this.element.find("select").bind('keyup', {editor: this}, BestInPlaceEditor.forms.select.keyupHandler);
480
+ this.element.find("select")[0].focus();
481
+
482
+ // automatically click on the select so you
483
+ // don't have to click twice
484
+ try {
485
+ var e = document.createEvent("MouseEvents");
486
+ e.initMouseEvent("mousedown", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
487
+ this.element.find("select")[0].dispatchEvent(e);
488
+ }
489
+ catch(e) {
490
+ // browser doesn't support this, e.g. IE8
491
+ }
492
+ },
493
+
494
+ getValue: function () {
495
+ 'use strict';
496
+ return this.sanitizeValue(this.element.find("select").val());
497
+ },
498
+
499
+ blurHandler: function (event) {
500
+ 'use strict';
501
+ event.data.editor.update();
502
+ },
503
+
504
+ keyupHandler: function (event) {
505
+ 'use strict';
506
+ if (event.keyCode === 27) {
507
+ event.data.editor.abort();
508
+ }
509
+ }
510
+ },
511
+
512
+ "checkbox": {
513
+ activateForm: function () {
514
+ 'use strict';
515
+ this.collectionValue = !this.getValue();
516
+ this.setHtmlAttributes();
517
+ this.update();
518
+ },
519
+
520
+ getValue: function () {
521
+ 'use strict';
522
+ return this.collectionValue;
523
+ }
524
+ },
525
+
526
+ "textarea": {
527
+ activateForm: function () {
528
+ 'use strict';
529
+ // grab width and height of text
530
+ var width = this.element.css('width');
531
+ var height = this.element.css('height');
532
+
533
+ // construct form
534
+ var output = jQuery(document.createElement('form'))
535
+ .addClass('form_in_place')
536
+ .attr('action', 'javascript:void(0);')
537
+ .attr('style', 'display:inline');
538
+ var textarea_elt = jQuery(document.createElement('textarea'))
539
+ .attr('name', this.attributeName)
540
+ .val(this.sanitizeValue(this.display_value));
541
+
542
+ if (this.inner_class !== null) {
543
+ textarea_elt.addClass(this.inner_class);
544
+ }
545
+
546
+ output.append(textarea_elt);
547
+
548
+ this.placeButtons(output, this);
549
+
550
+ this.element.html(output);
551
+ this.setHtmlAttributes();
552
+
553
+ // set width and height of textarea
554
+ jQuery(this.element.find("textarea")[0]).css({'min-width': width, 'min-height': height});
555
+ jQuery(this.element.find("textarea")[0]).autosize();
556
+
557
+ this.element.find("textarea")[0].focus();
558
+ this.element.find("form").bind('submit', {editor: this}, BestInPlaceEditor.forms.textarea.submitHandler);
559
+
560
+ if (this.cancelButton) {
561
+ this.element.find("input[type='button']").bind('click', {editor: this}, BestInPlaceEditor.forms.textarea.cancelButtonHandler);
562
+ }
563
+
564
+ if (!this.skipBlur) {
565
+ this.element.find("textarea").bind('blur', {editor: this}, BestInPlaceEditor.forms.textarea.blurHandler);
566
+ }
567
+ this.element.find("textarea").bind('keyup', {editor: this}, BestInPlaceEditor.forms.textarea.keyupHandler);
568
+ this.blurTimer = null;
569
+ this.userClicked = false;
570
+ },
571
+
572
+ getValue: function () {
573
+ 'use strict';
574
+ return this.sanitizeValue(this.element.find("textarea").val());
575
+ },
576
+
577
+ // When buttons are present, use a timer on the blur event to give precedence to clicks
578
+ blurHandler: function (event) {
579
+ 'use strict';
580
+ if (event.data.editor.okButton) {
581
+ event.data.editor.blurTimer = setTimeout(function () {
582
+ if (!event.data.editor.userClicked) {
583
+ event.data.editor.abortIfConfirm();
584
+ }
585
+ }, 500);
586
+ } else {
587
+ if (event.data.editor.cancelButton) {
588
+ event.data.editor.blurTimer = setTimeout(function () {
589
+ if (!event.data.editor.userClicked) {
590
+ event.data.editor.update();
591
+ }
592
+ }, 500);
593
+ } else {
594
+ event.data.editor.update();
595
+ }
596
+ }
597
+ },
598
+
599
+ submitHandler: function (event) {
600
+ 'use strict';
601
+ event.data.editor.userClicked = true;
602
+ clearTimeout(event.data.editor.blurTimer);
603
+ event.data.editor.update();
604
+ },
605
+
606
+ cancelButtonHandler: function (event) {
607
+ 'use strict';
608
+ event.data.editor.userClicked = true;
609
+ clearTimeout(event.data.editor.blurTimer);
610
+ event.data.editor.abortIfConfirm();
611
+ event.stopPropagation(); // Without this, click isn't handled
612
+ },
613
+
614
+ keyupHandler: function (event) {
615
+ 'use strict';
616
+ if (event.keyCode === 27) {
617
+ event.data.editor.abortIfConfirm();
618
+ }
619
+ }
620
+ }
621
+ };
622
+
623
+ BestInPlaceEditor.defaults = {
624
+ locales: {},
625
+ ajaxMethod: "put", //TODO Change to patch when support to 3.2 is dropped
626
+ ajaxDataType: 'text',
627
+ okButtonClass: '',
628
+ cancelButtonClass: '',
629
+ skipBlur: false
630
+ };
631
+
632
+ // Default locale
633
+ BestInPlaceEditor.defaults.locales[''] = {
634
+ confirmMessage: "Are you sure you want to discard your changes?",
635
+ uninitializedForm: "The form was not properly initialized. getValue is unbound",
636
+ placeHolder: '-'
637
+ };
638
+
639
+ jQuery.fn.best_in_place = function () {
640
+ 'use strict';
641
+ function setBestInPlace(element) {
642
+ if (!element.data('bestInPlaceEditor')) {
643
+ element.data('bestInPlaceEditor', new BestInPlaceEditor(element));
644
+ return true;
645
+ }
646
+ }
647
+
648
+ jQuery(this.context).delegate(this.selector, 'click', function () {
649
+ var el = jQuery(this);
650
+ if (setBestInPlace(el)) {
651
+ el.click();
652
+ }
653
+ });
654
+
655
+ this.each(function () {
656
+ setBestInPlace(jQuery(this));
657
+ });
658
+
659
+ return this;
660
+ };
661
+
662
+
663
+