bootstrap-editable-rails 0.0.1 → 0.0.2
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/README.md +50 -1
- data/lib/bootstrap-editable-rails/version.rb +1 -1
- data/vendor/assets/javascripts/bootstrap-editable-inline.js +604 -327
- data/vendor/assets/javascripts/bootstrap-editable-inline.min.js +2 -2
- data/vendor/assets/javascripts/bootstrap-editable-rails.js.coffee +4 -5
- data/vendor/assets/javascripts/bootstrap-editable.js +606 -323
- data/vendor/assets/javascripts/bootstrap-editable.min.js +2 -2
- data/vendor/assets/stylesheets/bootstrap-editable.css +24 -11
- metadata +4 -4
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
In-place editing with Twitter Bootstrap for Rails
|
4
4
|
|
5
|
-
This gem is based on X-editable (v1.
|
5
|
+
This gem is based on X-editable (v1.3.0) which is the new version of Bootstrap Editable.
|
6
6
|
|
7
7
|
https://github.com/vitalets/x-editable
|
8
8
|
|
@@ -22,6 +22,8 @@ And then execute:
|
|
22
22
|
|
23
23
|
## Usage
|
24
24
|
|
25
|
+
### JavaScript & Stylesheet
|
26
|
+
|
25
27
|
Write the top of `app/assets/javascripts/application.js` like this:
|
26
28
|
|
27
29
|
```javascript
|
@@ -33,8 +35,55 @@ Write the top of `app/assets/javascripts/application.js` like this:
|
|
33
35
|
//= require_tree .
|
34
36
|
```
|
35
37
|
|
38
|
+
(You can choose `bootstrap-editable-inline`)
|
39
|
+
|
36
40
|
and need to load `bootstrap-editable.css` at the place where you like.
|
37
41
|
|
42
|
+
### HTML
|
43
|
+
|
44
|
+
Follow the documents above.
|
45
|
+
|
46
|
+
Additional required attribute(option) is `resource`.
|
47
|
+
|
48
|
+
```html
|
49
|
+
<a href="#" id="username" data-type="text" data-resource="post" data-name="username" data-url="/posts/1" data-original-title="Enter username">superuser</a>
|
50
|
+
```
|
51
|
+
|
52
|
+
then, sends `PUT /posts/1` request with the body:
|
53
|
+
|
54
|
+
```
|
55
|
+
post[username]=superuser
|
56
|
+
```
|
57
|
+
|
58
|
+
### Controller
|
59
|
+
|
60
|
+
PostsController receives the parameters
|
61
|
+
|
62
|
+
```
|
63
|
+
{ "id" => "1", "post" => { "username" => "superuser" } }
|
64
|
+
```
|
65
|
+
|
66
|
+
and must respond with 2xx (means _success_) status code if successful.
|
67
|
+
|
68
|
+
For example, scaffold goes well because default dataType is json.
|
69
|
+
|
70
|
+
```ruby
|
71
|
+
def update
|
72
|
+
@post = Post.find(params[:id])
|
73
|
+
|
74
|
+
respond_to do |format|
|
75
|
+
if @post.update_attributes(params[:post])
|
76
|
+
format.html { redirect_to @post, notice: 'Post was successfully updated.' }
|
77
|
+
format.json { head :no_content } # 204 No Content
|
78
|
+
else
|
79
|
+
format.html { render action: "edit" }
|
80
|
+
format.json { render json: @post.errors, status: :unprocessable_entity }
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
```
|
85
|
+
|
86
|
+
|
38
87
|
## Contributing
|
39
88
|
|
40
89
|
1. Fork it
|
@@ -1,12 +1,12 @@
|
|
1
|
-
/*! X-editable - v1.
|
1
|
+
/*! X-editable - v1.3.0
|
2
2
|
* In-place editing with Twitter Bootstrap, jQuery UI or pure jQuery
|
3
3
|
* http://github.com/vitalets/x-editable
|
4
4
|
* Copyright (c) 2012 Vitaliy Potapov; Licensed MIT */
|
5
5
|
|
6
6
|
/**
|
7
7
|
Form with single input element, two buttons and two states: normal/loading.
|
8
|
-
Applied as jQuery method to DIV tag (not to form tag!)
|
9
|
-
Editableform is linked with one of input types, e.g. 'text'
|
8
|
+
Applied as jQuery method to DIV tag (not to form tag!). This is because form can be in loading state when spinner shown.
|
9
|
+
Editableform is linked with one of input types, e.g. 'text', 'select' etc.
|
10
10
|
|
11
11
|
@class editableform
|
12
12
|
@uses text
|
@@ -14,9 +14,12 @@ Editableform is linked with one of input types, e.g. 'text' or 'select'.
|
|
14
14
|
**/
|
15
15
|
(function ($) {
|
16
16
|
|
17
|
-
var EditableForm = function (
|
17
|
+
var EditableForm = function (div, options) {
|
18
18
|
this.options = $.extend({}, $.fn.editableform.defaults, options);
|
19
|
-
this.$
|
19
|
+
this.$div = $(div); //div, containing form. Not form tag! Not editable-element.
|
20
|
+
if(!this.options.scope) {
|
21
|
+
this.options.scope = this;
|
22
|
+
}
|
20
23
|
this.initInput();
|
21
24
|
};
|
22
25
|
|
@@ -26,9 +29,9 @@ Editableform is linked with one of input types, e.g. 'text' or 'select'.
|
|
26
29
|
var TypeConstructor, typeOptions;
|
27
30
|
|
28
31
|
//create input of specified type
|
29
|
-
if(typeof $.fn.
|
30
|
-
TypeConstructor = $.fn.
|
31
|
-
typeOptions = $.fn.
|
32
|
+
if(typeof $.fn.editabletypes[this.options.type] === 'function') {
|
33
|
+
TypeConstructor = $.fn.editabletypes[this.options.type];
|
34
|
+
typeOptions = $.fn.editableutils.sliceObj(this.options, $.fn.editableutils.objectKeys(TypeConstructor.defaults));
|
32
35
|
this.input = new TypeConstructor(typeOptions);
|
33
36
|
} else {
|
34
37
|
$.error('Unknown type: '+ this.options.type);
|
@@ -50,7 +53,7 @@ Editableform is linked with one of input types, e.g. 'text' or 'select'.
|
|
50
53
|
**/
|
51
54
|
render: function() {
|
52
55
|
this.$loading = $($.fn.editableform.loading);
|
53
|
-
this.$
|
56
|
+
this.$div.empty().append(this.$loading);
|
54
57
|
this.showLoading();
|
55
58
|
|
56
59
|
//init form template and buttons
|
@@ -66,7 +69,7 @@ Editableform is linked with one of input types, e.g. 'text' or 'select'.
|
|
66
69
|
@event rendering
|
67
70
|
@param {Object} event event object
|
68
71
|
**/
|
69
|
-
this.$
|
72
|
+
this.$div.triggerHandler('rendering');
|
70
73
|
|
71
74
|
//render input
|
72
75
|
$.when(this.input.render())
|
@@ -85,21 +88,23 @@ Editableform is linked with one of input types, e.g. 'text' or 'select'.
|
|
85
88
|
}
|
86
89
|
|
87
90
|
//append form to container
|
88
|
-
this.$
|
89
|
-
|
91
|
+
this.$div.append(this.$form);
|
92
|
+
|
90
93
|
//attach 'cancel' handler
|
91
94
|
this.$form.find('.editable-cancel').click($.proxy(this.cancel, this));
|
92
|
-
// this.$form.find('.editable-buttons button').eq(1).click($.proxy(this.cancel, this));
|
93
95
|
|
94
96
|
if(this.input.error) {
|
95
97
|
this.error(this.input.error);
|
96
98
|
this.$form.find('.editable-submit').attr('disabled', true);
|
97
99
|
this.input.$input.attr('disabled', true);
|
100
|
+
//prevent form from submitting
|
101
|
+
this.$form.submit(function(e){ e.preventDefault(); });
|
98
102
|
} else {
|
99
103
|
this.error(false);
|
100
104
|
this.input.$input.removeAttr('disabled');
|
101
105
|
this.$form.find('.editable-submit').removeAttr('disabled');
|
102
106
|
this.input.value2input(this.value);
|
107
|
+
//attach submit handler
|
103
108
|
this.$form.submit($.proxy(this.submit, this));
|
104
109
|
}
|
105
110
|
|
@@ -108,7 +113,7 @@ Editableform is linked with one of input types, e.g. 'text' or 'select'.
|
|
108
113
|
@event rendered
|
109
114
|
@param {Object} event event object
|
110
115
|
**/
|
111
|
-
this.$
|
116
|
+
this.$div.triggerHandler('rendered');
|
112
117
|
|
113
118
|
this.showForm();
|
114
119
|
}, this));
|
@@ -119,7 +124,7 @@ Editableform is linked with one of input types, e.g. 'text' or 'select'.
|
|
119
124
|
@event cancel
|
120
125
|
@param {Object} event event object
|
121
126
|
**/
|
122
|
-
this.$
|
127
|
+
this.$div.triggerHandler('cancel');
|
123
128
|
},
|
124
129
|
showLoading: function() {
|
125
130
|
var w;
|
@@ -138,16 +143,18 @@ Editableform is linked with one of input types, e.g. 'text' or 'select'.
|
|
138
143
|
this.$loading.show();
|
139
144
|
},
|
140
145
|
|
141
|
-
showForm: function() {
|
146
|
+
showForm: function(activate) {
|
142
147
|
this.$loading.hide();
|
143
148
|
this.$form.show();
|
144
|
-
|
149
|
+
if(activate !== false) {
|
150
|
+
this.input.activate();
|
151
|
+
}
|
145
152
|
/**
|
146
153
|
Fired when form is shown
|
147
154
|
@event show
|
148
155
|
@param {Object} event event object
|
149
156
|
**/
|
150
|
-
this.$
|
157
|
+
this.$div.triggerHandler('show');
|
151
158
|
},
|
152
159
|
|
153
160
|
error: function(msg) {
|
@@ -168,8 +175,7 @@ Editableform is linked with one of input types, e.g. 'text' or 'select'.
|
|
168
175
|
e.preventDefault();
|
169
176
|
|
170
177
|
var error,
|
171
|
-
newValue = this.input.input2value()
|
172
|
-
newValueStr;
|
178
|
+
newValue = this.input.input2value(); //get new value from input
|
173
179
|
|
174
180
|
//validation
|
175
181
|
if (error = this.validate(newValue)) {
|
@@ -178,25 +184,34 @@ Editableform is linked with one of input types, e.g. 'text' or 'select'.
|
|
178
184
|
return;
|
179
185
|
}
|
180
186
|
|
181
|
-
//value
|
182
|
-
newValueStr = this.input.value2str(newValue);
|
183
|
-
|
184
|
-
//if value not changed --> cancel
|
187
|
+
//if value not changed --> trigger 'nochange' event and return
|
185
188
|
/*jslint eqeq: true*/
|
186
|
-
if (
|
189
|
+
if (!this.options.savenochange && this.input.value2str(newValue) == this.input.value2str(this.value)) {
|
187
190
|
/*jslint eqeq: false*/
|
188
|
-
|
191
|
+
/**
|
192
|
+
Fired when value not changed but form is submitted. Requires savenochange = false.
|
193
|
+
@event nochange
|
194
|
+
@param {Object} event event object
|
195
|
+
**/
|
196
|
+
this.$div.triggerHandler('nochange');
|
189
197
|
return;
|
190
198
|
}
|
191
199
|
|
192
200
|
//sending data to server
|
193
|
-
$.when(this.save(
|
201
|
+
$.when(this.save(newValue))
|
194
202
|
.done($.proxy(function(response) {
|
195
203
|
//run success callback
|
196
|
-
var res = typeof this.options.success === 'function' ? this.options.success.call(this, response, newValue) : null;
|
204
|
+
var res = typeof this.options.success === 'function' ? this.options.success.call(this.options.scope, response, newValue) : null;
|
197
205
|
|
198
|
-
//if success callback returns
|
199
|
-
if(res
|
206
|
+
//if success callback returns false --> keep form open and do not activate input
|
207
|
+
if(res === false) {
|
208
|
+
this.error(false);
|
209
|
+
this.showForm(false);
|
210
|
+
return;
|
211
|
+
}
|
212
|
+
|
213
|
+
//if success callback returns string --> keep form open, show error and activate input
|
214
|
+
if(typeof res === 'string') {
|
200
215
|
this.error(res);
|
201
216
|
this.showForm();
|
202
217
|
return;
|
@@ -223,7 +238,7 @@ Editableform is linked with one of input types, e.g. 'text' or 'select'.
|
|
223
238
|
if(params.newValue === 'username') {...}
|
224
239
|
});
|
225
240
|
**/
|
226
|
-
this.$
|
241
|
+
this.$div.triggerHandler('save', {newValue: newValue, response: response});
|
227
242
|
}, this))
|
228
243
|
.fail($.proxy(function(xhr) {
|
229
244
|
this.error(typeof xhr === 'string' ? xhr : xhr.responseText || xhr.statusText || 'Unknown error!');
|
@@ -231,10 +246,16 @@ Editableform is linked with one of input types, e.g. 'text' or 'select'.
|
|
231
246
|
}, this));
|
232
247
|
},
|
233
248
|
|
234
|
-
save: function(
|
235
|
-
|
249
|
+
save: function(newValue) {
|
250
|
+
//convert value for submitting to server
|
251
|
+
var submitValue = this.input.value2submit(newValue);
|
252
|
+
|
253
|
+
//try parse composite pk defined as json string in data-pk
|
254
|
+
this.options.pk = $.fn.editableutils.tryParseJson(this.options.pk, true);
|
255
|
+
|
256
|
+
var pk = (typeof this.options.pk === 'function') ? this.options.pk.call(this.options.scope) : this.options.pk,
|
236
257
|
send = !!(typeof this.options.url === 'function' || (this.options.url && ((this.options.send === 'always') || (this.options.send === 'auto' && pk)))),
|
237
|
-
params
|
258
|
+
params;
|
238
259
|
|
239
260
|
if (send) { //send to server
|
240
261
|
this.showLoading();
|
@@ -242,30 +263,28 @@ Editableform is linked with one of input types, e.g. 'text' or 'select'.
|
|
242
263
|
//standard params
|
243
264
|
params = {
|
244
265
|
name: this.options.name || '',
|
245
|
-
value:
|
266
|
+
value: submitValue,
|
246
267
|
pk: pk
|
247
268
|
};
|
248
269
|
|
249
270
|
//additional params
|
250
271
|
if(typeof this.options.params === 'function') {
|
251
|
-
|
272
|
+
params = this.options.params.call(this.options.scope, params);
|
252
273
|
} else {
|
253
274
|
//try parse json in single quotes (from data-params attribute)
|
254
|
-
this.options.params = $.fn.
|
275
|
+
this.options.params = $.fn.editableutils.tryParseJson(this.options.params, true);
|
255
276
|
$.extend(params, this.options.params);
|
256
277
|
}
|
257
278
|
|
258
279
|
if(typeof this.options.url === 'function') { //user's function
|
259
|
-
return this.options.url.call(this, params);
|
260
|
-
} else {
|
261
|
-
|
280
|
+
return this.options.url.call(this.options.scope, params);
|
281
|
+
} else {
|
282
|
+
//send ajax to server and return deferred object
|
283
|
+
return $.ajax($.extend({
|
262
284
|
url : this.options.url,
|
263
285
|
data : params,
|
264
|
-
type : '
|
265
|
-
|
266
|
-
}, this.options.ajaxOptions);
|
267
|
-
|
268
|
-
return $.ajax(ajaxOptions);
|
286
|
+
type : 'POST'
|
287
|
+
}, this.options.ajaxOptions));
|
269
288
|
}
|
270
289
|
}
|
271
290
|
},
|
@@ -275,7 +294,7 @@ Editableform is linked with one of input types, e.g. 'text' or 'select'.
|
|
275
294
|
value = this.value;
|
276
295
|
}
|
277
296
|
if (typeof this.options.validate === 'function') {
|
278
|
-
return this.options.validate.call(this, value);
|
297
|
+
return this.options.validate.call(this.options.scope, value);
|
279
298
|
}
|
280
299
|
},
|
281
300
|
|
@@ -361,10 +380,13 @@ Editableform is linked with one of input types, e.g. 'text' or 'select'.
|
|
361
380
|
**/
|
362
381
|
url:null,
|
363
382
|
/**
|
364
|
-
Additional params for submit.
|
383
|
+
Additional params for submit. If defined as <code>object</code> - it is **appended** to original ajax data (pk, name and value).
|
384
|
+
If defined as <code>function</code> - returned object **overwrites** original ajax data.
|
365
385
|
@example
|
366
386
|
params: function(params) {
|
367
|
-
|
387
|
+
//originally params contain pk, name and value
|
388
|
+
params.a = 1;
|
389
|
+
return params;
|
368
390
|
}
|
369
391
|
|
370
392
|
@property params
|
@@ -382,7 +404,7 @@ Editableform is linked with one of input types, e.g. 'text' or 'select'.
|
|
382
404
|
name: null,
|
383
405
|
/**
|
384
406
|
Primary key of editable object (e.g. record id in database). For composite keys use object, e.g. <code>{id: 1, lang: 'en'}</code>.
|
385
|
-
Can be calculated
|
407
|
+
Can be calculated dynamically via function.
|
386
408
|
|
387
409
|
@property pk
|
388
410
|
@type string|object|function
|
@@ -423,7 +445,7 @@ Editableform is linked with one of input types, e.g. 'text' or 'select'.
|
|
423
445
|
validate: null,
|
424
446
|
/**
|
425
447
|
Success callback. Called when value successfully sent on server and **response status = 200**.
|
426
|
-
|
448
|
+
Useful to work with json response. For example, if your backend response can be <code>{success: true}</code>
|
427
449
|
or <code>{success: false, msg: "server error"}</code> you can check it inside this callback.
|
428
450
|
If it returns **string** - means error occured and string is shown as error message.
|
429
451
|
If it returns **object like** <code>{newValue: <something>}</code> - it overwrites value, submitted by user.
|
@@ -437,7 +459,7 @@ Editableform is linked with one of input types, e.g. 'text' or 'select'.
|
|
437
459
|
if(!response.success) return response.msg;
|
438
460
|
}
|
439
461
|
**/
|
440
|
-
success:
|
462
|
+
success: null,
|
441
463
|
/**
|
442
464
|
Additional options for ajax request.
|
443
465
|
List of values: http://api.jquery.com/jQuery.ajax
|
@@ -445,28 +467,44 @@ Editableform is linked with one of input types, e.g. 'text' or 'select'.
|
|
445
467
|
@property ajaxOptions
|
446
468
|
@type object
|
447
469
|
@default null
|
470
|
+
@since 1.1.1
|
448
471
|
**/
|
449
472
|
ajaxOptions: null,
|
450
473
|
/**
|
451
|
-
|
474
|
+
Whether to show buttons or not.
|
452
475
|
Form without buttons can be auto-submitted by input or by onblur = 'submit'.
|
476
|
+
@example
|
477
|
+
ajaxOptions: {
|
478
|
+
method: 'PUT',
|
479
|
+
dataType: 'xml'
|
480
|
+
}
|
453
481
|
|
454
482
|
@property showbuttons
|
455
483
|
@type boolean
|
456
484
|
@default true
|
485
|
+
@since 1.1.1
|
457
486
|
**/
|
458
|
-
showbuttons: true
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
<code>submitmode='never'</code> usefull for turning into classic form several inputs and submitting them together manually.
|
463
|
-
Works pretty with <code>showbuttons=false</code>
|
487
|
+
showbuttons: true,
|
488
|
+
/**
|
489
|
+
Scope for callback methods (success, validate).
|
490
|
+
If <code>null</code> means editableform instance itself.
|
464
491
|
|
465
|
-
@property
|
466
|
-
@type
|
467
|
-
@default
|
468
|
-
|
469
|
-
|
492
|
+
@property scope
|
493
|
+
@type DOMElement|object
|
494
|
+
@default null
|
495
|
+
@since 1.2.0
|
496
|
+
@private
|
497
|
+
**/
|
498
|
+
scope: null,
|
499
|
+
/**
|
500
|
+
Whether to save or cancel value when it was not changed but form was submitted
|
501
|
+
|
502
|
+
@property savenochange
|
503
|
+
@type boolean
|
504
|
+
@default false
|
505
|
+
@since 1.2.0
|
506
|
+
**/
|
507
|
+
savenochange: false
|
470
508
|
};
|
471
509
|
|
472
510
|
/*
|
@@ -487,26 +525,21 @@ Editableform is linked with one of input types, e.g. 'text' or 'select'.
|
|
487
525
|
$.fn.editableform.buttons = '<button type="submit" class="editable-submit">ok</button>'+
|
488
526
|
'<button type="button" class="editable-cancel">cancel</button>';
|
489
527
|
|
490
|
-
//error class
|
528
|
+
//error class attached to control-group
|
491
529
|
$.fn.editableform.errorGroupClass = null;
|
492
530
|
|
493
|
-
//error class
|
531
|
+
//error class attached to editable-error-block
|
494
532
|
$.fn.editableform.errorBlockClass = 'editable-error';
|
495
|
-
|
496
|
-
//input types
|
497
|
-
$.fn.editableform.types = {};
|
498
|
-
//utils
|
499
|
-
$.fn.editableform.utils = {};
|
500
|
-
|
501
533
|
}(window.jQuery));
|
502
534
|
/**
|
503
535
|
* EditableForm utilites
|
504
536
|
*/
|
505
537
|
(function ($) {
|
506
|
-
|
538
|
+
//utils
|
539
|
+
$.fn.editableutils = {
|
507
540
|
/**
|
508
541
|
* classic JS inheritance function
|
509
|
-
*/
|
542
|
+
*/
|
510
543
|
inherit: function (Child, Parent) {
|
511
544
|
var F = function() { };
|
512
545
|
F.prototype = Parent.prototype;
|
@@ -617,7 +650,14 @@ Editableform is linked with one of input types, e.g. 'text' or 'select'.
|
|
617
650
|
return k;
|
618
651
|
}
|
619
652
|
|
620
|
-
}
|
653
|
+
},
|
654
|
+
|
655
|
+
/**
|
656
|
+
method to escape html.
|
657
|
+
**/
|
658
|
+
escape: function(str) {
|
659
|
+
return $('<div>').text(str).html();
|
660
|
+
}
|
621
661
|
};
|
622
662
|
}(window.jQuery));
|
623
663
|
/**
|
@@ -642,7 +682,7 @@ Applied as jQuery method.
|
|
642
682
|
init: function(element, options) {
|
643
683
|
this.$element = $(element);
|
644
684
|
//todo: what is in priority: data or js?
|
645
|
-
this.options = $.extend({}, $.fn.editableContainer.defaults, $.fn.
|
685
|
+
this.options = $.extend({}, $.fn.editableContainer.defaults, $.fn.editableutils.getConfigData(this.$element), options);
|
646
686
|
this.splitOptions();
|
647
687
|
this.initContainer();
|
648
688
|
|
@@ -697,12 +737,14 @@ Applied as jQuery method.
|
|
697
737
|
},
|
698
738
|
|
699
739
|
initForm: function() {
|
740
|
+
this.formOptions.scope = this.$element[0]; //set scope of form callbacks to element
|
700
741
|
this.$form = $('<div>')
|
701
742
|
.editableform(this.formOptions)
|
702
743
|
.on({
|
703
744
|
save: $.proxy(this.save, this),
|
704
|
-
cancel: $.proxy(this.cancel, this),
|
705
|
-
|
745
|
+
cancel: $.proxy(function(){ this.hide('cancel'); }, this),
|
746
|
+
nochange: $.proxy(function(){ this.hide('nochange'); }, this),
|
747
|
+
show: $.proxy(this.setPosition, this), //re-position container every time form is shown (occurs each time after loading state)
|
706
748
|
rendering: $.proxy(this.setPosition, this), //this allows to place container correctly when loading shown
|
707
749
|
rendered: $.proxy(function(){
|
708
750
|
/**
|
@@ -741,7 +783,7 @@ Applied as jQuery method.
|
|
741
783
|
/**
|
742
784
|
Shows container with form
|
743
785
|
@method show()
|
744
|
-
@param {boolean} closeAll
|
786
|
+
@param {boolean} closeAll Whether to close all other editable containers when showing this one. Default true.
|
745
787
|
**/
|
746
788
|
show: function (closeAll) {
|
747
789
|
this.$element.addClass('editable-open');
|
@@ -765,8 +807,9 @@ Applied as jQuery method.
|
|
765
807
|
/**
|
766
808
|
Hides container with form
|
767
809
|
@method hide()
|
810
|
+
@param {string} reason Reason caused hiding. Can be <code>save|cancel|onblur|nochange|undefined (=manual)</code>
|
768
811
|
**/
|
769
|
-
hide: function() {
|
812
|
+
hide: function(reason) {
|
770
813
|
if(!this.tip() || !this.tip().is(':visible') || !this.$element.hasClass('editable-open')) {
|
771
814
|
return;
|
772
815
|
}
|
@@ -776,9 +819,17 @@ Applied as jQuery method.
|
|
776
819
|
Fired when container was hidden. It occurs on both save or cancel.
|
777
820
|
|
778
821
|
@event hidden
|
779
|
-
@param {
|
822
|
+
@param {object} event event object
|
823
|
+
@param {string} reason Reason caused hiding. Can be <code>save|cancel|onblur|nochange|undefined (=manual)</code>
|
824
|
+
@example
|
825
|
+
$('#username').on('hidden', function(e, reason) {
|
826
|
+
if(reason === 'save' || reason === 'cancel') {
|
827
|
+
//auto-open next editable
|
828
|
+
$(this).closest('tr').next().find('.editable').editable('show');
|
829
|
+
}
|
830
|
+
});
|
780
831
|
**/
|
781
|
-
this.$element.triggerHandler('hidden');
|
832
|
+
this.$element.triggerHandler('hidden', reason);
|
782
833
|
},
|
783
834
|
|
784
835
|
/* internal hide method. To be overwritten in child classes */
|
@@ -789,7 +840,7 @@ Applied as jQuery method.
|
|
789
840
|
/**
|
790
841
|
Toggles container visibility (show / hide)
|
791
842
|
@method toggle()
|
792
|
-
@param {boolean} closeAll
|
843
|
+
@param {boolean} closeAll Whether to close all other editable containers when showing this one. Default true.
|
793
844
|
**/
|
794
845
|
toggle: function(closeAll) {
|
795
846
|
if(this.tip && this.tip().is(':visible')) {
|
@@ -807,23 +858,8 @@ Applied as jQuery method.
|
|
807
858
|
//tbd in child class
|
808
859
|
},
|
809
860
|
|
810
|
-
cancel: function() {
|
811
|
-
if(this.options.autohide) {
|
812
|
-
this.hide();
|
813
|
-
}
|
814
|
-
/**
|
815
|
-
Fired when form was cancelled by user
|
816
|
-
|
817
|
-
@event cancel
|
818
|
-
@param {Object} event event object
|
819
|
-
**/
|
820
|
-
this.$element.triggerHandler('cancel');
|
821
|
-
},
|
822
|
-
|
823
861
|
save: function(e, params) {
|
824
|
-
|
825
|
-
this.hide();
|
826
|
-
}
|
862
|
+
this.hide('save');
|
827
863
|
/**
|
828
864
|
Fired when new value was submitted. You can use <code>$(this).data('editableContainer')</code> inside handler to access to editableContainer instance
|
829
865
|
|
@@ -884,8 +920,8 @@ Applied as jQuery method.
|
|
884
920
|
*/
|
885
921
|
closeOthers: function(element) {
|
886
922
|
$('.editable-open').each(function(i, el){
|
887
|
-
//do nothing with passed element
|
888
|
-
if(el === element) {
|
923
|
+
//do nothing with passed element and it's children
|
924
|
+
if(el === element || $(el).find(element).length) {
|
889
925
|
return;
|
890
926
|
}
|
891
927
|
|
@@ -898,7 +934,7 @@ Applied as jQuery method.
|
|
898
934
|
}
|
899
935
|
|
900
936
|
if(ec.options.onblur === 'cancel') {
|
901
|
-
$el.data('editableContainer').hide();
|
937
|
+
$el.data('editableContainer').hide('onblur');
|
902
938
|
} else if(ec.options.onblur === 'submit') {
|
903
939
|
$el.data('editableContainer').tip().find('form').submit();
|
904
940
|
}
|
@@ -972,7 +1008,7 @@ Applied as jQuery method.
|
|
972
1008
|
**/
|
973
1009
|
placement: 'top',
|
974
1010
|
/**
|
975
|
-
|
1011
|
+
Whether to hide container on save/cancel.
|
976
1012
|
|
977
1013
|
@property autohide
|
978
1014
|
@type boolean
|
@@ -987,6 +1023,7 @@ Applied as jQuery method.
|
|
987
1023
|
@property onblur
|
988
1024
|
@type string
|
989
1025
|
@default 'cancel'
|
1026
|
+
@since 1.1.1
|
990
1027
|
**/
|
991
1028
|
onblur: 'cancel'
|
992
1029
|
};
|
@@ -1015,7 +1052,7 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1015
1052
|
|
1016
1053
|
var Editable = function (element, options) {
|
1017
1054
|
this.$element = $(element);
|
1018
|
-
this.options = $.extend({}, $.fn.editable.defaults, $.fn.
|
1055
|
+
this.options = $.extend({}, $.fn.editable.defaults, $.fn.editableutils.getConfigData(this.$element), options);
|
1019
1056
|
this.init();
|
1020
1057
|
};
|
1021
1058
|
|
@@ -1027,9 +1064,6 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1027
1064
|
doAutotext,
|
1028
1065
|
finalize;
|
1029
1066
|
|
1030
|
-
//initialization flag
|
1031
|
-
this.isInit = true;
|
1032
|
-
|
1033
1067
|
//editableContainer must be defined
|
1034
1068
|
if(!$.fn.editableContainer) {
|
1035
1069
|
$.error('You must define $.fn.editableContainer via including corresponding file (e.g. editable-popover.js)');
|
@@ -1040,9 +1074,9 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1040
1074
|
this.options.name = this.options.name || this.$element.attr('id');
|
1041
1075
|
|
1042
1076
|
//create input of specified type. Input will be used for converting value, not in form
|
1043
|
-
if(typeof $.fn.
|
1044
|
-
TypeConstructor = $.fn.
|
1045
|
-
this.typeOptions = $.fn.
|
1077
|
+
if(typeof $.fn.editabletypes[this.options.type] === 'function') {
|
1078
|
+
TypeConstructor = $.fn.editabletypes[this.options.type];
|
1079
|
+
this.typeOptions = $.fn.editableutils.sliceObj(this.options, $.fn.editableutils.objectKeys(TypeConstructor.defaults));
|
1046
1080
|
this.input = new TypeConstructor(this.typeOptions);
|
1047
1081
|
} else {
|
1048
1082
|
$.error('Unknown type: '+ this.options.type);
|
@@ -1054,13 +1088,20 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1054
1088
|
this.value = this.input.html2value($.trim(this.$element.html()));
|
1055
1089
|
isValueByText = true;
|
1056
1090
|
} else {
|
1091
|
+
/*
|
1092
|
+
value can be string when received from 'data-value' attribute
|
1093
|
+
for complext objects value can be set as json string in data-value attribute,
|
1094
|
+
e.g. data-value="{city: 'Moscow', street: 'Lenina'}"
|
1095
|
+
*/
|
1096
|
+
this.options.value = $.fn.editableutils.tryParseJson(this.options.value, true);
|
1057
1097
|
if(typeof this.options.value === 'string') {
|
1058
|
-
|
1098
|
+
this.value = this.input.str2value(this.options.value);
|
1099
|
+
} else {
|
1100
|
+
this.value = this.options.value;
|
1059
1101
|
}
|
1060
|
-
this.value = this.input.str2value(this.options.value);
|
1061
1102
|
}
|
1062
1103
|
|
1063
|
-
//add 'editable' class
|
1104
|
+
//add 'editable' class to every editable element
|
1064
1105
|
this.$element.addClass('editable');
|
1065
1106
|
|
1066
1107
|
//attach handler activating editable. In disabled mode it just prevent default action (useful for links)
|
@@ -1088,29 +1129,46 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1088
1129
|
//if value was generated by text or value is empty, no sense to run autotext
|
1089
1130
|
doAutotext = !isValueByText && this.value !== null && this.value !== undefined;
|
1090
1131
|
doAutotext &= (this.options.autotext === 'always') || (this.options.autotext === 'auto' && !this.$element.text().length);
|
1091
|
-
$.when(doAutotext ? this.
|
1132
|
+
$.when(doAutotext ? this.render() : true).then($.proxy(function() {
|
1092
1133
|
if(this.options.disabled) {
|
1093
1134
|
this.disable();
|
1094
1135
|
} else {
|
1095
1136
|
this.enable();
|
1096
1137
|
}
|
1097
1138
|
/**
|
1098
|
-
Fired
|
1099
|
-
Can be used for display customization.
|
1139
|
+
Fired when element was initialized by editable method.
|
1100
1140
|
|
1101
|
-
@event
|
1141
|
+
@event init
|
1102
1142
|
@param {Object} event event object
|
1103
1143
|
@param {Object} editable editable instance
|
1104
|
-
@
|
1105
|
-
$('#action').on('render', function(e, editable) {
|
1106
|
-
var colors = {0: "gray", 1: "green", 2: "blue", 3: "red"};
|
1107
|
-
$(this).css("color", colors[editable.value]);
|
1108
|
-
});
|
1144
|
+
@since 1.2.0
|
1109
1145
|
**/
|
1110
|
-
this.$element.triggerHandler('
|
1111
|
-
this.isInit = false;
|
1146
|
+
this.$element.triggerHandler('init', this);
|
1112
1147
|
}, this));
|
1113
1148
|
},
|
1149
|
+
|
1150
|
+
/*
|
1151
|
+
Renders value into element's text.
|
1152
|
+
Can call custom display method from options.
|
1153
|
+
Can return deferred object.
|
1154
|
+
@method render()
|
1155
|
+
*/
|
1156
|
+
render: function() {
|
1157
|
+
//do not display anything
|
1158
|
+
if(this.options.display === false) {
|
1159
|
+
return;
|
1160
|
+
}
|
1161
|
+
//if it is input with source, we pass callback in third param to be called when source is loaded
|
1162
|
+
if(this.input.options.hasOwnProperty('source')) {
|
1163
|
+
return this.input.value2html(this.value, this.$element[0], this.options.display);
|
1164
|
+
//if display method defined --> use it
|
1165
|
+
} else if(typeof this.options.display === 'function') {
|
1166
|
+
return this.options.display.call(this.$element[0], this.value);
|
1167
|
+
//else use input's original value2html() method
|
1168
|
+
} else {
|
1169
|
+
return this.input.value2html(this.value, this.$element[0]);
|
1170
|
+
}
|
1171
|
+
},
|
1114
1172
|
|
1115
1173
|
/**
|
1116
1174
|
Enables editable
|
@@ -1198,6 +1256,11 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1198
1256
|
* set emptytext if element is empty (reverse: remove emptytext if needed)
|
1199
1257
|
*/
|
1200
1258
|
handleEmpty: function () {
|
1259
|
+
//do not handle empty if we do not display anything
|
1260
|
+
if(this.options.display === false) {
|
1261
|
+
return;
|
1262
|
+
}
|
1263
|
+
|
1201
1264
|
var emptyClass = 'editable-empty';
|
1202
1265
|
//emptytext shown only for enabled
|
1203
1266
|
if(!this.options.disabled) {
|
@@ -1218,7 +1281,7 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1218
1281
|
/**
|
1219
1282
|
Shows container with form
|
1220
1283
|
@method show()
|
1221
|
-
@param {boolean} closeAll
|
1284
|
+
@param {boolean} closeAll Whether to close all other editable containers when showing this one. Default true.
|
1222
1285
|
**/
|
1223
1286
|
show: function (closeAll) {
|
1224
1287
|
if(this.options.disabled) {
|
@@ -1228,14 +1291,10 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1228
1291
|
//init editableContainer: popover, tooltip, inline, etc..
|
1229
1292
|
if(!this.container) {
|
1230
1293
|
var containerOptions = $.extend({}, this.options, {
|
1231
|
-
value: this.value
|
1232
|
-
autohide: false //element will take care to show/hide container
|
1294
|
+
value: this.value
|
1233
1295
|
});
|
1234
1296
|
this.$element.editableContainer(containerOptions);
|
1235
|
-
this.$element.on(
|
1236
|
-
save: $.proxy(this.save, this),
|
1237
|
-
cancel: $.proxy(this.hide, this)
|
1238
|
-
});
|
1297
|
+
this.$element.on("save.internal", $.proxy(this.save, this));
|
1239
1298
|
this.container = this.$element.data('editableContainer');
|
1240
1299
|
} else if(this.container.tip().is(':visible')) {
|
1241
1300
|
return;
|
@@ -1253,17 +1312,12 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1253
1312
|
if(this.container) {
|
1254
1313
|
this.container.hide();
|
1255
1314
|
}
|
1256
|
-
|
1257
|
-
//return focus on element
|
1258
|
-
if (this.options.enablefocus && this.options.toggle === 'click') {
|
1259
|
-
this.$element.focus();
|
1260
|
-
}
|
1261
1315
|
},
|
1262
1316
|
|
1263
1317
|
/**
|
1264
1318
|
Toggles container visibility (show / hide)
|
1265
1319
|
@method toggle()
|
1266
|
-
@param {boolean} closeAll
|
1320
|
+
@param {boolean} closeAll Whether to close all other editable containers when showing this one. Default true.
|
1267
1321
|
**/
|
1268
1322
|
toggle: function(closeAll) {
|
1269
1323
|
if(this.container && this.container.tip().is(':visible')) {
|
@@ -1278,13 +1332,13 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1278
1332
|
*/
|
1279
1333
|
save: function(e, params) {
|
1280
1334
|
//if url is not user's function and value was not sent to server and value changed --> mark element with unsaved css.
|
1281
|
-
if(typeof this.options.url !== 'function' && params.response === undefined && this.input.value2str(this.value) !== this.input.value2str(params.newValue)) {
|
1335
|
+
if(typeof this.options.url !== 'function' && this.options.display !== false && params.response === undefined && this.input.value2str(this.value) !== this.input.value2str(params.newValue)) {
|
1282
1336
|
this.$element.addClass('editable-unsaved');
|
1283
1337
|
} else {
|
1284
1338
|
this.$element.removeClass('editable-unsaved');
|
1285
1339
|
}
|
1286
1340
|
|
1287
|
-
|
1341
|
+
// this.hide();
|
1288
1342
|
this.setValue(params.newValue);
|
1289
1343
|
|
1290
1344
|
/**
|
@@ -1319,7 +1373,7 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1319
1373
|
Sets new value of editable
|
1320
1374
|
@method setValue(value, convertStr)
|
1321
1375
|
@param {mixed} value new value
|
1322
|
-
@param {boolean} convertStr
|
1376
|
+
@param {boolean} convertStr whether to convert value from string to internal format
|
1323
1377
|
**/
|
1324
1378
|
setValue: function(value, convertStr) {
|
1325
1379
|
if(convertStr) {
|
@@ -1330,10 +1384,9 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1330
1384
|
if(this.container) {
|
1331
1385
|
this.container.option('value', this.value);
|
1332
1386
|
}
|
1333
|
-
$.when(this.
|
1387
|
+
$.when(this.render())
|
1334
1388
|
.then($.proxy(function() {
|
1335
1389
|
this.handleEmpty();
|
1336
|
-
this.$element.triggerHandler('render', this);
|
1337
1390
|
}, this));
|
1338
1391
|
},
|
1339
1392
|
|
@@ -1345,7 +1398,7 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1345
1398
|
if(this.container) {
|
1346
1399
|
this.container.activate();
|
1347
1400
|
}
|
1348
|
-
}
|
1401
|
+
}
|
1349
1402
|
};
|
1350
1403
|
|
1351
1404
|
/* EDITABLE PLUGIN DEFINITION
|
@@ -1376,7 +1429,7 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1376
1429
|
$('#username, #fullname').editable('validate');
|
1377
1430
|
// possible result:
|
1378
1431
|
{
|
1379
|
-
username: "username is
|
1432
|
+
username: "username is required",
|
1380
1433
|
fullname: "fullname should be minimum 3 letters length"
|
1381
1434
|
}
|
1382
1435
|
**/
|
@@ -1405,21 +1458,23 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1405
1458
|
this.each(function () {
|
1406
1459
|
var $this = $(this), data = $this.data(datakey);
|
1407
1460
|
if (data && data.value !== undefined && data.value !== null) {
|
1408
|
-
result[data.options.name] = data.input.
|
1461
|
+
result[data.options.name] = data.input.value2submit(data.value);
|
1409
1462
|
}
|
1410
1463
|
});
|
1411
1464
|
return result;
|
1412
1465
|
|
1413
1466
|
/**
|
1414
|
-
This method collects values from several editable elements and submit them all to server.
|
1415
|
-
|
1467
|
+
This method collects values from several editable elements and submit them all to server.
|
1468
|
+
Internally it runs client-side validation for all fields and submits only in case of success.
|
1469
|
+
See <a href="#newrecord">creating new records</a> for details.
|
1416
1470
|
|
1417
1471
|
@method submit(options)
|
1418
1472
|
@param {object} options
|
1419
1473
|
@param {object} options.url url to submit data
|
1420
1474
|
@param {object} options.data additional data to submit
|
1421
|
-
@param {
|
1422
|
-
@param {function} options.
|
1475
|
+
@param {object} options.ajaxOptions additional ajax options
|
1476
|
+
@param {function} options.error(obj) error handler
|
1477
|
+
@param {function} options.success(obj,config) success handler
|
1423
1478
|
@returns {Object} jQuery object
|
1424
1479
|
**/
|
1425
1480
|
case 'submit': //collects value, validate and submit to server for creating new record
|
@@ -1428,35 +1483,32 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1428
1483
|
errors = this.editable('validate'),
|
1429
1484
|
values;
|
1430
1485
|
|
1431
|
-
if(typeof config.error !== 'function') {
|
1432
|
-
config.error = function() {};
|
1433
|
-
}
|
1434
|
-
|
1435
1486
|
if($.isEmptyObject(errors)) {
|
1436
1487
|
values = this.editable('getValue');
|
1437
1488
|
if(config.data) {
|
1438
1489
|
$.extend(values, config.data);
|
1439
|
-
}
|
1440
|
-
|
1441
|
-
|
1490
|
+
}
|
1491
|
+
|
1492
|
+
$.ajax($.extend({
|
1442
1493
|
url: config.url,
|
1443
1494
|
data: values,
|
1444
|
-
|
1445
|
-
}
|
1446
|
-
|
1447
|
-
|
1448
|
-
|
1449
|
-
|
1450
|
-
|
1451
|
-
|
1452
|
-
|
1495
|
+
type: 'POST'
|
1496
|
+
}, config.ajaxOptions))
|
1497
|
+
.success(function(response) {
|
1498
|
+
//successful response 200 OK
|
1499
|
+
if(typeof config.success === 'function') {
|
1500
|
+
config.success.call($elems, response, config);
|
1501
|
+
}
|
1502
|
+
})
|
1503
|
+
.error(function(){ //ajax error
|
1504
|
+
if(typeof config.error === 'function') {
|
1453
1505
|
config.error.apply($elems, arguments);
|
1454
1506
|
}
|
1455
|
-
}).error(function(){ //ajax error
|
1456
|
-
config.error.apply($elems, arguments);
|
1457
1507
|
});
|
1458
1508
|
} else { //client-side validation error
|
1459
|
-
config.error
|
1509
|
+
if(typeof config.error === 'function') {
|
1510
|
+
config.error.call($elems, errors);
|
1511
|
+
}
|
1460
1512
|
}
|
1461
1513
|
return this;
|
1462
1514
|
}
|
@@ -1512,7 +1564,6 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1512
1564
|
@default 'click'
|
1513
1565
|
**/
|
1514
1566
|
toggle: 'click',
|
1515
|
-
|
1516
1567
|
/**
|
1517
1568
|
Text shown when element is empty.
|
1518
1569
|
|
@@ -1522,7 +1573,7 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1522
1573
|
**/
|
1523
1574
|
emptytext: 'Empty',
|
1524
1575
|
/**
|
1525
|
-
Allows to automatically set element's text based on it's value. Can be <code>auto|always|never</code>.
|
1576
|
+
Allows to automatically set element's text based on it's value. Can be <code>auto|always|never</code>. Useful for select and date.
|
1526
1577
|
For example, if dropdown list is <code>{1: 'a', 2: 'b'}</code> and element's value set to <code>1</code>, it's html will be automatically set to <code>'a'</code>.
|
1527
1578
|
<code>auto</code> - text will be automatically set only if element is empty.
|
1528
1579
|
<code>always|never</code> - always(never) try to set element's text.
|
@@ -1533,38 +1584,52 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1533
1584
|
**/
|
1534
1585
|
autotext: 'auto',
|
1535
1586
|
/**
|
1536
|
-
Wether to return focus on element after form is closed.
|
1537
|
-
This allows fully keyboard input.
|
1538
|
-
|
1539
|
-
@property enablefocus
|
1540
|
-
@type boolean
|
1541
|
-
@default false
|
1542
|
-
**/
|
1543
|
-
enablefocus: false,
|
1544
|
-
/**
|
1545
1587
|
Initial value of input. Taken from <code>data-value</code> or element's text.
|
1546
1588
|
|
1547
1589
|
@property value
|
1548
1590
|
@type mixed
|
1549
1591
|
@default element's text
|
1550
1592
|
**/
|
1551
|
-
value: null
|
1593
|
+
value: null,
|
1594
|
+
/**
|
1595
|
+
Callback to perform custom displaying of value in element's text.
|
1596
|
+
If <code>null</code>, default input's value2html() will be called.
|
1597
|
+
If <code>false</code>, no displaying methods will be called, element's text will no change.
|
1598
|
+
Runs under element's scope.
|
1599
|
+
Second parameter __sourceData__ is passed for inputs with source (select, checklist).
|
1600
|
+
|
1601
|
+
@property display
|
1602
|
+
@type function|boolean
|
1603
|
+
@default null
|
1604
|
+
@since 1.2.0
|
1605
|
+
@example
|
1606
|
+
display: function(value, sourceData) {
|
1607
|
+
var escapedValue = $('<div>').text(value).html();
|
1608
|
+
$(this).html('<b>'+escapedValue+'</b>');
|
1609
|
+
}
|
1610
|
+
**/
|
1611
|
+
display: null
|
1552
1612
|
};
|
1553
1613
|
|
1554
|
-
}(window.jQuery));
|
1614
|
+
}(window.jQuery));
|
1615
|
+
|
1555
1616
|
/**
|
1556
|
-
|
1557
|
-
|
1617
|
+
AbstractInput - base class for all editable inputs.
|
1618
|
+
It defines interface to be implemented by any input type.
|
1619
|
+
To create your own input you can inherit from this class.
|
1558
1620
|
|
1559
|
-
@class
|
1621
|
+
@class abstractinput
|
1560
1622
|
**/
|
1561
1623
|
(function ($) {
|
1562
1624
|
|
1563
|
-
|
1625
|
+
//types
|
1626
|
+
$.fn.editabletypes = {};
|
1627
|
+
|
1628
|
+
var AbstractInput = function () { };
|
1564
1629
|
|
1565
|
-
|
1630
|
+
AbstractInput.prototype = {
|
1566
1631
|
/**
|
1567
|
-
|
1632
|
+
Initializes input
|
1568
1633
|
|
1569
1634
|
@method init()
|
1570
1635
|
**/
|
@@ -1577,7 +1642,7 @@ To create your own input you should inherit from this class.
|
|
1577
1642
|
},
|
1578
1643
|
|
1579
1644
|
/**
|
1580
|
-
Renders input. Can return jQuery deferred object.
|
1645
|
+
Renders input from tpl. Can return jQuery deferred object.
|
1581
1646
|
|
1582
1647
|
@method render()
|
1583
1648
|
**/
|
@@ -1600,8 +1665,7 @@ To create your own input you should inherit from this class.
|
|
1600
1665
|
@param {DOMElement} element
|
1601
1666
|
**/
|
1602
1667
|
value2html: function(value, element) {
|
1603
|
-
|
1604
|
-
$(element).html(html);
|
1668
|
+
$(element).text(value);
|
1605
1669
|
},
|
1606
1670
|
|
1607
1671
|
/**
|
@@ -1616,7 +1680,7 @@ To create your own input you should inherit from this class.
|
|
1616
1680
|
},
|
1617
1681
|
|
1618
1682
|
/**
|
1619
|
-
Converts value to string (for
|
1683
|
+
Converts value to string (for internal compare). For submitting to server used value2submit().
|
1620
1684
|
|
1621
1685
|
@method value2str(value)
|
1622
1686
|
@param {mixed} value
|
@@ -1637,6 +1701,17 @@ To create your own input you should inherit from this class.
|
|
1637
1701
|
return str;
|
1638
1702
|
},
|
1639
1703
|
|
1704
|
+
/**
|
1705
|
+
Converts value for submitting to server
|
1706
|
+
|
1707
|
+
@method value2submit(value)
|
1708
|
+
@param {mixed} value
|
1709
|
+
@returns {mixed}
|
1710
|
+
**/
|
1711
|
+
value2submit: function(value) {
|
1712
|
+
return value;
|
1713
|
+
},
|
1714
|
+
|
1640
1715
|
/**
|
1641
1716
|
Sets value of input.
|
1642
1717
|
|
@@ -1668,11 +1743,11 @@ To create your own input you should inherit from this class.
|
|
1668
1743
|
},
|
1669
1744
|
|
1670
1745
|
/**
|
1671
|
-
|
1746
|
+
Creates input.
|
1672
1747
|
|
1673
1748
|
@method clear()
|
1674
1749
|
**/
|
1675
|
-
clear:
|
1750
|
+
clear: function() {
|
1676
1751
|
this.$input.val(null);
|
1677
1752
|
},
|
1678
1753
|
|
@@ -1684,14 +1759,14 @@ To create your own input you should inherit from this class.
|
|
1684
1759
|
},
|
1685
1760
|
|
1686
1761
|
/**
|
1687
|
-
attach handler to automatically submit form when value changed (
|
1762
|
+
attach handler to automatically submit form when value changed (useful when buttons not shown)
|
1688
1763
|
**/
|
1689
1764
|
autosubmit: function() {
|
1690
1765
|
|
1691
1766
|
}
|
1692
1767
|
};
|
1693
1768
|
|
1694
|
-
|
1769
|
+
AbstractInput.defaults = {
|
1695
1770
|
/**
|
1696
1771
|
HTML template of input. Normally you should not change it.
|
1697
1772
|
|
@@ -1702,12 +1777,12 @@ To create your own input you should inherit from this class.
|
|
1702
1777
|
tpl: '',
|
1703
1778
|
/**
|
1704
1779
|
CSS class automatically applied to input
|
1705
|
-
|
1780
|
+
|
1706
1781
|
@property inputclass
|
1707
1782
|
@type string
|
1708
|
-
@default
|
1783
|
+
@default input-medium
|
1709
1784
|
**/
|
1710
|
-
inputclass: '
|
1785
|
+
inputclass: 'input-medium',
|
1711
1786
|
/**
|
1712
1787
|
Name attribute of input
|
1713
1788
|
|
@@ -1718,14 +1793,15 @@ To create your own input you should inherit from this class.
|
|
1718
1793
|
name: null
|
1719
1794
|
};
|
1720
1795
|
|
1721
|
-
$.extend($.fn.
|
1796
|
+
$.extend($.fn.editabletypes, {abstractinput: AbstractInput});
|
1722
1797
|
|
1723
|
-
}(window.jQuery));
|
1798
|
+
}(window.jQuery));
|
1799
|
+
|
1724
1800
|
/**
|
1725
1801
|
List - abstract class for inputs that have source option loaded from js array or via ajax
|
1726
1802
|
|
1727
1803
|
@class list
|
1728
|
-
@extends
|
1804
|
+
@extends abstractinput
|
1729
1805
|
**/
|
1730
1806
|
(function ($) {
|
1731
1807
|
|
@@ -1733,7 +1809,7 @@ List - abstract class for inputs that have source option loaded from js array or
|
|
1733
1809
|
|
1734
1810
|
};
|
1735
1811
|
|
1736
|
-
$.fn.
|
1812
|
+
$.fn.editableutils.inherit(List, $.fn.editabletypes.abstractinput);
|
1737
1813
|
|
1738
1814
|
$.extend(List.prototype, {
|
1739
1815
|
render: function () {
|
@@ -1757,13 +1833,18 @@ List - abstract class for inputs that have source option loaded from js array or
|
|
1757
1833
|
return null; //can't set value by text
|
1758
1834
|
},
|
1759
1835
|
|
1760
|
-
value2html: function (value, element) {
|
1836
|
+
value2html: function (value, element, display) {
|
1761
1837
|
var deferred = $.Deferred();
|
1762
1838
|
this.onSourceReady(function () {
|
1763
|
-
|
1839
|
+
if(typeof display === 'function') {
|
1840
|
+
//custom display method
|
1841
|
+
display.call(element, value, this.sourceData);
|
1842
|
+
} else {
|
1843
|
+
this.value2htmlFinal(value, element);
|
1844
|
+
}
|
1764
1845
|
deferred.resolve();
|
1765
1846
|
}, function () {
|
1766
|
-
|
1847
|
+
//do nothing with element
|
1767
1848
|
deferred.resolve();
|
1768
1849
|
});
|
1769
1850
|
|
@@ -1781,7 +1862,7 @@ List - abstract class for inputs that have source option loaded from js array or
|
|
1781
1862
|
|
1782
1863
|
// try parse json in single quotes (for double quotes jquery does automatically)
|
1783
1864
|
try {
|
1784
|
-
this.options.source = $.fn.
|
1865
|
+
this.options.source = $.fn.editableutils.tryParseJson(this.options.source, false);
|
1785
1866
|
} catch (e) {
|
1786
1867
|
error.call(this);
|
1787
1868
|
return;
|
@@ -1789,32 +1870,35 @@ List - abstract class for inputs that have source option loaded from js array or
|
|
1789
1870
|
|
1790
1871
|
//loading from url
|
1791
1872
|
if (typeof this.options.source === 'string') {
|
1792
|
-
|
1793
|
-
|
1873
|
+
//try to get from cache
|
1874
|
+
if(this.options.sourceCache) {
|
1875
|
+
var cacheID = this.options.source + (this.options.name ? '-' + this.options.name : ''),
|
1876
|
+
cache;
|
1794
1877
|
|
1795
|
-
|
1796
|
-
|
1797
|
-
|
1798
|
-
|
1878
|
+
if (!$(document).data(cacheID)) {
|
1879
|
+
$(document).data(cacheID, {});
|
1880
|
+
}
|
1881
|
+
cache = $(document).data(cacheID);
|
1799
1882
|
|
1800
|
-
|
1801
|
-
|
1802
|
-
this.sourceData = cache.sourceData;
|
1803
|
-
success.call(this);
|
1804
|
-
return;
|
1805
|
-
} else if (cache.loading === true) { //cache is loading, put callback in stack to be called later
|
1806
|
-
cache.callbacks.push($.proxy(function () {
|
1883
|
+
//check for cached data
|
1884
|
+
if (cache.loading === false && cache.sourceData) { //take source from cache
|
1807
1885
|
this.sourceData = cache.sourceData;
|
1808
1886
|
success.call(this);
|
1809
|
-
|
1887
|
+
return;
|
1888
|
+
} else if (cache.loading === true) { //cache is loading, put callback in stack to be called later
|
1889
|
+
cache.callbacks.push($.proxy(function () {
|
1890
|
+
this.sourceData = cache.sourceData;
|
1891
|
+
success.call(this);
|
1892
|
+
}, this));
|
1810
1893
|
|
1811
|
-
|
1812
|
-
|
1813
|
-
|
1814
|
-
|
1815
|
-
|
1816
|
-
|
1817
|
-
|
1894
|
+
//also collecting error callbacks
|
1895
|
+
cache.err_callbacks.push($.proxy(error, this));
|
1896
|
+
return;
|
1897
|
+
} else { //no cache yet, activate it
|
1898
|
+
cache.loading = true;
|
1899
|
+
cache.callbacks = [];
|
1900
|
+
cache.err_callbacks = [];
|
1901
|
+
}
|
1818
1902
|
}
|
1819
1903
|
|
1820
1904
|
//loading sourceData from server
|
@@ -1825,23 +1909,32 @@ List - abstract class for inputs that have source option loaded from js array or
|
|
1825
1909
|
data: this.options.name ? {name: this.options.name} : {},
|
1826
1910
|
dataType: 'json',
|
1827
1911
|
success: $.proxy(function (data) {
|
1828
|
-
cache
|
1912
|
+
if(cache) {
|
1913
|
+
cache.loading = false;
|
1914
|
+
}
|
1829
1915
|
this.sourceData = this.makeArray(data);
|
1830
1916
|
if($.isArray(this.sourceData)) {
|
1831
1917
|
this.doPrepend();
|
1832
|
-
//store result in cache
|
1833
|
-
cache.sourceData = this.sourceData;
|
1834
1918
|
success.call(this);
|
1835
|
-
|
1919
|
+
if(cache) {
|
1920
|
+
//store result in cache
|
1921
|
+
cache.sourceData = this.sourceData;
|
1922
|
+
$.each(cache.callbacks, function () { this.call(); }); //run success callbacks for other fields
|
1923
|
+
}
|
1836
1924
|
} else {
|
1837
1925
|
error.call(this);
|
1838
|
-
|
1926
|
+
if(cache) {
|
1927
|
+
$.each(cache.err_callbacks, function () { this.call(); }); //run error callbacks for other fields
|
1928
|
+
}
|
1839
1929
|
}
|
1840
1930
|
}, this),
|
1841
1931
|
error: $.proxy(function () {
|
1842
|
-
cache.loading = false;
|
1843
1932
|
error.call(this);
|
1844
|
-
|
1933
|
+
if(cache) {
|
1934
|
+
cache.loading = false;
|
1935
|
+
//run error callbacks for other fields
|
1936
|
+
$.each(cache.err_callbacks, function () { this.call(); });
|
1937
|
+
}
|
1845
1938
|
}, this)
|
1846
1939
|
});
|
1847
1940
|
} else { //options as json/array
|
@@ -1862,7 +1955,7 @@ List - abstract class for inputs that have source option loaded from js array or
|
|
1862
1955
|
|
1863
1956
|
if(!$.isArray(this.prependData)) {
|
1864
1957
|
//try parse json in single quotes
|
1865
|
-
this.options.prepend = $.fn.
|
1958
|
+
this.options.prepend = $.fn.editableutils.tryParseJson(this.options.prepend, true);
|
1866
1959
|
if (typeof this.options.prepend === 'string') {
|
1867
1960
|
this.options.prepend = {'': this.options.prepend};
|
1868
1961
|
}
|
@@ -1943,19 +2036,20 @@ List - abstract class for inputs that have source option loaded from js array or
|
|
1943
2036
|
|
1944
2037
|
});
|
1945
2038
|
|
1946
|
-
List.defaults = $.extend({}, $.fn.
|
2039
|
+
List.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, {
|
1947
2040
|
/**
|
1948
2041
|
Source data for list. If string - considered ajax url to load items. Otherwise should be an array.
|
1949
2042
|
Array format is: <code>[{value: 1, text: "text"}, {...}]</code><br>
|
1950
2043
|
For compability it also supports format <code>{value1: "text1", value2: "text2" ...}</code> but it does not guarantee elements order.
|
1951
|
-
|
2044
|
+
If source is **string**, results will be cached for fields with the same source and name. See also <code>sourceCache</code> option.
|
2045
|
+
|
1952
2046
|
@property source
|
1953
2047
|
@type string|array|object
|
1954
2048
|
@default null
|
1955
2049
|
**/
|
1956
2050
|
source:null,
|
1957
2051
|
/**
|
1958
|
-
Data automatically prepended to the
|
2052
|
+
Data automatically prepended to the beginning of dropdown list.
|
1959
2053
|
|
1960
2054
|
@property prepend
|
1961
2055
|
@type string|array|object
|
@@ -1969,17 +2063,27 @@ List - abstract class for inputs that have source option loaded from js array or
|
|
1969
2063
|
@type string
|
1970
2064
|
@default Error when loading list
|
1971
2065
|
**/
|
1972
|
-
sourceError: 'Error when loading list'
|
2066
|
+
sourceError: 'Error when loading list',
|
2067
|
+
/**
|
2068
|
+
if <code>true</code> and source is **string url** - results will be cached for fields with the same source and name.
|
2069
|
+
Usefull for editable grids.
|
2070
|
+
|
2071
|
+
@property sourceCache
|
2072
|
+
@type boolean
|
2073
|
+
@default true
|
2074
|
+
@since 1.2.0
|
2075
|
+
**/
|
2076
|
+
sourceCache: true
|
1973
2077
|
});
|
1974
2078
|
|
1975
|
-
$.fn.
|
2079
|
+
$.fn.editabletypes.list = List;
|
1976
2080
|
|
1977
2081
|
}(window.jQuery));
|
1978
2082
|
/**
|
1979
2083
|
Text input
|
1980
2084
|
|
1981
2085
|
@class text
|
1982
|
-
@extends
|
2086
|
+
@extends abstractinput
|
1983
2087
|
@final
|
1984
2088
|
@example
|
1985
2089
|
<a href="#" id="username" data-type="text" data-pk="1">awesome</a>
|
@@ -1997,18 +2101,18 @@ $(function(){
|
|
1997
2101
|
this.init('text', options, Text.defaults);
|
1998
2102
|
};
|
1999
2103
|
|
2000
|
-
$.fn.
|
2104
|
+
$.fn.editableutils.inherit(Text, $.fn.editabletypes.abstractinput);
|
2001
2105
|
|
2002
2106
|
$.extend(Text.prototype, {
|
2003
2107
|
activate: function() {
|
2004
2108
|
if(this.$input.is(':visible')) {
|
2005
2109
|
this.$input.focus();
|
2006
|
-
$.fn.
|
2110
|
+
$.fn.editableutils.setCursorPosition(this.$input.get(0), this.$input.val().length);
|
2007
2111
|
}
|
2008
2112
|
}
|
2009
2113
|
});
|
2010
2114
|
|
2011
|
-
Text.defaults = $.extend({}, $.fn.
|
2115
|
+
Text.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, {
|
2012
2116
|
/**
|
2013
2117
|
@property tpl
|
2014
2118
|
@default <input type="text">
|
@@ -2024,7 +2128,7 @@ $(function(){
|
|
2024
2128
|
placeholder: null
|
2025
2129
|
});
|
2026
2130
|
|
2027
|
-
$.fn.
|
2131
|
+
$.fn.editabletypes.text = Text;
|
2028
2132
|
|
2029
2133
|
}(window.jQuery));
|
2030
2134
|
|
@@ -2032,7 +2136,7 @@ $(function(){
|
|
2032
2136
|
Textarea input
|
2033
2137
|
|
2034
2138
|
@class textarea
|
2035
|
-
@extends
|
2139
|
+
@extends abstractinput
|
2036
2140
|
@final
|
2037
2141
|
@example
|
2038
2142
|
<a href="#" id="comments" data-type="textarea" data-pk="1">awesome comment!</a>
|
@@ -2051,7 +2155,7 @@ $(function(){
|
|
2051
2155
|
this.init('textarea', options, Textarea.defaults);
|
2052
2156
|
};
|
2053
2157
|
|
2054
|
-
$.fn.
|
2158
|
+
$.fn.editableutils.inherit(Textarea, $.fn.editabletypes.abstractinput);
|
2055
2159
|
|
2056
2160
|
$.extend(Textarea.prototype, {
|
2057
2161
|
render: function () {
|
@@ -2090,13 +2194,13 @@ $(function(){
|
|
2090
2194
|
|
2091
2195
|
activate: function() {
|
2092
2196
|
if(this.$input.is(':visible')) {
|
2093
|
-
$.fn.
|
2197
|
+
$.fn.editableutils.setCursorPosition(this.$input.get(0), this.$input.val().length);
|
2094
2198
|
this.$input.focus();
|
2095
2199
|
}
|
2096
2200
|
}
|
2097
2201
|
});
|
2098
2202
|
|
2099
|
-
Textarea.defaults = $.extend({}, $.fn.
|
2203
|
+
Textarea.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, {
|
2100
2204
|
/**
|
2101
2205
|
@property tpl
|
2102
2206
|
@default <textarea></textarea>
|
@@ -2104,9 +2208,9 @@ $(function(){
|
|
2104
2208
|
tpl:'<textarea></textarea>',
|
2105
2209
|
/**
|
2106
2210
|
@property inputclass
|
2107
|
-
@default
|
2211
|
+
@default input-large
|
2108
2212
|
**/
|
2109
|
-
inputclass:'
|
2213
|
+
inputclass: 'input-large',
|
2110
2214
|
/**
|
2111
2215
|
Placeholder attribute of input. Shown when input is empty.
|
2112
2216
|
|
@@ -2114,12 +2218,13 @@ $(function(){
|
|
2114
2218
|
@type string
|
2115
2219
|
@default null
|
2116
2220
|
**/
|
2117
|
-
placeholder: null
|
2221
|
+
placeholder: null
|
2118
2222
|
});
|
2119
2223
|
|
2120
|
-
$.fn.
|
2224
|
+
$.fn.editabletypes.textarea = Textarea;
|
2121
2225
|
|
2122
|
-
}(window.jQuery));
|
2226
|
+
}(window.jQuery));
|
2227
|
+
|
2123
2228
|
/**
|
2124
2229
|
Select (dropdown)
|
2125
2230
|
|
@@ -2148,7 +2253,7 @@ $(function(){
|
|
2148
2253
|
this.init('select', options, Select.defaults);
|
2149
2254
|
};
|
2150
2255
|
|
2151
|
-
$.fn.
|
2256
|
+
$.fn.editableutils.inherit(Select, $.fn.editabletypes.list);
|
2152
2257
|
|
2153
2258
|
$.extend(Select.prototype, {
|
2154
2259
|
renderList: function() {
|
@@ -2159,6 +2264,13 @@ $(function(){
|
|
2159
2264
|
for(var i=0; i<this.sourceData.length; i++) {
|
2160
2265
|
this.$input.append($('<option>', {value: this.sourceData[i].value}).text(this.sourceData[i].text));
|
2161
2266
|
}
|
2267
|
+
|
2268
|
+
//enter submit
|
2269
|
+
this.$input.on('keydown.editable', function (e) {
|
2270
|
+
if (e.which === 13) {
|
2271
|
+
$(this).closest('form').submit();
|
2272
|
+
}
|
2273
|
+
});
|
2162
2274
|
},
|
2163
2275
|
|
2164
2276
|
value2htmlFinal: function(value, element) {
|
@@ -2170,13 +2282,13 @@ $(function(){
|
|
2170
2282
|
},
|
2171
2283
|
|
2172
2284
|
autosubmit: function() {
|
2173
|
-
this.$input.on('change', function(){
|
2285
|
+
this.$input.off('keydown.editable').on('change.editable', function(){
|
2174
2286
|
$(this).closest('form').submit();
|
2175
2287
|
});
|
2176
2288
|
}
|
2177
2289
|
});
|
2178
2290
|
|
2179
|
-
Select.defaults = $.extend({}, $.fn.
|
2291
|
+
Select.defaults = $.extend({}, $.fn.editabletypes.list.defaults, {
|
2180
2292
|
/**
|
2181
2293
|
@property tpl
|
2182
2294
|
@default <select></select>
|
@@ -2184,7 +2296,7 @@ $(function(){
|
|
2184
2296
|
tpl:'<select></select>'
|
2185
2297
|
});
|
2186
2298
|
|
2187
|
-
$.fn.
|
2299
|
+
$.fn.editabletypes.select = Select;
|
2188
2300
|
|
2189
2301
|
}(window.jQuery));
|
2190
2302
|
/**
|
@@ -2216,7 +2328,7 @@ $(function(){
|
|
2216
2328
|
this.init('checklist', options, Checklist.defaults);
|
2217
2329
|
};
|
2218
2330
|
|
2219
|
-
$.fn.
|
2331
|
+
$.fn.editableutils.inherit(Checklist, $.fn.editabletypes.list);
|
2220
2332
|
|
2221
2333
|
$.extend(Checklist.prototype, {
|
2222
2334
|
renderList: function() {
|
@@ -2238,10 +2350,8 @@ $(function(){
|
|
2238
2350
|
},
|
2239
2351
|
|
2240
2352
|
value2str: function(value) {
|
2241
|
-
return $.isArray(value) ? value.join($.trim(this.options.separator)) : '';
|
2242
|
-
|
2243
|
-
//return value;
|
2244
|
-
},
|
2353
|
+
return $.isArray(value) ? value.sort().join($.trim(this.options.separator)) : '';
|
2354
|
+
},
|
2245
2355
|
|
2246
2356
|
//parse separated string
|
2247
2357
|
str2value: function(str) {
|
@@ -2284,19 +2394,18 @@ $(function(){
|
|
2284
2394
|
|
2285
2395
|
//collect text of checked boxes
|
2286
2396
|
value2htmlFinal: function(value, element) {
|
2287
|
-
var
|
2288
|
-
|
2289
|
-
|
2290
|
-
|
2291
|
-
|
2292
|
-
|
2293
|
-
|
2294
|
-
}
|
2295
|
-
html
|
2296
|
-
} else {
|
2297
|
-
|
2397
|
+
var html = [],
|
2398
|
+
/*jslint eqeq: true*/
|
2399
|
+
checked = $.grep(this.sourceData, function(o){
|
2400
|
+
return $.grep(value, function(v){ return v == o.value; }).length;
|
2401
|
+
});
|
2402
|
+
/*jslint eqeq: false*/
|
2403
|
+
if(checked.length) {
|
2404
|
+
$.each(checked, function(i, v) { html.push($.fn.editableutils.escape(v.text)); });
|
2405
|
+
$(element).html(html.join('<br>'));
|
2406
|
+
} else {
|
2407
|
+
$(element).empty();
|
2298
2408
|
}
|
2299
|
-
$(element).html(html);
|
2300
2409
|
},
|
2301
2410
|
|
2302
2411
|
activate: function() {
|
@@ -2312,7 +2421,7 @@ $(function(){
|
|
2312
2421
|
}
|
2313
2422
|
});
|
2314
2423
|
|
2315
|
-
Checklist.defaults = $.extend({}, $.fn.
|
2424
|
+
Checklist.defaults = $.extend({}, $.fn.editabletypes.list.defaults, {
|
2316
2425
|
/**
|
2317
2426
|
@property tpl
|
2318
2427
|
@default <div></div>
|
@@ -2322,50 +2431,212 @@ $(function(){
|
|
2322
2431
|
/**
|
2323
2432
|
@property inputclass
|
2324
2433
|
@type string
|
2325
|
-
@default
|
2434
|
+
@default editable-checklist
|
2326
2435
|
**/
|
2327
|
-
inputclass: '
|
2436
|
+
inputclass: 'editable-checklist',
|
2328
2437
|
|
2329
2438
|
/**
|
2330
|
-
Separator of values
|
2439
|
+
Separator of values when reading from 'data-value' string
|
2331
2440
|
|
2332
2441
|
@property separator
|
2333
2442
|
@type string
|
2334
2443
|
@default ', '
|
2335
2444
|
**/
|
2336
|
-
separator: ','
|
2337
|
-
|
2338
|
-
Separator of text when display as element content.
|
2445
|
+
separator: ','
|
2446
|
+
});
|
2339
2447
|
|
2340
|
-
|
2341
|
-
@type string
|
2342
|
-
@default '<br>'
|
2343
|
-
**/
|
2344
|
-
viewseparator: '<br>',
|
2345
|
-
/**
|
2346
|
-
Maximum number of items shown as element content.
|
2347
|
-
If checked more items - <code>limitText</code> will be shown.
|
2448
|
+
$.fn.editabletypes.checklist = Checklist;
|
2348
2449
|
|
2349
|
-
|
2350
|
-
|
2351
|
-
|
2352
|
-
|
2353
|
-
|
2354
|
-
|
2355
|
-
|
2356
|
-
|
2450
|
+
}(window.jQuery));
|
2451
|
+
|
2452
|
+
/**
|
2453
|
+
HTML5 input types.
|
2454
|
+
Following types are supported:
|
2455
|
+
|
2456
|
+
* password
|
2457
|
+
* email
|
2458
|
+
* url
|
2459
|
+
* tel
|
2460
|
+
* number
|
2461
|
+
* range
|
2462
|
+
|
2463
|
+
Learn more about html5 inputs:
|
2464
|
+
http://www.w3.org/wiki/HTML5_form_additions
|
2465
|
+
To check browser compatibility please see:
|
2466
|
+
https://developer.mozilla.org/en-US/docs/HTML/Element/Input
|
2467
|
+
|
2468
|
+
@class html5types
|
2469
|
+
@extends text
|
2470
|
+
@final
|
2471
|
+
@since 1.3.0
|
2472
|
+
@example
|
2473
|
+
<a href="#" id="email" data-type="email" data-pk="1">admin@example.com</a>
|
2474
|
+
<script>
|
2475
|
+
$(function(){
|
2476
|
+
$('#email').editable({
|
2477
|
+
url: '/post',
|
2478
|
+
title: 'Enter email'
|
2479
|
+
});
|
2480
|
+
});
|
2481
|
+
</script>
|
2482
|
+
**/
|
2357
2483
|
|
2358
|
-
|
2359
|
-
|
2360
|
-
|
2361
|
-
|
2362
|
-
|
2484
|
+
/**
|
2485
|
+
@property tpl
|
2486
|
+
@default depends on type
|
2487
|
+
**/
|
2488
|
+
|
2489
|
+
/*
|
2490
|
+
Password
|
2491
|
+
*/
|
2492
|
+
(function ($) {
|
2493
|
+
var Password = function (options) {
|
2494
|
+
this.init('password', options, Password.defaults);
|
2495
|
+
};
|
2496
|
+
$.fn.editableutils.inherit(Password, $.fn.editabletypes.text);
|
2497
|
+
$.extend(Password.prototype, {
|
2498
|
+
//do not display password, show '[hidden]' instead
|
2499
|
+
value2html: function(value, element) {
|
2500
|
+
if(value) {
|
2501
|
+
$(element).text('[hidden]');
|
2502
|
+
} else {
|
2503
|
+
$(element).empty();
|
2504
|
+
}
|
2505
|
+
},
|
2506
|
+
//as password not displayed, should not set value by html
|
2507
|
+
html2value: function(html) {
|
2508
|
+
return null;
|
2509
|
+
}
|
2510
|
+
});
|
2511
|
+
Password.defaults = $.extend({}, $.fn.editabletypes.text.defaults, {
|
2512
|
+
tpl: '<input type="password">'
|
2363
2513
|
});
|
2514
|
+
$.fn.editabletypes.password = Password;
|
2515
|
+
}(window.jQuery));
|
2364
2516
|
|
2365
|
-
$.fn.editableform.types.checklist = Checklist;
|
2366
2517
|
|
2518
|
+
/*
|
2519
|
+
Email
|
2520
|
+
*/
|
2521
|
+
(function ($) {
|
2522
|
+
var Email = function (options) {
|
2523
|
+
this.init('email', options, Email.defaults);
|
2524
|
+
};
|
2525
|
+
$.fn.editableutils.inherit(Email, $.fn.editabletypes.text);
|
2526
|
+
Email.defaults = $.extend({}, $.fn.editabletypes.text.defaults, {
|
2527
|
+
tpl: '<input type="email">'
|
2528
|
+
});
|
2529
|
+
$.fn.editabletypes.email = Email;
|
2367
2530
|
}(window.jQuery));
|
2368
|
-
|
2531
|
+
|
2532
|
+
|
2533
|
+
/*
|
2534
|
+
Url
|
2535
|
+
*/
|
2536
|
+
(function ($) {
|
2537
|
+
var Url = function (options) {
|
2538
|
+
this.init('url', options, Url.defaults);
|
2539
|
+
};
|
2540
|
+
$.fn.editableutils.inherit(Url, $.fn.editabletypes.text);
|
2541
|
+
Url.defaults = $.extend({}, $.fn.editabletypes.text.defaults, {
|
2542
|
+
tpl: '<input type="url">'
|
2543
|
+
});
|
2544
|
+
$.fn.editabletypes.url = Url;
|
2545
|
+
}(window.jQuery));
|
2546
|
+
|
2547
|
+
|
2548
|
+
/*
|
2549
|
+
Tel
|
2550
|
+
*/
|
2551
|
+
(function ($) {
|
2552
|
+
var Tel = function (options) {
|
2553
|
+
this.init('tel', options, Tel.defaults);
|
2554
|
+
};
|
2555
|
+
$.fn.editableutils.inherit(Tel, $.fn.editabletypes.text);
|
2556
|
+
Tel.defaults = $.extend({}, $.fn.editabletypes.text.defaults, {
|
2557
|
+
tpl: '<input type="tel">'
|
2558
|
+
});
|
2559
|
+
$.fn.editabletypes.tel = Tel;
|
2560
|
+
}(window.jQuery));
|
2561
|
+
|
2562
|
+
|
2563
|
+
/*
|
2564
|
+
Number
|
2565
|
+
*/
|
2566
|
+
(function ($) {
|
2567
|
+
var NumberInput = function (options) {
|
2568
|
+
this.init('number', options, NumberInput.defaults);
|
2569
|
+
};
|
2570
|
+
$.fn.editableutils.inherit(NumberInput, $.fn.editabletypes.text);
|
2571
|
+
$.extend(NumberInput.prototype, {
|
2572
|
+
render: function () {
|
2573
|
+
NumberInput.superclass.render.call(this);
|
2574
|
+
|
2575
|
+
if (this.options.min !== null) {
|
2576
|
+
this.$input.attr('min', this.options.min);
|
2577
|
+
}
|
2578
|
+
|
2579
|
+
if (this.options.max !== null) {
|
2580
|
+
this.$input.attr('max', this.options.max);
|
2581
|
+
}
|
2582
|
+
|
2583
|
+
if (this.options.step !== null) {
|
2584
|
+
this.$input.attr('step', this.options.step);
|
2585
|
+
}
|
2586
|
+
}
|
2587
|
+
});
|
2588
|
+
NumberInput.defaults = $.extend({}, $.fn.editabletypes.text.defaults, {
|
2589
|
+
tpl: '<input type="number">',
|
2590
|
+
inputclass: 'input-mini',
|
2591
|
+
min: null,
|
2592
|
+
max: null,
|
2593
|
+
step: null
|
2594
|
+
});
|
2595
|
+
$.fn.editabletypes.number = NumberInput;
|
2596
|
+
}(window.jQuery));
|
2597
|
+
|
2598
|
+
|
2599
|
+
/*
|
2600
|
+
Range (inherit from number)
|
2601
|
+
*/
|
2602
|
+
(function ($) {
|
2603
|
+
var Range = function (options) {
|
2604
|
+
this.init('range', options, Range.defaults);
|
2605
|
+
};
|
2606
|
+
$.fn.editableutils.inherit(Range, $.fn.editabletypes.number);
|
2607
|
+
$.extend(Range.prototype, {
|
2608
|
+
render: function () {
|
2609
|
+
this.$input = $(this.options.tpl);
|
2610
|
+
var $slider = this.$input.filter('input');
|
2611
|
+
if(this.options.inputclass) {
|
2612
|
+
$slider.addClass(this.options.inputclass);
|
2613
|
+
}
|
2614
|
+
if (this.options.min !== null) {
|
2615
|
+
$slider.attr('min', this.options.min);
|
2616
|
+
}
|
2617
|
+
|
2618
|
+
if (this.options.max !== null) {
|
2619
|
+
$slider.attr('max', this.options.max);
|
2620
|
+
}
|
2621
|
+
|
2622
|
+
if (this.options.step !== null) {
|
2623
|
+
$slider.attr('step', this.options.step);
|
2624
|
+
}
|
2625
|
+
|
2626
|
+
$slider.on('input', function(){
|
2627
|
+
$(this).siblings('output').text($(this).val());
|
2628
|
+
});
|
2629
|
+
},
|
2630
|
+
activate: function() {
|
2631
|
+
this.$input.filter('input').focus();
|
2632
|
+
}
|
2633
|
+
});
|
2634
|
+
Range.defaults = $.extend({}, $.fn.editabletypes.number.defaults, {
|
2635
|
+
tpl: '<input type="range"><output style="width: 30px; display: inline-block"></output>',
|
2636
|
+
inputclass: 'input-medium'
|
2637
|
+
});
|
2638
|
+
$.fn.editabletypes.range = Range;
|
2639
|
+
}(window.jQuery));
|
2369
2640
|
/*
|
2370
2641
|
Editableform based on Twitter Bootstrap
|
2371
2642
|
*/
|
@@ -2432,10 +2703,6 @@ Editableform based on Twitter Bootstrap
|
|
2432
2703
|
innerHide: function () {
|
2433
2704
|
this.$form.hide(this.options.anim, $.proxy(function() {
|
2434
2705
|
this.$element.show();
|
2435
|
-
//return focus on element
|
2436
|
-
if (this.options.enablefocus) {
|
2437
|
-
this.$element.focus();
|
2438
|
-
}
|
2439
2706
|
}, this));
|
2440
2707
|
},
|
2441
2708
|
|
@@ -2446,8 +2713,7 @@ Editableform based on Twitter Bootstrap
|
|
2446
2713
|
|
2447
2714
|
//defaults
|
2448
2715
|
$.fn.editableContainer.defaults = $.extend({}, $.fn.editableContainer.defaults, {
|
2449
|
-
anim: 'fast'
|
2450
|
-
enablefocus: false
|
2716
|
+
anim: 'fast'
|
2451
2717
|
});
|
2452
2718
|
|
2453
2719
|
|
@@ -2458,7 +2724,7 @@ Description and examples: http://vitalets.github.com/bootstrap-datepicker.
|
|
2458
2724
|
For localization you can include js file from here: https://github.com/eternicode/bootstrap-datepicker/tree/master/js/locales
|
2459
2725
|
|
2460
2726
|
@class date
|
2461
|
-
@extends
|
2727
|
+
@extends abstractinput
|
2462
2728
|
@final
|
2463
2729
|
@example
|
2464
2730
|
<a href="#" id="dob" data-type="date" data-pk="1" data-url="/post" data-original-title="Select date">15/05/1984</a>
|
@@ -2481,7 +2747,7 @@ $(function(){
|
|
2481
2747
|
this.init('date', options, Date.defaults);
|
2482
2748
|
|
2483
2749
|
//set popular options directly from settings or data-* attributes
|
2484
|
-
var directOptions = $.fn.
|
2750
|
+
var directOptions = $.fn.editableutils.sliceObj(this.options, ['format']);
|
2485
2751
|
|
2486
2752
|
//overriding datepicker config (as by default jQuery extend() is not recursive)
|
2487
2753
|
this.options.datepicker = $.extend({}, Date.defaults.datepicker, directOptions, options.datepicker);
|
@@ -2502,7 +2768,7 @@ $(function(){
|
|
2502
2768
|
this.parsedViewFormat = this.dpg.parseFormat(this.options.viewformat);
|
2503
2769
|
};
|
2504
2770
|
|
2505
|
-
$.fn.
|
2771
|
+
$.fn.editableutils.inherit(Date, $.fn.editabletypes.abstractinput);
|
2506
2772
|
|
2507
2773
|
$.extend(Date.prototype, {
|
2508
2774
|
render: function () {
|
@@ -2533,7 +2799,11 @@ $(function(){
|
|
2533
2799
|
|
2534
2800
|
str2value: function(str) {
|
2535
2801
|
return str ? this.dpg.parseDate(str, this.parsedFormat, this.options.datepicker.language) : null;
|
2536
|
-
},
|
2802
|
+
},
|
2803
|
+
|
2804
|
+
value2submit: function(value) {
|
2805
|
+
return this.value2str(value);
|
2806
|
+
},
|
2537
2807
|
|
2538
2808
|
value2input: function(value) {
|
2539
2809
|
this.$input.datepicker('update', value);
|
@@ -2562,7 +2832,7 @@ $(function(){
|
|
2562
2832
|
|
2563
2833
|
});
|
2564
2834
|
|
2565
|
-
Date.defaults = $.extend({}, $.fn.
|
2835
|
+
Date.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, {
|
2566
2836
|
/**
|
2567
2837
|
@property tpl
|
2568
2838
|
@default <div></div>
|
@@ -2619,7 +2889,7 @@ $(function(){
|
|
2619
2889
|
clear: '× clear'
|
2620
2890
|
});
|
2621
2891
|
|
2622
|
-
$.fn.
|
2892
|
+
$.fn.editabletypes.date = Date;
|
2623
2893
|
|
2624
2894
|
}(window.jQuery));
|
2625
2895
|
|
@@ -2911,13 +3181,13 @@ $(function(){
|
|
2911
3181
|
startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
|
2912
3182
|
endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
|
2913
3183
|
endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
|
2914
|
-
currentDate = this.date.valueOf(),
|
3184
|
+
currentDate = this.date && this.date.valueOf(),
|
2915
3185
|
today = new Date();
|
2916
3186
|
this.picker.find('.datepicker-days thead th:eq(1)')
|
2917
3187
|
.text(dates[this.language].months[month]+' '+year);
|
2918
3188
|
this.picker.find('tfoot th.today')
|
2919
3189
|
.text(dates[this.language].today)
|
2920
|
-
.toggle(this.todayBtn);
|
3190
|
+
.toggle(this.todayBtn !== false);
|
2921
3191
|
this.updateNavArrows();
|
2922
3192
|
this.fillMonths();
|
2923
3193
|
var prevMonth = UTCDate(year, month-1, 28,0,0,0,0),
|
@@ -2946,7 +3216,7 @@ $(function(){
|
|
2946
3216
|
prevMonth.getUTCDate() == today.getDate()) {
|
2947
3217
|
clsName += ' today';
|
2948
3218
|
}
|
2949
|
-
if (prevMonth.valueOf() == currentDate) {
|
3219
|
+
if (currentDate && prevMonth.valueOf() == currentDate) {
|
2950
3220
|
clsName += ' active';
|
2951
3221
|
}
|
2952
3222
|
if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate) {
|
@@ -2959,14 +3229,14 @@ $(function(){
|
|
2959
3229
|
prevMonth.setUTCDate(prevMonth.getUTCDate()+1);
|
2960
3230
|
}
|
2961
3231
|
this.picker.find('.datepicker-days tbody').empty().append(html.join(''));
|
2962
|
-
var currentYear = this.date.getUTCFullYear();
|
3232
|
+
var currentYear = this.date && this.date.getUTCFullYear();
|
2963
3233
|
|
2964
3234
|
var months = this.picker.find('.datepicker-months')
|
2965
3235
|
.find('th:eq(1)')
|
2966
3236
|
.text(year)
|
2967
3237
|
.end()
|
2968
3238
|
.find('span').removeClass('active');
|
2969
|
-
if (currentYear == year) {
|
3239
|
+
if (currentYear && currentYear == year) {
|
2970
3240
|
months.eq(this.date.getUTCMonth()).addClass('active');
|
2971
3241
|
}
|
2972
3242
|
if (year < startYear || year > endYear) {
|
@@ -3054,10 +3324,7 @@ $(function(){
|
|
3054
3324
|
break;
|
3055
3325
|
case 'today':
|
3056
3326
|
var date = new Date();
|
3057
|
-
date.
|
3058
|
-
date.setUTCMinutes(0);
|
3059
|
-
date.setUTCSeconds(0);
|
3060
|
-
date.setUTCMilliseconds(0);
|
3327
|
+
date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
|
3061
3328
|
|
3062
3329
|
this.showMode(-2);
|
3063
3330
|
var which = this.todayBtn == 'linked' ? null : 'view';
|
@@ -3280,7 +3547,17 @@ $(function(){
|
|
3280
3547
|
if (dir) {
|
3281
3548
|
this.viewMode = Math.max(0, Math.min(2, this.viewMode + dir));
|
3282
3549
|
}
|
3283
|
-
|
3550
|
+
/*
|
3551
|
+
vitalets: fixing bug of very special conditions:
|
3552
|
+
jquery 1.7.1 + webkit + show inline datepicker in bootstrap popover.
|
3553
|
+
Method show() does not set display css correctly and datepicker is not shown.
|
3554
|
+
Changed to .css('display', 'block') solve the problem.
|
3555
|
+
See https://github.com/vitalets/x-editable/issues/37
|
3556
|
+
|
3557
|
+
In jquery 1.7.2+ everything works fine.
|
3558
|
+
*/
|
3559
|
+
//this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).show();
|
3560
|
+
this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).css('display', 'block');
|
3284
3561
|
this.updateNavArrows();
|
3285
3562
|
}
|
3286
3563
|
};
|
@@ -3398,7 +3675,7 @@ $(function(){
|
|
3398
3675
|
val, filtered, part;
|
3399
3676
|
setters_map['M'] = setters_map['MM'] = setters_map['mm'] = setters_map['m'];
|
3400
3677
|
setters_map['dd'] = setters_map['d'];
|
3401
|
-
date = UTCDate(date.
|
3678
|
+
date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
|
3402
3679
|
if (parts.length == format.parts.length) {
|
3403
3680
|
for (var i=0, cnt = format.parts.length; i < cnt; i++) {
|
3404
3681
|
val = parseInt(parts[i], 10);
|