x-editable-rails 0.0.3 → 1.0.0
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 +7 -0
- data/LICENSE.txt +1 -1
- data/README.md +31 -14
- data/lib/x-editable-rails.rb +5 -1
- data/lib/x-editable-rails/version.rb +1 -1
- data/lib/x-editable-rails/view_helpers.rb +20 -0
- data/vendor/assets/images/editable/clear.png +0 -0
- data/vendor/assets/images/{loading.gif → editable/loading.gif} +0 -0
- data/vendor/assets/javascripts/{bootstrap-editable.js → editable/bootstrap-editable.js} +3816 -1425
- data/vendor/assets/javascripts/{jquery-editable-poshytip.js → editable/jquery-editable-poshytip.js} +2171 -541
- data/vendor/assets/javascripts/{jqueryui-editable.js → editable/jqueryui-editable.js} +2080 -478
- data/vendor/assets/javascripts/{rails-editable.js.coffee → editable/rails.js.coffee} +3 -0
- data/vendor/assets/stylesheets/editable/bootstrap-editable.css +495 -0
- data/vendor/assets/stylesheets/{jquery-editable.css → editable/jquery-editable.css} +63 -18
- data/vendor/assets/stylesheets/{jqueryui-editable.css → editable/jqueryui-editable.css} +63 -18
- metadata +79 -66
- data/.gitignore +0 -19
- data/Gemfile +0 -4
- data/Rakefile +0 -1
- data/vendor/assets/javascripts/bootstrap-editable-inline.js +0 -3769
- data/vendor/assets/javascripts/bootstrap-editable-inline.min.js +0 -5
- data/vendor/assets/javascripts/bootstrap-editable.min.js +0 -5
- data/vendor/assets/javascripts/jquery-editable-inline.js +0 -2892
- data/vendor/assets/javascripts/jquery-editable-inline.min.js +0 -5
- data/vendor/assets/javascripts/jquery-editable-poshytip.min.js +0 -5
- data/vendor/assets/javascripts/jqueryui-editable-inline.js +0 -2916
- data/vendor/assets/javascripts/jqueryui-editable-inline.min.js +0 -5
- data/vendor/assets/javascripts/jqueryui-editable.min.js +0 -5
- data/vendor/assets/stylesheets/bootstrap-editable.css +0 -434
- data/x-editable-rails.gemspec +0 -19
data/vendor/assets/javascripts/{jquery-editable-poshytip.js → editable/jquery-editable-poshytip.js}
RENAMED
@@ -1,7 +1,7 @@
|
|
1
|
-
/*! X-editable - v1.
|
1
|
+
/*! X-editable - v1.4.4
|
2
2
|
* In-place editing with Twitter Bootstrap, jQuery UI or pure jQuery
|
3
3
|
* http://github.com/vitalets/x-editable
|
4
|
-
* Copyright (c)
|
4
|
+
* Copyright (c) 2013 Vitaliy Potapov; Licensed MIT */
|
5
5
|
|
6
6
|
/**
|
7
7
|
Form with single input element, two buttons and two states: normal/loading.
|
@@ -13,38 +13,36 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
|
|
13
13
|
@uses textarea
|
14
14
|
**/
|
15
15
|
(function ($) {
|
16
|
-
|
16
|
+
"use strict";
|
17
|
+
|
17
18
|
var EditableForm = function (div, options) {
|
18
19
|
this.options = $.extend({}, $.fn.editableform.defaults, options);
|
19
|
-
this.$div = $(div); //div, containing form. Not form tag
|
20
|
+
this.$div = $(div); //div, containing form. Not form tag. Not editable-element.
|
20
21
|
if(!this.options.scope) {
|
21
22
|
this.options.scope = this;
|
22
23
|
}
|
23
|
-
|
24
|
+
//nothing shown after init
|
24
25
|
};
|
25
26
|
|
26
27
|
EditableForm.prototype = {
|
27
28
|
constructor: EditableForm,
|
28
29
|
initInput: function() { //called once
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
typeOptions = $.fn.editableutils.sliceObj(this.options, $.fn.editableutils.objectKeys(TypeConstructor.defaults));
|
35
|
-
this.input = new TypeConstructor(typeOptions);
|
36
|
-
} else {
|
37
|
-
$.error('Unknown type: '+ this.options.type);
|
38
|
-
return;
|
39
|
-
}
|
40
|
-
|
30
|
+
//take input from options (as it is created in editable-element)
|
31
|
+
this.input = this.options.input;
|
32
|
+
|
33
|
+
//set initial value
|
34
|
+
//todo: may be add check: typeof str === 'string' ?
|
41
35
|
this.value = this.input.str2value(this.options.value);
|
42
36
|
},
|
43
37
|
initTemplate: function() {
|
44
38
|
this.$form = $($.fn.editableform.template);
|
45
39
|
},
|
46
40
|
initButtons: function() {
|
47
|
-
this.$form.find('.editable-buttons')
|
41
|
+
var $btn = this.$form.find('.editable-buttons');
|
42
|
+
$btn.append($.fn.editableform.buttons);
|
43
|
+
if(this.options.showbuttons === 'bottom') {
|
44
|
+
$btn.addClass('editable-buttons-bottom');
|
45
|
+
}
|
48
46
|
},
|
49
47
|
/**
|
50
48
|
Renders editableform
|
@@ -52,47 +50,49 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
|
|
52
50
|
@method render
|
53
51
|
**/
|
54
52
|
render: function() {
|
53
|
+
//init loader
|
55
54
|
this.$loading = $($.fn.editableform.loading);
|
56
55
|
this.$div.empty().append(this.$loading);
|
57
|
-
this.showLoading();
|
58
56
|
|
59
57
|
//init form template and buttons
|
60
|
-
this.initTemplate();
|
58
|
+
this.initTemplate();
|
61
59
|
if(this.options.showbuttons) {
|
62
60
|
this.initButtons();
|
63
61
|
} else {
|
64
62
|
this.$form.find('.editable-buttons').remove();
|
65
63
|
}
|
66
64
|
|
65
|
+
//show loading state
|
66
|
+
this.showLoading();
|
67
|
+
|
67
68
|
/**
|
68
69
|
Fired when rendering starts
|
69
70
|
@event rendering
|
70
71
|
@param {Object} event event object
|
71
72
|
**/
|
72
73
|
this.$div.triggerHandler('rendering');
|
74
|
+
|
75
|
+
//init input
|
76
|
+
this.initInput();
|
77
|
+
|
78
|
+
//append input to form
|
79
|
+
this.input.prerender();
|
80
|
+
this.$form.find('div.editable-input').append(this.input.$tpl);
|
73
81
|
|
82
|
+
//append form to container
|
83
|
+
this.$div.append(this.$form);
|
84
|
+
|
74
85
|
//render input
|
75
86
|
$.when(this.input.render())
|
76
87
|
.then($.proxy(function () {
|
77
|
-
//input
|
78
|
-
this.$form.find('div.editable-input').append(this.input.$input);
|
79
|
-
|
80
|
-
//automatically submit inputs when no buttons shown
|
88
|
+
//setup input to submit automatically when no buttons shown
|
81
89
|
if(!this.options.showbuttons) {
|
82
90
|
this.input.autosubmit();
|
83
91
|
}
|
84
|
-
|
85
|
-
//"clear" link
|
86
|
-
if(this.input.$clear) {
|
87
|
-
this.$form.find('div.editable-input').append($('<div class="editable-clear">').append(this.input.$clear));
|
88
|
-
}
|
89
|
-
|
90
|
-
//append form to container
|
91
|
-
this.$div.append(this.$form);
|
92
92
|
|
93
93
|
//attach 'cancel' handler
|
94
94
|
this.$form.find('.editable-cancel').click($.proxy(this.cancel, this));
|
95
|
-
|
95
|
+
|
96
96
|
if(this.input.error) {
|
97
97
|
this.error(this.input.error);
|
98
98
|
this.$form.find('.editable-submit').attr('disabled', true);
|
@@ -116,6 +116,11 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
|
|
116
116
|
this.$div.triggerHandler('rendered');
|
117
117
|
|
118
118
|
this.showForm();
|
119
|
+
|
120
|
+
//call postrender method to perform actions required visibility of form
|
121
|
+
if(this.input.postrender) {
|
122
|
+
this.input.postrender();
|
123
|
+
}
|
119
124
|
}, this));
|
120
125
|
},
|
121
126
|
cancel: function() {
|
@@ -127,11 +132,17 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
|
|
127
132
|
this.$div.triggerHandler('cancel');
|
128
133
|
},
|
129
134
|
showLoading: function() {
|
130
|
-
var w;
|
135
|
+
var w, h;
|
131
136
|
if(this.$form) {
|
132
|
-
//set loading size equal to form
|
133
|
-
this.$
|
134
|
-
this.$
|
137
|
+
//set loading size equal to form
|
138
|
+
w = this.$form.outerWidth();
|
139
|
+
h = this.$form.outerHeight();
|
140
|
+
if(w) {
|
141
|
+
this.$loading.width(w);
|
142
|
+
}
|
143
|
+
if(h) {
|
144
|
+
this.$loading.height(h);
|
145
|
+
}
|
135
146
|
this.$form.hide();
|
136
147
|
} else {
|
137
148
|
//stretch loading to fill container width
|
@@ -159,14 +170,23 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
|
|
159
170
|
|
160
171
|
error: function(msg) {
|
161
172
|
var $group = this.$form.find('.control-group'),
|
162
|
-
|
173
|
+
$block = this.$form.find('.editable-error-block'),
|
174
|
+
lines;
|
163
175
|
|
164
176
|
if(msg === false) {
|
165
177
|
$group.removeClass($.fn.editableform.errorGroupClass);
|
166
178
|
$block.removeClass($.fn.editableform.errorBlockClass).empty().hide();
|
167
179
|
} else {
|
180
|
+
//convert newline to <br> for more pretty error display
|
181
|
+
if(msg) {
|
182
|
+
lines = msg.split("\n");
|
183
|
+
for (var i = 0; i < lines.length; i++) {
|
184
|
+
lines[i] = $('<div>').text(lines[i]).html();
|
185
|
+
}
|
186
|
+
msg = lines.join('<br>');
|
187
|
+
}
|
168
188
|
$group.addClass($.fn.editableform.errorGroupClass);
|
169
|
-
$block.addClass($.fn.editableform.errorBlockClass).
|
189
|
+
$block.addClass($.fn.editableform.errorBlockClass).html(msg).show();
|
170
190
|
}
|
171
191
|
},
|
172
192
|
|
@@ -218,6 +238,7 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
|
|
218
238
|
}
|
219
239
|
|
220
240
|
//if success callback returns object like {newValue: <something>} --> use that value instead of submitted
|
241
|
+
//it is usefull if you want to chnage value in url-function
|
221
242
|
if(res && typeof res === 'object' && res.hasOwnProperty('newValue')) {
|
222
243
|
newValue = res.newValue;
|
223
244
|
}
|
@@ -241,8 +262,15 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
|
|
241
262
|
this.$div.triggerHandler('save', {newValue: newValue, response: response});
|
242
263
|
}, this))
|
243
264
|
.fail($.proxy(function(xhr) {
|
244
|
-
|
245
|
-
this.
|
265
|
+
var msg;
|
266
|
+
if(typeof this.options.error === 'function') {
|
267
|
+
msg = this.options.error.call(this.options.scope, xhr, newValue);
|
268
|
+
} else {
|
269
|
+
msg = typeof xhr === 'string' ? xhr : xhr.responseText || xhr.statusText || 'Unknown error!';
|
270
|
+
}
|
271
|
+
|
272
|
+
this.error(msg);
|
273
|
+
this.showForm();
|
246
274
|
}, this));
|
247
275
|
},
|
248
276
|
|
@@ -254,7 +282,7 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
|
|
254
282
|
this.options.pk = $.fn.editableutils.tryParseJson(this.options.pk, true);
|
255
283
|
|
256
284
|
var pk = (typeof this.options.pk === 'function') ? this.options.pk.call(this.options.scope) : this.options.pk,
|
257
|
-
send = !!(typeof this.options.url === 'function' || (this.options.url && ((this.options.send === 'always') || (this.options.send === 'auto' && pk)))),
|
285
|
+
send = !!(typeof this.options.url === 'function' || (this.options.url && ((this.options.send === 'always') || (this.options.send === 'auto' && pk !== null && pk !== undefined)))),
|
258
286
|
params;
|
259
287
|
|
260
288
|
if (send) { //send to server
|
@@ -299,10 +327,15 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
|
|
299
327
|
},
|
300
328
|
|
301
329
|
option: function(key, value) {
|
302
|
-
this.options
|
330
|
+
if(key in this.options) {
|
331
|
+
this.options[key] = value;
|
332
|
+
}
|
333
|
+
|
303
334
|
if(key === 'value') {
|
304
335
|
this.setValue(value);
|
305
336
|
}
|
337
|
+
|
338
|
+
//do not pass option to input as it is passed in editable-element
|
306
339
|
},
|
307
340
|
|
308
341
|
setValue: function(value, convertStr) {
|
@@ -311,6 +344,11 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
|
|
311
344
|
} else {
|
312
345
|
this.value = value;
|
313
346
|
}
|
347
|
+
|
348
|
+
//if form is visible, update input
|
349
|
+
if(this.$form && this.$form.is(':visible')) {
|
350
|
+
this.input.value2input(this.value);
|
351
|
+
}
|
314
352
|
}
|
315
353
|
};
|
316
354
|
|
@@ -363,18 +401,25 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
|
|
363
401
|
type: 'text',
|
364
402
|
/**
|
365
403
|
Url for submit, e.g. <code>'/post'</code>
|
366
|
-
If function - it will be called instead of ajax. Function
|
404
|
+
If function - it will be called instead of ajax. Function should return deferred object to run fail/done callbacks.
|
367
405
|
|
368
406
|
@property url
|
369
407
|
@type string|function
|
370
408
|
@default null
|
371
409
|
@example
|
372
410
|
url: function(params) {
|
411
|
+
var d = new $.Deferred;
|
373
412
|
if(params.value === 'abc') {
|
374
|
-
|
375
|
-
return d.reject('field cannot be "abc"'); //returning error via deferred object
|
413
|
+
return d.reject('error message'); //returning error via deferred object
|
376
414
|
} else {
|
377
|
-
|
415
|
+
//async saving data in js model
|
416
|
+
someModel.asyncSaveMethod({
|
417
|
+
...,
|
418
|
+
success: function(){
|
419
|
+
d.resolve();
|
420
|
+
}
|
421
|
+
});
|
422
|
+
return d.promise();
|
378
423
|
}
|
379
424
|
}
|
380
425
|
**/
|
@@ -445,7 +490,7 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
|
|
445
490
|
validate: null,
|
446
491
|
/**
|
447
492
|
Success callback. Called when value successfully sent on server and **response status = 200**.
|
448
|
-
|
493
|
+
Usefull to work with json response. For example, if your backend response can be <code>{success: true}</code>
|
449
494
|
or <code>{success: false, msg: "server error"}</code> you can check it inside this callback.
|
450
495
|
If it returns **string** - means error occured and string is shown as error message.
|
451
496
|
If it returns **object like** <code>{newValue: <something>}</code> - it overwrites value, submitted by user.
|
@@ -461,26 +506,45 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
|
|
461
506
|
**/
|
462
507
|
success: null,
|
463
508
|
/**
|
464
|
-
|
509
|
+
Error callback. Called when request failed (response status != 200).
|
510
|
+
Usefull when you want to parse error response and display a custom message.
|
511
|
+
Must return **string** - the message to be displayed in the error block.
|
512
|
+
|
513
|
+
@property error
|
514
|
+
@type function
|
515
|
+
@default null
|
516
|
+
@since 1.4.4
|
517
|
+
@example
|
518
|
+
error: function(response, newValue) {
|
519
|
+
if(response.status === 500) {
|
520
|
+
return 'Service unavailable. Please try later.';
|
521
|
+
} else {
|
522
|
+
return response.responseText;
|
523
|
+
}
|
524
|
+
}
|
525
|
+
**/
|
526
|
+
error: null,
|
527
|
+
/**
|
528
|
+
Additional options for submit ajax request.
|
465
529
|
List of values: http://api.jquery.com/jQuery.ajax
|
466
|
-
|
530
|
+
|
467
531
|
@property ajaxOptions
|
468
532
|
@type object
|
469
533
|
@default null
|
470
534
|
@since 1.1.1
|
535
|
+
@example
|
536
|
+
ajaxOptions: {
|
537
|
+
type: 'put',
|
538
|
+
dataType: 'json'
|
539
|
+
}
|
471
540
|
**/
|
472
541
|
ajaxOptions: null,
|
473
542
|
/**
|
474
|
-
|
475
|
-
Form without buttons
|
476
|
-
@example
|
477
|
-
ajaxOptions: {
|
478
|
-
method: 'PUT',
|
479
|
-
dataType: 'xml'
|
480
|
-
}
|
543
|
+
Where to show buttons: left(true)|bottom|false
|
544
|
+
Form without buttons is auto-submitted.
|
481
545
|
|
482
546
|
@property showbuttons
|
483
|
-
@type boolean
|
547
|
+
@type boolean|string
|
484
548
|
@default true
|
485
549
|
@since 1.1.1
|
486
550
|
**/
|
@@ -504,7 +568,7 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
|
|
504
568
|
@default false
|
505
569
|
@since 1.2.0
|
506
570
|
**/
|
507
|
-
savenochange: false
|
571
|
+
savenochange: false
|
508
572
|
};
|
509
573
|
|
510
574
|
/*
|
@@ -530,11 +594,14 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
|
|
530
594
|
|
531
595
|
//error class attached to editable-error-block
|
532
596
|
$.fn.editableform.errorBlockClass = 'editable-error';
|
533
|
-
}(window.jQuery));
|
597
|
+
}(window.jQuery));
|
598
|
+
|
534
599
|
/**
|
535
600
|
* EditableForm utilites
|
536
601
|
*/
|
537
602
|
(function ($) {
|
603
|
+
"use strict";
|
604
|
+
|
538
605
|
//utils
|
539
606
|
$.fn.editableutils = {
|
540
607
|
/**
|
@@ -621,19 +688,22 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
|
|
621
688
|
return newObj;
|
622
689
|
},
|
623
690
|
|
624
|
-
|
625
|
-
|
691
|
+
/*
|
692
|
+
exclude complex objects from $.data() before pass to config
|
626
693
|
*/
|
627
694
|
getConfigData: function($element) {
|
628
695
|
var data = {};
|
629
696
|
$.each($element.data(), function(k, v) {
|
630
|
-
if(typeof v !== 'object' || (v && typeof v === 'object' && v.constructor === Object)) {
|
697
|
+
if(typeof v !== 'object' || (v && typeof v === 'object' && (v.constructor === Object || v.constructor === Array))) {
|
631
698
|
data[k] = v;
|
632
699
|
}
|
633
700
|
});
|
634
701
|
return data;
|
635
702
|
},
|
636
703
|
|
704
|
+
/*
|
705
|
+
returns keys of object
|
706
|
+
*/
|
637
707
|
objectKeys: function(o) {
|
638
708
|
if (Object.keys) {
|
639
709
|
return Object.keys(o);
|
@@ -657,9 +727,100 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
|
|
657
727
|
**/
|
658
728
|
escape: function(str) {
|
659
729
|
return $('<div>').text(str).html();
|
660
|
-
}
|
730
|
+
},
|
731
|
+
|
732
|
+
/*
|
733
|
+
returns array items from sourceData having value property equal or inArray of 'value'
|
734
|
+
*/
|
735
|
+
itemsByValue: function(value, sourceData, valueProp) {
|
736
|
+
if(!sourceData || value === null) {
|
737
|
+
return [];
|
738
|
+
}
|
739
|
+
|
740
|
+
valueProp = valueProp || 'value';
|
741
|
+
|
742
|
+
var isValArray = $.isArray(value),
|
743
|
+
result = [],
|
744
|
+
that = this;
|
745
|
+
|
746
|
+
$.each(sourceData, function(i, o) {
|
747
|
+
if(o.children) {
|
748
|
+
result = result.concat(that.itemsByValue(value, o.children, valueProp));
|
749
|
+
} else {
|
750
|
+
/*jslint eqeq: true*/
|
751
|
+
if(isValArray) {
|
752
|
+
if($.grep(value, function(v){ return v == (o && typeof o === 'object' ? o[valueProp] : o); }).length) {
|
753
|
+
result.push(o);
|
754
|
+
}
|
755
|
+
} else {
|
756
|
+
if(value == (o && typeof o === 'object' ? o[valueProp] : o)) {
|
757
|
+
result.push(o);
|
758
|
+
}
|
759
|
+
}
|
760
|
+
/*jslint eqeq: false*/
|
761
|
+
}
|
762
|
+
});
|
763
|
+
|
764
|
+
return result;
|
765
|
+
},
|
766
|
+
|
767
|
+
/*
|
768
|
+
Returns input by options: type, mode.
|
769
|
+
*/
|
770
|
+
createInput: function(options) {
|
771
|
+
var TypeConstructor, typeOptions, input,
|
772
|
+
type = options.type;
|
773
|
+
|
774
|
+
//`date` is some kind of virtual type that is transformed to one of exact types
|
775
|
+
//depending on mode and core lib
|
776
|
+
if(type === 'date') {
|
777
|
+
//inline
|
778
|
+
if(options.mode === 'inline') {
|
779
|
+
if($.fn.editabletypes.datefield) {
|
780
|
+
type = 'datefield';
|
781
|
+
} else if($.fn.editabletypes.dateuifield) {
|
782
|
+
type = 'dateuifield';
|
783
|
+
}
|
784
|
+
//popup
|
785
|
+
} else {
|
786
|
+
if($.fn.editabletypes.date) {
|
787
|
+
type = 'date';
|
788
|
+
} else if($.fn.editabletypes.dateui) {
|
789
|
+
type = 'dateui';
|
790
|
+
}
|
791
|
+
}
|
792
|
+
|
793
|
+
//if type still `date` and not exist in types, replace with `combodate` that is base input
|
794
|
+
if(type === 'date' && !$.fn.editabletypes.date) {
|
795
|
+
type = 'combodate';
|
796
|
+
}
|
797
|
+
}
|
798
|
+
|
799
|
+
//`datetime` should be datetimefield in 'inline' mode
|
800
|
+
if(type === 'datetime' && options.mode === 'inline') {
|
801
|
+
type = 'datetimefield';
|
802
|
+
}
|
803
|
+
|
804
|
+
//change wysihtml5 to textarea for jquery UI and plain versions
|
805
|
+
if(type === 'wysihtml5' && !$.fn.editabletypes[type]) {
|
806
|
+
type = 'textarea';
|
807
|
+
}
|
808
|
+
|
809
|
+
//create input of specified type. Input will be used for converting value, not in form
|
810
|
+
if(typeof $.fn.editabletypes[type] === 'function') {
|
811
|
+
TypeConstructor = $.fn.editabletypes[type];
|
812
|
+
typeOptions = this.sliceObj(options, this.objectKeys(TypeConstructor.defaults));
|
813
|
+
input = new TypeConstructor(typeOptions);
|
814
|
+
return input;
|
815
|
+
} else {
|
816
|
+
$.error('Unknown type: '+ type);
|
817
|
+
return false;
|
818
|
+
}
|
819
|
+
}
|
820
|
+
|
661
821
|
};
|
662
|
-
}(window.jQuery));
|
822
|
+
}(window.jQuery));
|
823
|
+
|
663
824
|
/**
|
664
825
|
Attaches stand-alone container with editable-form to HTML element. Element is used only for positioning, value is not stored anywhere.<br>
|
665
826
|
This method applied internally in <code>$().editable()</code>. You should subscribe on it's events (save / cancel) to get profit of it.<br>
|
@@ -670,20 +831,30 @@ Applied as jQuery method.
|
|
670
831
|
@uses editableform
|
671
832
|
**/
|
672
833
|
(function ($) {
|
834
|
+
"use strict";
|
673
835
|
|
674
|
-
var
|
836
|
+
var Popup = function (element, options) {
|
675
837
|
this.init(element, options);
|
676
838
|
};
|
839
|
+
|
840
|
+
var Inline = function (element, options) {
|
841
|
+
this.init(element, options);
|
842
|
+
};
|
677
843
|
|
678
844
|
//methods
|
679
|
-
|
845
|
+
Popup.prototype = {
|
680
846
|
containerName: null, //tbd in child class
|
681
847
|
innerCss: null, //tbd in child class
|
848
|
+
containerClass: 'editable-container editable-popup', //css class applied to container element
|
682
849
|
init: function(element, options) {
|
683
850
|
this.$element = $(element);
|
684
|
-
//
|
685
|
-
this.options = $.extend({}, $.fn.editableContainer.defaults,
|
851
|
+
//since 1.4.1 container do not use data-* directly as they already merged into options.
|
852
|
+
this.options = $.extend({}, $.fn.editableContainer.defaults, options);
|
686
853
|
this.splitOptions();
|
854
|
+
|
855
|
+
//set scope of form callbacks to element
|
856
|
+
this.formOptions.scope = this.$element[0];
|
857
|
+
|
687
858
|
this.initContainer();
|
688
859
|
|
689
860
|
//bind 'destroyed' listener to destroy container when element is removed from dom
|
@@ -691,7 +862,7 @@ Applied as jQuery method.
|
|
691
862
|
this.destroy();
|
692
863
|
}, this));
|
693
864
|
|
694
|
-
//attach document
|
865
|
+
//attach document handler to close containers on click / escape
|
695
866
|
if(!$(document).data('editable-handlers-attached')) {
|
696
867
|
//close all on escape
|
697
868
|
$(document).on('keyup.editable', function (e) {
|
@@ -701,17 +872,39 @@ Applied as jQuery method.
|
|
701
872
|
}
|
702
873
|
});
|
703
874
|
|
704
|
-
//close containers when click outside
|
875
|
+
//close containers when click outside
|
876
|
+
//(mousedown could be better than click, it closes everything also on drag drop)
|
705
877
|
$(document).on('click.editable', function(e) {
|
706
|
-
var $target = $(e.target)
|
878
|
+
var $target = $(e.target), i,
|
879
|
+
exclude_classes = ['.editable-container',
|
880
|
+
'.ui-datepicker-header',
|
881
|
+
'.datepicker', //in inline mode datepicker is rendered into body
|
882
|
+
'.modal-backdrop',
|
883
|
+
'.bootstrap-wysihtml5-insert-image-modal',
|
884
|
+
'.bootstrap-wysihtml5-insert-link-modal'
|
885
|
+
];
|
707
886
|
|
708
|
-
//if
|
709
|
-
if(
|
710
|
-
|
711
|
-
}
|
712
|
-
|
713
|
-
|
887
|
+
//check if element is detached. It occurs when clicking in bootstrap datepicker
|
888
|
+
if (!$.contains(document.documentElement, e.target)) {
|
889
|
+
return;
|
890
|
+
}
|
891
|
+
|
892
|
+
//for some reason FF 20 generates extra event (click) in select2 widget with e.target = document
|
893
|
+
//we need to filter it via construction below. See https://github.com/vitalets/x-editable/issues/199
|
894
|
+
//Possibly related to http://stackoverflow.com/questions/10119793/why-does-firefox-react-differently-from-webkit-and-ie-to-click-event-on-selec
|
895
|
+
if($target.is(document)) {
|
896
|
+
return;
|
897
|
+
}
|
898
|
+
|
899
|
+
//if click inside one of exclude classes --> no nothing
|
900
|
+
for(i=0; i<exclude_classes.length; i++) {
|
901
|
+
if($target.is(exclude_classes[i]) || $target.parents(exclude_classes[i]).length) {
|
902
|
+
return;
|
903
|
+
}
|
714
904
|
}
|
905
|
+
|
906
|
+
//close all open containers (except one - target)
|
907
|
+
Popup.prototype.closeOthers(e.target);
|
715
908
|
});
|
716
909
|
|
717
910
|
$(document).data('editable-handlers-attached', true);
|
@@ -722,7 +915,13 @@ Applied as jQuery method.
|
|
722
915
|
splitOptions: function() {
|
723
916
|
this.containerOptions = {};
|
724
917
|
this.formOptions = {};
|
918
|
+
|
919
|
+
if(!$.fn[this.containerName]) {
|
920
|
+
throw new Error(this.containerName + ' not found. Have you included corresponding js file?');
|
921
|
+
}
|
922
|
+
|
725
923
|
var cDef = $.fn[this.containerName].defaults;
|
924
|
+
//keys defined in container defaults go to container, others go to form
|
726
925
|
for(var k in this.options) {
|
727
926
|
if(k in cDef) {
|
728
927
|
this.containerOptions[k] = this.options[k];
|
@@ -732,59 +931,66 @@ Applied as jQuery method.
|
|
732
931
|
}
|
733
932
|
},
|
734
933
|
|
934
|
+
/*
|
935
|
+
Returns jquery object of container
|
936
|
+
@method tip()
|
937
|
+
*/
|
938
|
+
tip: function() {
|
939
|
+
return this.container() ? this.container().$tip : null;
|
940
|
+
},
|
941
|
+
|
942
|
+
/* returns container object */
|
943
|
+
container: function() {
|
944
|
+
return this.$element.data(this.containerDataName || this.containerName);
|
945
|
+
},
|
946
|
+
|
947
|
+
/* call native method of underlying container, e.g. this.$element.popover('method') */
|
948
|
+
call: function() {
|
949
|
+
this.$element[this.containerName].apply(this.$element, arguments);
|
950
|
+
},
|
951
|
+
|
735
952
|
initContainer: function(){
|
736
953
|
this.call(this.containerOptions);
|
737
954
|
},
|
738
955
|
|
739
|
-
|
740
|
-
this
|
741
|
-
this.$form = $('<div>')
|
956
|
+
renderForm: function() {
|
957
|
+
this.$form
|
742
958
|
.editableform(this.formOptions)
|
743
959
|
.on({
|
744
|
-
save: $.proxy(this.save, this),
|
745
|
-
|
746
|
-
|
960
|
+
save: $.proxy(this.save, this), //click on submit button (value changed)
|
961
|
+
nochange: $.proxy(function(){ this.hide('nochange'); }, this), //click on submit button (value NOT changed)
|
962
|
+
cancel: $.proxy(function(){ this.hide('cancel'); }, this), //click on calcel button
|
747
963
|
show: $.proxy(this.setPosition, this), //re-position container every time form is shown (occurs each time after loading state)
|
748
964
|
rendering: $.proxy(this.setPosition, this), //this allows to place container correctly when loading shown
|
965
|
+
resize: $.proxy(this.setPosition, this), //this allows to re-position container when form size is changed
|
749
966
|
rendered: $.proxy(function(){
|
750
967
|
/**
|
751
|
-
Fired when container is shown and form is rendered (for select will wait for loading dropdown options)
|
968
|
+
Fired when container is shown and form is rendered (for select will wait for loading dropdown options).
|
969
|
+
**Note:** Bootstrap popover has own `shown` event that now cannot be separated from x-editable's one.
|
970
|
+
The workaround is to check `arguments.length` that is always `2` for x-editable.
|
752
971
|
|
753
972
|
@event shown
|
754
973
|
@param {Object} event event object
|
755
974
|
@example
|
756
|
-
$('#username').on('shown', function() {
|
757
|
-
|
758
|
-
$tip.find('input').val('overwriting value of input..');
|
975
|
+
$('#username').on('shown', function(e, editable) {
|
976
|
+
editable.input.$input.val('overwriting value of input..');
|
759
977
|
});
|
760
978
|
**/
|
761
|
-
|
979
|
+
/*
|
980
|
+
TODO: added second param mainly to distinguish from bootstrap's shown event. It's a hotfix that will be solved in future versions via namespaced events.
|
981
|
+
*/
|
982
|
+
this.$element.triggerHandler('shown', this);
|
762
983
|
}, this)
|
763
|
-
})
|
764
|
-
|
984
|
+
})
|
985
|
+
.editableform('render');
|
765
986
|
},
|
766
987
|
|
767
|
-
/*
|
768
|
-
Returns jquery object of container
|
769
|
-
@method tip()
|
770
|
-
*/
|
771
|
-
tip: function() {
|
772
|
-
return this.container().$tip;
|
773
|
-
},
|
774
|
-
|
775
|
-
container: function() {
|
776
|
-
return this.$element.data(this.containerName);
|
777
|
-
},
|
778
|
-
|
779
|
-
call: function() {
|
780
|
-
this.$element[this.containerName].apply(this.$element, arguments);
|
781
|
-
},
|
782
|
-
|
783
988
|
/**
|
784
989
|
Shows container with form
|
785
990
|
@method show()
|
786
991
|
@param {boolean} closeAll Whether to close all other editable containers when showing this one. Default true.
|
787
|
-
**/
|
992
|
+
**/
|
993
|
+
/* Note: poshytip owerwrites this method totally! */
|
788
994
|
show: function (closeAll) {
|
789
995
|
this.$element.addClass('editable-open');
|
790
996
|
if(closeAll !== false) {
|
@@ -792,16 +998,37 @@ Applied as jQuery method.
|
|
792
998
|
this.closeOthers(this.$element[0]);
|
793
999
|
}
|
794
1000
|
|
1001
|
+
//show container itself
|
795
1002
|
this.innerShow();
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
1003
|
+
this.tip().addClass(this.containerClass);
|
1004
|
+
|
1005
|
+
/*
|
1006
|
+
Currently, form is re-rendered on every show.
|
1007
|
+
The main reason is that we dont know, what container will do with content when closed:
|
1008
|
+
remove(), detach() or just hide().
|
1009
|
+
|
1010
|
+
Detaching form itself before hide and re-insert before show is good solution,
|
1011
|
+
but visually it looks ugly, as container changes size before hide.
|
1012
|
+
*/
|
1013
|
+
|
1014
|
+
//if form already exist - delete previous data
|
1015
|
+
if(this.$form) {
|
1016
|
+
//todo: destroy prev data!
|
1017
|
+
//this.$form.destroy();
|
1018
|
+
}
|
1019
|
+
|
1020
|
+
this.$form = $('<div>');
|
1021
|
+
|
1022
|
+
//insert form into container body
|
1023
|
+
if(this.tip().is(this.innerCss)) {
|
1024
|
+
//for inline container
|
1025
|
+
this.tip().append(this.$form);
|
1026
|
+
} else {
|
1027
|
+
this.tip().find(this.innerCss).append(this.$form);
|
1028
|
+
}
|
1029
|
+
|
1030
|
+
//render form
|
1031
|
+
this.renderForm();
|
805
1032
|
},
|
806
1033
|
|
807
1034
|
/**
|
@@ -813,14 +1040,18 @@ Applied as jQuery method.
|
|
813
1040
|
if(!this.tip() || !this.tip().is(':visible') || !this.$element.hasClass('editable-open')) {
|
814
1041
|
return;
|
815
1042
|
}
|
1043
|
+
|
816
1044
|
this.$element.removeClass('editable-open');
|
817
1045
|
this.innerHide();
|
1046
|
+
|
818
1047
|
/**
|
819
|
-
Fired when container was hidden. It occurs on both save or cancel.
|
1048
|
+
Fired when container was hidden. It occurs on both save or cancel.
|
1049
|
+
**Note:** Bootstrap popover has own `hidden` event that now cannot be separated from x-editable's one.
|
1050
|
+
The workaround is to check `arguments.length` that is always `2` for x-editable.
|
820
1051
|
|
821
1052
|
@event hidden
|
822
1053
|
@param {object} event event object
|
823
|
-
@param {string} reason Reason caused hiding. Can be <code>save|cancel|onblur|nochange|
|
1054
|
+
@param {string} reason Reason caused hiding. Can be <code>save|cancel|onblur|nochange|manual</code>
|
824
1055
|
@example
|
825
1056
|
$('#username').on('hidden', function(e, reason) {
|
826
1057
|
if(reason === 'save' || reason === 'cancel') {
|
@@ -829,12 +1060,17 @@ Applied as jQuery method.
|
|
829
1060
|
}
|
830
1061
|
});
|
831
1062
|
**/
|
832
|
-
this.$element.triggerHandler('hidden', reason);
|
1063
|
+
this.$element.triggerHandler('hidden', reason || 'manual');
|
833
1064
|
},
|
834
1065
|
|
1066
|
+
/* internal show method. To be overwritten in child classes */
|
1067
|
+
innerShow: function () {
|
1068
|
+
|
1069
|
+
},
|
1070
|
+
|
835
1071
|
/* internal hide method. To be overwritten in child classes */
|
836
1072
|
innerHide: function () {
|
837
|
-
|
1073
|
+
|
838
1074
|
},
|
839
1075
|
|
840
1076
|
/**
|
@@ -843,7 +1079,7 @@ Applied as jQuery method.
|
|
843
1079
|
@param {boolean} closeAll Whether to close all other editable containers when showing this one. Default true.
|
844
1080
|
**/
|
845
1081
|
toggle: function(closeAll) {
|
846
|
-
if(this.tip && this.tip().is(':visible')) {
|
1082
|
+
if(this.container() && this.tip() && this.tip().is(':visible')) {
|
847
1083
|
this.hide();
|
848
1084
|
} else {
|
849
1085
|
this.show(closeAll);
|
@@ -859,7 +1095,6 @@ Applied as jQuery method.
|
|
859
1095
|
},
|
860
1096
|
|
861
1097
|
save: function(e, params) {
|
862
|
-
this.hide('save');
|
863
1098
|
/**
|
864
1099
|
Fired when new value was submitted. You can use <code>$(this).data('editableContainer')</code> inside handler to access to editableContainer instance
|
865
1100
|
|
@@ -880,6 +1115,9 @@ Applied as jQuery method.
|
|
880
1115
|
});
|
881
1116
|
**/
|
882
1117
|
this.$element.triggerHandler('save', params);
|
1118
|
+
|
1119
|
+
//hide must be after trigger, as saving value may require methods od plugin, applied to input
|
1120
|
+
this.hide('save');
|
883
1121
|
},
|
884
1122
|
|
885
1123
|
/**
|
@@ -911,9 +1149,17 @@ Applied as jQuery method.
|
|
911
1149
|
@method destroy()
|
912
1150
|
**/
|
913
1151
|
destroy: function() {
|
914
|
-
this.
|
1152
|
+
this.hide();
|
1153
|
+
this.innerDestroy();
|
1154
|
+
this.$element.off('destroyed');
|
1155
|
+
this.$element.removeData('editableContainer');
|
915
1156
|
},
|
916
1157
|
|
1158
|
+
/* to be overwritten in child classes */
|
1159
|
+
innerDestroy: function() {
|
1160
|
+
|
1161
|
+
},
|
1162
|
+
|
917
1163
|
/*
|
918
1164
|
Closes other containers except one related to passed element.
|
919
1165
|
Other containers can be cancelled or submitted (depends on onblur option)
|
@@ -972,11 +1218,12 @@ Applied as jQuery method.
|
|
972
1218
|
return this.each(function () {
|
973
1219
|
var $this = $(this),
|
974
1220
|
dataKey = 'editableContainer',
|
975
|
-
data = $this.data(dataKey),
|
976
|
-
options = typeof option === 'object' && option
|
1221
|
+
data = $this.data(dataKey),
|
1222
|
+
options = typeof option === 'object' && option,
|
1223
|
+
Constructor = (options.mode === 'inline') ? Inline : Popup;
|
977
1224
|
|
978
1225
|
if (!data) {
|
979
|
-
$this.data(dataKey, (data = new
|
1226
|
+
$this.data(dataKey, (data = new Constructor(this, options)));
|
980
1227
|
}
|
981
1228
|
|
982
1229
|
if (typeof option === 'string') { //call method
|
@@ -985,8 +1232,9 @@ Applied as jQuery method.
|
|
985
1232
|
});
|
986
1233
|
};
|
987
1234
|
|
988
|
-
//store
|
989
|
-
$.fn.editableContainer.
|
1235
|
+
//store constructors
|
1236
|
+
$.fn.editableContainer.Popup = Popup;
|
1237
|
+
$.fn.editableContainer.Inline = Inline;
|
990
1238
|
|
991
1239
|
//defaults
|
992
1240
|
$.fn.editableContainer.defaults = {
|
@@ -1025,7 +1273,25 @@ Applied as jQuery method.
|
|
1025
1273
|
@default 'cancel'
|
1026
1274
|
@since 1.1.1
|
1027
1275
|
**/
|
1028
|
-
onblur: 'cancel'
|
1276
|
+
onblur: 'cancel',
|
1277
|
+
|
1278
|
+
/**
|
1279
|
+
Animation speed (inline mode)
|
1280
|
+
@property anim
|
1281
|
+
@type string
|
1282
|
+
@default false
|
1283
|
+
**/
|
1284
|
+
anim: false,
|
1285
|
+
|
1286
|
+
/**
|
1287
|
+
Mode of editable, can be `popup` or `inline`
|
1288
|
+
|
1289
|
+
@property mode
|
1290
|
+
@type string
|
1291
|
+
@default 'popup'
|
1292
|
+
@since 1.4.0
|
1293
|
+
**/
|
1294
|
+
mode: 'popup'
|
1029
1295
|
};
|
1030
1296
|
|
1031
1297
|
/*
|
@@ -1042,6 +1308,60 @@ Applied as jQuery method.
|
|
1042
1308
|
|
1043
1309
|
}(window.jQuery));
|
1044
1310
|
|
1311
|
+
/**
|
1312
|
+
* Editable Inline
|
1313
|
+
* ---------------------
|
1314
|
+
*/
|
1315
|
+
(function ($) {
|
1316
|
+
"use strict";
|
1317
|
+
|
1318
|
+
//copy prototype from EditableContainer
|
1319
|
+
//extend methods
|
1320
|
+
$.extend($.fn.editableContainer.Inline.prototype, $.fn.editableContainer.Popup.prototype, {
|
1321
|
+
containerName: 'editableform',
|
1322
|
+
innerCss: '.editable-inline',
|
1323
|
+
containerClass: 'editable-container editable-inline', //css class applied to container element
|
1324
|
+
|
1325
|
+
initContainer: function(){
|
1326
|
+
//container is <span> element
|
1327
|
+
this.$tip = $('<span></span>');
|
1328
|
+
|
1329
|
+
//convert anim to miliseconds (int)
|
1330
|
+
if(!this.options.anim) {
|
1331
|
+
this.options.anim = 0;
|
1332
|
+
}
|
1333
|
+
},
|
1334
|
+
|
1335
|
+
splitOptions: function() {
|
1336
|
+
//all options are passed to form
|
1337
|
+
this.containerOptions = {};
|
1338
|
+
this.formOptions = this.options;
|
1339
|
+
},
|
1340
|
+
|
1341
|
+
tip: function() {
|
1342
|
+
return this.$tip;
|
1343
|
+
},
|
1344
|
+
|
1345
|
+
innerShow: function () {
|
1346
|
+
this.$element.hide();
|
1347
|
+
this.tip().insertAfter(this.$element).show();
|
1348
|
+
},
|
1349
|
+
|
1350
|
+
innerHide: function () {
|
1351
|
+
this.$tip.hide(this.options.anim, $.proxy(function() {
|
1352
|
+
this.$element.show();
|
1353
|
+
this.innerDestroy();
|
1354
|
+
}, this));
|
1355
|
+
},
|
1356
|
+
|
1357
|
+
innerDestroy: function() {
|
1358
|
+
if(this.tip()) {
|
1359
|
+
this.tip().empty().remove();
|
1360
|
+
}
|
1361
|
+
}
|
1362
|
+
});
|
1363
|
+
|
1364
|
+
}(window.jQuery));
|
1045
1365
|
/**
|
1046
1366
|
Makes editable any HTML element on the page. Applied as jQuery method.
|
1047
1367
|
|
@@ -1049,37 +1369,33 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1049
1369
|
@uses editableContainer
|
1050
1370
|
**/
|
1051
1371
|
(function ($) {
|
1372
|
+
"use strict";
|
1052
1373
|
|
1053
1374
|
var Editable = function (element, options) {
|
1054
1375
|
this.$element = $(element);
|
1055
|
-
|
1056
|
-
this.
|
1376
|
+
//data-* has more priority over js options: because dynamically created elements may change data-*
|
1377
|
+
this.options = $.extend({}, $.fn.editable.defaults, options, $.fn.editableutils.getConfigData(this.$element));
|
1378
|
+
if(this.options.selector) {
|
1379
|
+
this.initLive();
|
1380
|
+
} else {
|
1381
|
+
this.init();
|
1382
|
+
}
|
1057
1383
|
};
|
1058
1384
|
|
1059
1385
|
Editable.prototype = {
|
1060
1386
|
constructor: Editable,
|
1061
1387
|
init: function () {
|
1062
|
-
var
|
1063
|
-
|
1064
|
-
|
1065
|
-
finalize;
|
1066
|
-
|
1067
|
-
//editableContainer must be defined
|
1068
|
-
if(!$.fn.editableContainer) {
|
1069
|
-
$.error('You must define $.fn.editableContainer via including corresponding file (e.g. editable-popover.js)');
|
1070
|
-
return;
|
1071
|
-
}
|
1072
|
-
|
1388
|
+
var isValueByText = false,
|
1389
|
+
doAutotext, finalize;
|
1390
|
+
|
1073
1391
|
//name
|
1074
1392
|
this.options.name = this.options.name || this.$element.attr('id');
|
1075
1393
|
|
1076
|
-
//create input of specified type. Input
|
1077
|
-
|
1078
|
-
|
1079
|
-
|
1080
|
-
|
1081
|
-
} else {
|
1082
|
-
$.error('Unknown type: '+ this.options.type);
|
1394
|
+
//create input of specified type. Input needed already here to convert value for initial display (e.g. show text by id for select)
|
1395
|
+
//also we set scope option to have access to element inside input specific callbacks (e. g. source as function)
|
1396
|
+
this.options.scope = this.$element[0];
|
1397
|
+
this.input = $.fn.editableutils.createInput(this.options);
|
1398
|
+
if(!this.input) {
|
1083
1399
|
return;
|
1084
1400
|
}
|
1085
1401
|
|
@@ -1108,8 +1424,10 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1108
1424
|
if(this.options.toggle !== 'manual') {
|
1109
1425
|
this.$element.addClass('editable-click');
|
1110
1426
|
this.$element.on(this.options.toggle + '.editable', $.proxy(function(e){
|
1427
|
+
//prevent following link
|
1111
1428
|
e.preventDefault();
|
1112
|
-
|
1429
|
+
|
1430
|
+
//stop propagation not required because in document click handler it checks event target
|
1113
1431
|
//e.stopPropagation();
|
1114
1432
|
|
1115
1433
|
if(this.options.toggle === 'mouseenter') {
|
@@ -1126,9 +1444,19 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1126
1444
|
}
|
1127
1445
|
|
1128
1446
|
//check conditions for autotext:
|
1129
|
-
|
1130
|
-
|
1131
|
-
|
1447
|
+
switch(this.options.autotext) {
|
1448
|
+
case 'always':
|
1449
|
+
doAutotext = true;
|
1450
|
+
break;
|
1451
|
+
case 'auto':
|
1452
|
+
//if element text is empty and value is defined and value not generated by text --> run autotext
|
1453
|
+
doAutotext = !$.trim(this.$element.text()).length && this.value !== null && this.value !== undefined && !isValueByText;
|
1454
|
+
break;
|
1455
|
+
default:
|
1456
|
+
doAutotext = false;
|
1457
|
+
}
|
1458
|
+
|
1459
|
+
//depending on autotext run render() or just finilize init
|
1132
1460
|
$.when(doAutotext ? this.render() : true).then($.proxy(function() {
|
1133
1461
|
if(this.options.disabled) {
|
1134
1462
|
this.disable();
|
@@ -1136,34 +1464,65 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1136
1464
|
this.enable();
|
1137
1465
|
}
|
1138
1466
|
/**
|
1139
|
-
Fired when element was initialized by editable method.
|
1467
|
+
Fired when element was initialized by `$().editable()` method.
|
1468
|
+
Please note that you should setup `init` handler **before** applying `editable`.
|
1140
1469
|
|
1141
1470
|
@event init
|
1142
1471
|
@param {Object} event event object
|
1143
|
-
@param {Object} editable editable instance
|
1472
|
+
@param {Object} editable editable instance (as here it cannot accessed via data('editable'))
|
1144
1473
|
@since 1.2.0
|
1474
|
+
@example
|
1475
|
+
$('#username').on('init', function(e, editable) {
|
1476
|
+
alert('initialized ' + editable.options.name);
|
1477
|
+
});
|
1478
|
+
$('#username').editable();
|
1145
1479
|
**/
|
1146
1480
|
this.$element.triggerHandler('init', this);
|
1147
1481
|
}, this));
|
1148
1482
|
},
|
1149
1483
|
|
1484
|
+
/*
|
1485
|
+
Initializes parent element for live editables
|
1486
|
+
*/
|
1487
|
+
initLive: function() {
|
1488
|
+
//store selector
|
1489
|
+
var selector = this.options.selector;
|
1490
|
+
//modify options for child elements
|
1491
|
+
this.options.selector = false;
|
1492
|
+
this.options.autotext = 'never';
|
1493
|
+
//listen toggle events
|
1494
|
+
this.$element.on(this.options.toggle + '.editable', selector, $.proxy(function(e){
|
1495
|
+
var $target = $(e.target);
|
1496
|
+
if(!$target.data('editable')) {
|
1497
|
+
//if delegated element initially empty, we need to clear it's text (that was manually set to `empty` by user)
|
1498
|
+
//see https://github.com/vitalets/x-editable/issues/137
|
1499
|
+
if($target.hasClass(this.options.emptyclass)) {
|
1500
|
+
$target.empty();
|
1501
|
+
}
|
1502
|
+
$target.editable(this.options).trigger(e);
|
1503
|
+
}
|
1504
|
+
}, this));
|
1505
|
+
},
|
1506
|
+
|
1150
1507
|
/*
|
1151
1508
|
Renders value into element's text.
|
1152
1509
|
Can call custom display method from options.
|
1153
1510
|
Can return deferred object.
|
1154
1511
|
@method render()
|
1512
|
+
@param {mixed} response server response (if exist) to pass into display function
|
1155
1513
|
*/
|
1156
|
-
render: function() {
|
1514
|
+
render: function(response) {
|
1157
1515
|
//do not display anything
|
1158
1516
|
if(this.options.display === false) {
|
1159
1517
|
return;
|
1160
1518
|
}
|
1161
|
-
|
1162
|
-
if
|
1163
|
-
|
1519
|
+
|
1520
|
+
//if input has `value2htmlFinal` method, we pass callback in third param to be called when source is loaded
|
1521
|
+
if(this.input.value2htmlFinal) {
|
1522
|
+
return this.input.value2html(this.value, this.$element[0], this.options.display, response);
|
1164
1523
|
//if display method defined --> use it
|
1165
1524
|
} else if(typeof this.options.display === 'function') {
|
1166
|
-
return this.options.display.call(this.$element[0], this.value);
|
1525
|
+
return this.options.display.call(this.$element[0], this.value, response);
|
1167
1526
|
//else use input's original value2html() method
|
1168
1527
|
} else {
|
1169
1528
|
return this.input.value2html(this.value, this.$element[0]);
|
@@ -1177,7 +1536,7 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1177
1536
|
enable: function() {
|
1178
1537
|
this.options.disabled = false;
|
1179
1538
|
this.$element.removeClass('editable-disabled');
|
1180
|
-
this.handleEmpty();
|
1539
|
+
this.handleEmpty(this.isEmpty);
|
1181
1540
|
if(this.options.toggle !== 'manual') {
|
1182
1541
|
if(this.$element.attr('tabindex') === '-1') {
|
1183
1542
|
this.$element.removeAttr('tabindex');
|
@@ -1193,7 +1552,7 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1193
1552
|
this.options.disabled = true;
|
1194
1553
|
this.hide();
|
1195
1554
|
this.$element.addClass('editable-disabled');
|
1196
|
-
this.handleEmpty();
|
1555
|
+
this.handleEmpty(this.isEmpty);
|
1197
1556
|
//do not stop focus on this element
|
1198
1557
|
this.$element.attr('tabindex', -1);
|
1199
1558
|
},
|
@@ -1233,12 +1592,7 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1233
1592
|
|
1234
1593
|
//disabled
|
1235
1594
|
if(key === 'disabled') {
|
1236
|
-
|
1237
|
-
this.disable();
|
1238
|
-
} else {
|
1239
|
-
this.enable();
|
1240
|
-
}
|
1241
|
-
return;
|
1595
|
+
return value ? this.disable() : this.enable();
|
1242
1596
|
}
|
1243
1597
|
|
1244
1598
|
//value
|
@@ -1250,30 +1604,42 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1250
1604
|
if(this.container) {
|
1251
1605
|
this.container.option(key, value);
|
1252
1606
|
}
|
1607
|
+
|
1608
|
+
//pass option to input directly (as it points to the same in form)
|
1609
|
+
if(this.input.option) {
|
1610
|
+
this.input.option(key, value);
|
1611
|
+
}
|
1612
|
+
|
1253
1613
|
},
|
1254
1614
|
|
1255
1615
|
/*
|
1256
|
-
* set emptytext if element is empty
|
1616
|
+
* set emptytext if element is empty
|
1257
1617
|
*/
|
1258
|
-
handleEmpty: function () {
|
1618
|
+
handleEmpty: function (isEmpty) {
|
1259
1619
|
//do not handle empty if we do not display anything
|
1260
1620
|
if(this.options.display === false) {
|
1261
1621
|
return;
|
1262
1622
|
}
|
1623
|
+
|
1624
|
+
this.isEmpty = isEmpty !== undefined ? isEmpty : $.trim(this.$element.text()) === '';
|
1263
1625
|
|
1264
|
-
var emptyClass = 'editable-empty';
|
1265
1626
|
//emptytext shown only for enabled
|
1266
1627
|
if(!this.options.disabled) {
|
1267
|
-
if (
|
1268
|
-
this.$element.
|
1269
|
-
|
1270
|
-
|
1628
|
+
if (this.isEmpty) {
|
1629
|
+
this.$element.text(this.options.emptytext);
|
1630
|
+
if(this.options.emptyclass) {
|
1631
|
+
this.$element.addClass(this.options.emptyclass);
|
1632
|
+
}
|
1633
|
+
} else if(this.options.emptyclass) {
|
1634
|
+
this.$element.removeClass(this.options.emptyclass);
|
1271
1635
|
}
|
1272
1636
|
} else {
|
1273
1637
|
//below required if element disable property was changed
|
1274
|
-
if(this
|
1638
|
+
if(this.isEmpty) {
|
1275
1639
|
this.$element.empty();
|
1276
|
-
this
|
1640
|
+
if(this.options.emptyclass) {
|
1641
|
+
this.$element.removeClass(this.options.emptyclass);
|
1642
|
+
}
|
1277
1643
|
}
|
1278
1644
|
}
|
1279
1645
|
},
|
@@ -1291,9 +1657,11 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1291
1657
|
//init editableContainer: popover, tooltip, inline, etc..
|
1292
1658
|
if(!this.container) {
|
1293
1659
|
var containerOptions = $.extend({}, this.options, {
|
1294
|
-
value: this.value
|
1660
|
+
value: this.value,
|
1661
|
+
input: this.input //pass input to form (as it is already created)
|
1295
1662
|
});
|
1296
1663
|
this.$element.editableContainer(containerOptions);
|
1664
|
+
//listen `save` event
|
1297
1665
|
this.$element.on("save.internal", $.proxy(this.save, this));
|
1298
1666
|
this.container = this.$element.data('editableContainer');
|
1299
1667
|
} else if(this.container.tip().is(':visible')) {
|
@@ -1331,15 +1699,30 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1331
1699
|
* called when form was submitted
|
1332
1700
|
*/
|
1333
1701
|
save: function(e, params) {
|
1334
|
-
//
|
1335
|
-
if(
|
1336
|
-
|
1337
|
-
|
1338
|
-
|
1702
|
+
//mark element with unsaved class if needed
|
1703
|
+
if(this.options.unsavedclass) {
|
1704
|
+
/*
|
1705
|
+
Add unsaved css to element if:
|
1706
|
+
- url is not user's function
|
1707
|
+
- value was not sent to server
|
1708
|
+
- params.response === undefined, that means data was not sent
|
1709
|
+
- value changed
|
1710
|
+
*/
|
1711
|
+
var sent = false;
|
1712
|
+
sent = sent || typeof this.options.url === 'function';
|
1713
|
+
sent = sent || this.options.display === false;
|
1714
|
+
sent = sent || params.response !== undefined;
|
1715
|
+
sent = sent || (this.options.savenochange && this.input.value2str(this.value) !== this.input.value2str(params.newValue));
|
1716
|
+
|
1717
|
+
if(sent) {
|
1718
|
+
this.$element.removeClass(this.options.unsavedclass);
|
1719
|
+
} else {
|
1720
|
+
this.$element.addClass(this.options.unsavedclass);
|
1721
|
+
}
|
1339
1722
|
}
|
1340
1723
|
|
1341
|
-
|
1342
|
-
this.setValue(params.newValue);
|
1724
|
+
//set new value
|
1725
|
+
this.setValue(params.newValue, false, params.response);
|
1343
1726
|
|
1344
1727
|
/**
|
1345
1728
|
Fired when new value was submitted. You can use <code>$(this).data('editable')</code> to access to editable instance
|
@@ -1351,13 +1734,7 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1351
1734
|
@param {Object} params.response ajax response
|
1352
1735
|
@example
|
1353
1736
|
$('#username').on('save', function(e, params) {
|
1354
|
-
|
1355
|
-
var pk = $(this).data('editable').options.pk;
|
1356
|
-
if(params.response && params.response.success) {
|
1357
|
-
alert('value: ' + params.newValue + ' with pk: ' + pk + ' saved!');
|
1358
|
-
} else {
|
1359
|
-
alert('error!');
|
1360
|
-
}
|
1737
|
+
alert('Saved value: ' + params.newValue);
|
1361
1738
|
});
|
1362
1739
|
**/
|
1363
1740
|
//event itself is triggered by editableContainer. Description here is only for documentation
|
@@ -1375,7 +1752,7 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1375
1752
|
@param {mixed} value new value
|
1376
1753
|
@param {boolean} convertStr whether to convert value from string to internal format
|
1377
1754
|
**/
|
1378
|
-
setValue: function(value, convertStr) {
|
1755
|
+
setValue: function(value, convertStr, response) {
|
1379
1756
|
if(convertStr) {
|
1380
1757
|
this.value = this.input.str2value(value);
|
1381
1758
|
} else {
|
@@ -1384,7 +1761,7 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1384
1761
|
if(this.container) {
|
1385
1762
|
this.container.option('value', this.value);
|
1386
1763
|
}
|
1387
|
-
$.when(this.render())
|
1764
|
+
$.when(this.render(response))
|
1388
1765
|
.then($.proxy(function() {
|
1389
1766
|
this.handleEmpty();
|
1390
1767
|
}, this));
|
@@ -1398,13 +1775,35 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1398
1775
|
if(this.container) {
|
1399
1776
|
this.container.activate();
|
1400
1777
|
}
|
1401
|
-
}
|
1402
|
-
|
1403
|
-
|
1404
|
-
|
1405
|
-
|
1778
|
+
},
|
1779
|
+
|
1780
|
+
/**
|
1781
|
+
Removes editable feature from element
|
1782
|
+
@method destroy()
|
1783
|
+
**/
|
1784
|
+
destroy: function() {
|
1785
|
+
this.disable();
|
1786
|
+
|
1787
|
+
if(this.container) {
|
1788
|
+
this.container.destroy();
|
1789
|
+
}
|
1406
1790
|
|
1407
|
-
|
1791
|
+
if(this.options.toggle !== 'manual') {
|
1792
|
+
this.$element.removeClass('editable-click');
|
1793
|
+
this.$element.off(this.options.toggle + '.editable');
|
1794
|
+
}
|
1795
|
+
|
1796
|
+
this.$element.off("save.internal");
|
1797
|
+
|
1798
|
+
this.$element.removeClass('editable editable-open editable-disabled');
|
1799
|
+
this.$element.removeData('editable');
|
1800
|
+
}
|
1801
|
+
};
|
1802
|
+
|
1803
|
+
/* EDITABLE PLUGIN DEFINITION
|
1804
|
+
* ======================= */
|
1805
|
+
|
1806
|
+
/**
|
1408
1807
|
jQuery method to initialize editable element.
|
1409
1808
|
|
1410
1809
|
@method $().editable(options)
|
@@ -1415,7 +1814,7 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1415
1814
|
url: '/post',
|
1416
1815
|
pk: 1
|
1417
1816
|
});
|
1418
|
-
**/
|
1817
|
+
**/
|
1419
1818
|
$.fn.editable = function (option) {
|
1420
1819
|
//special API methods returning non-jquery object
|
1421
1820
|
var result = {}, args = arguments, datakey = 'editable';
|
@@ -1432,7 +1831,7 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1432
1831
|
username: "username is required",
|
1433
1832
|
fullname: "fullname should be minimum 3 letters length"
|
1434
1833
|
}
|
1435
|
-
**/
|
1834
|
+
**/
|
1436
1835
|
case 'validate':
|
1437
1836
|
this.each(function () {
|
1438
1837
|
var $this = $(this), data = $this.data(datakey), error;
|
@@ -1443,17 +1842,20 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1443
1842
|
return result;
|
1444
1843
|
|
1445
1844
|
/**
|
1446
|
-
Returns current values of editable elements.
|
1845
|
+
Returns current values of editable elements.
|
1846
|
+
Note that it returns an **object** with name-value pairs, not a value itself. It allows to get data from several elements.
|
1847
|
+
If value of some editable is `null` or `undefined` it is excluded from result object.
|
1848
|
+
|
1447
1849
|
@method getValue()
|
1448
1850
|
@returns {Object} object of element names and values
|
1449
1851
|
@example
|
1450
|
-
$('#username, #fullname').editable('
|
1852
|
+
$('#username, #fullname').editable('getValue');
|
1451
1853
|
// possible result:
|
1452
1854
|
{
|
1453
1855
|
username: "superuser",
|
1454
1856
|
fullname: "John"
|
1455
1857
|
}
|
1456
|
-
**/
|
1858
|
+
**/
|
1457
1859
|
case 'getValue':
|
1458
1860
|
this.each(function () {
|
1459
1861
|
var $this = $(this), data = $this.data(datakey);
|
@@ -1472,11 +1874,11 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1472
1874
|
@param {object} options
|
1473
1875
|
@param {object} options.url url to submit data
|
1474
1876
|
@param {object} options.data additional data to submit
|
1475
|
-
@param {object} options.ajaxOptions additional ajax options
|
1877
|
+
@param {object} options.ajaxOptions additional ajax options
|
1476
1878
|
@param {function} options.error(obj) error handler
|
1477
1879
|
@param {function} options.success(obj,config) success handler
|
1478
1880
|
@returns {Object} jQuery object
|
1479
|
-
**/
|
1881
|
+
**/
|
1480
1882
|
case 'submit': //collects value, validate and submit to server for creating new record
|
1481
1883
|
var config = arguments[1] || {},
|
1482
1884
|
$elems = this,
|
@@ -1584,8 +1986,20 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1584
1986
|
**/
|
1585
1987
|
autotext: 'auto',
|
1586
1988
|
/**
|
1587
|
-
Initial value of input.
|
1588
|
-
|
1989
|
+
Initial value of input. If not set, taken from element's text.
|
1990
|
+
Note, that if element's text is empty - text is automatically generated from value and can be customized (see `autotext` option).
|
1991
|
+
For example, to display currency sign:
|
1992
|
+
@example
|
1993
|
+
<a id="price" data-type="text" data-value="100"></a>
|
1994
|
+
<script>
|
1995
|
+
$('#price').editable({
|
1996
|
+
...
|
1997
|
+
display: function(value) {
|
1998
|
+
$(this).text(value + '$');
|
1999
|
+
}
|
2000
|
+
})
|
2001
|
+
</script>
|
2002
|
+
|
1589
2003
|
@property value
|
1590
2004
|
@type mixed
|
1591
2005
|
@default element's text
|
@@ -1593,10 +2007,21 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1593
2007
|
value: null,
|
1594
2008
|
/**
|
1595
2009
|
Callback to perform custom displaying of value in element's text.
|
1596
|
-
If
|
1597
|
-
If
|
2010
|
+
If `null`, default input's display used.
|
2011
|
+
If `false`, no displaying methods will be called, element's text will never change.
|
1598
2012
|
Runs under element's scope.
|
1599
|
-
|
2013
|
+
_**Parameters:**_
|
2014
|
+
|
2015
|
+
* `value` current value to be displayed
|
2016
|
+
* `response` server response (if display called after ajax submit), since 1.4.0
|
2017
|
+
|
2018
|
+
For _inputs with source_ (select, checklist) parameters are different:
|
2019
|
+
|
2020
|
+
* `value` current value to be displayed
|
2021
|
+
* `sourceData` array of items for current input (e.g. dropdown items)
|
2022
|
+
* `response` server response (if display called after ajax submit), since 1.4.0
|
2023
|
+
|
2024
|
+
To get currently selected items use `$.fn.editableutils.itemsByValue(value, sourceData)`.
|
1600
2025
|
|
1601
2026
|
@property display
|
1602
2027
|
@type function|boolean
|
@@ -1604,11 +2029,67 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1604
2029
|
@since 1.2.0
|
1605
2030
|
@example
|
1606
2031
|
display: function(value, sourceData) {
|
1607
|
-
|
1608
|
-
|
2032
|
+
//display checklist as comma-separated values
|
2033
|
+
var html = [],
|
2034
|
+
checked = $.fn.editableutils.itemsByValue(value, sourceData);
|
2035
|
+
|
2036
|
+
if(checked.length) {
|
2037
|
+
$.each(checked, function(i, v) { html.push($.fn.editableutils.escape(v.text)); });
|
2038
|
+
$(this).html(html.join(', '));
|
2039
|
+
} else {
|
2040
|
+
$(this).empty();
|
2041
|
+
}
|
1609
2042
|
}
|
1610
2043
|
**/
|
1611
|
-
display: null
|
2044
|
+
display: null,
|
2045
|
+
/**
|
2046
|
+
Css class applied when editable text is empty.
|
2047
|
+
|
2048
|
+
@property emptyclass
|
2049
|
+
@type string
|
2050
|
+
@since 1.4.1
|
2051
|
+
@default editable-empty
|
2052
|
+
**/
|
2053
|
+
emptyclass: 'editable-empty',
|
2054
|
+
/**
|
2055
|
+
Css class applied when value was stored but not sent to server (`pk` is empty or `send = 'never'`).
|
2056
|
+
You may set it to `null` if you work with editables locally and submit them together.
|
2057
|
+
|
2058
|
+
@property unsavedclass
|
2059
|
+
@type string
|
2060
|
+
@since 1.4.1
|
2061
|
+
@default editable-unsaved
|
2062
|
+
**/
|
2063
|
+
unsavedclass: 'editable-unsaved',
|
2064
|
+
/**
|
2065
|
+
If selector is provided, editable will be delegated to the specified targets.
|
2066
|
+
Usefull for dynamically generated DOM elements.
|
2067
|
+
**Please note**, that delegated targets can't be initialized with `emptytext` and `autotext` options,
|
2068
|
+
as they actually become editable only after first click.
|
2069
|
+
You should manually set class `editable-click` to these elements.
|
2070
|
+
Also, if element originally empty you should add class `editable-empty`, set `data-value=""` and write emptytext into element:
|
2071
|
+
|
2072
|
+
@property selector
|
2073
|
+
@type string
|
2074
|
+
@since 1.4.1
|
2075
|
+
@default null
|
2076
|
+
@example
|
2077
|
+
<div id="user">
|
2078
|
+
<!-- empty -->
|
2079
|
+
<a href="#" data-name="username" data-type="text" class="editable-click editable-empty" data-value="" title="Username">Empty</a>
|
2080
|
+
<!-- non-empty -->
|
2081
|
+
<a href="#" data-name="group" data-type="select" data-source="/groups" data-value="1" class="editable-click" title="Group">Operator</a>
|
2082
|
+
</div>
|
2083
|
+
|
2084
|
+
<script>
|
2085
|
+
$('#user').editable({
|
2086
|
+
selector: 'a',
|
2087
|
+
url: '/post',
|
2088
|
+
pk: 1
|
2089
|
+
});
|
2090
|
+
</script>
|
2091
|
+
**/
|
2092
|
+
selector: null
|
1612
2093
|
};
|
1613
2094
|
|
1614
2095
|
}(window.jQuery));
|
@@ -1621,7 +2102,8 @@ To create your own input you can inherit from this class.
|
|
1621
2102
|
@class abstractinput
|
1622
2103
|
**/
|
1623
2104
|
(function ($) {
|
1624
|
-
|
2105
|
+
"use strict";
|
2106
|
+
|
1625
2107
|
//types
|
1626
2108
|
$.fn.editabletypes = {};
|
1627
2109
|
|
@@ -1635,26 +2117,27 @@ To create your own input you can inherit from this class.
|
|
1635
2117
|
**/
|
1636
2118
|
init: function(type, options, defaults) {
|
1637
2119
|
this.type = type;
|
1638
|
-
this.options = $.extend({}, defaults, options);
|
1639
|
-
|
1640
|
-
|
1641
|
-
|
2120
|
+
this.options = $.extend({}, defaults, options);
|
2121
|
+
},
|
2122
|
+
|
2123
|
+
/*
|
2124
|
+
this method called before render to init $tpl that is inserted in DOM
|
2125
|
+
*/
|
2126
|
+
prerender: function() {
|
2127
|
+
this.$tpl = $(this.options.tpl); //whole tpl as jquery object
|
2128
|
+
this.$input = this.$tpl; //control itself, can be changed in render method
|
2129
|
+
this.$clear = null; //clear button
|
2130
|
+
this.error = null; //error message, if input cannot be rendered
|
1642
2131
|
},
|
1643
2132
|
|
1644
2133
|
/**
|
1645
2134
|
Renders input from tpl. Can return jQuery deferred object.
|
2135
|
+
Can be overwritten in child objects
|
1646
2136
|
|
1647
2137
|
@method render()
|
1648
2138
|
**/
|
1649
2139
|
render: function() {
|
1650
|
-
|
1651
|
-
if(this.options.inputclass) {
|
1652
|
-
this.$input.addClass(this.options.inputclass);
|
1653
|
-
}
|
1654
|
-
|
1655
|
-
if (this.options.placeholder) {
|
1656
|
-
this.$input.attr('placeholder', this.options.placeholder);
|
1657
|
-
}
|
2140
|
+
|
1658
2141
|
},
|
1659
2142
|
|
1660
2143
|
/**
|
@@ -1691,7 +2174,7 @@ To create your own input you can inherit from this class.
|
|
1691
2174
|
},
|
1692
2175
|
|
1693
2176
|
/**
|
1694
|
-
Converts string received from server into value.
|
2177
|
+
Converts string received from server into value. Usually from `data-value` attribute.
|
1695
2178
|
|
1696
2179
|
@method str2value(str)
|
1697
2180
|
@param {string} str
|
@@ -1702,7 +2185,7 @@ To create your own input you can inherit from this class.
|
|
1702
2185
|
},
|
1703
2186
|
|
1704
2187
|
/**
|
1705
|
-
Converts value for submitting to server
|
2188
|
+
Converts value for submitting to server. Result can be string or object.
|
1706
2189
|
|
1707
2190
|
@method value2submit(value)
|
1708
2191
|
@param {mixed} value
|
@@ -1763,7 +2246,25 @@ To create your own input you can inherit from this class.
|
|
1763
2246
|
**/
|
1764
2247
|
autosubmit: function() {
|
1765
2248
|
|
2249
|
+
},
|
2250
|
+
|
2251
|
+
// -------- helper functions --------
|
2252
|
+
setClass: function() {
|
2253
|
+
if(this.options.inputclass) {
|
2254
|
+
this.$input.addClass(this.options.inputclass);
|
2255
|
+
}
|
2256
|
+
},
|
2257
|
+
|
2258
|
+
setAttr: function(attr) {
|
2259
|
+
if (this.options[attr] !== undefined && this.options[attr] !== null) {
|
2260
|
+
this.$input.attr(attr, this.options[attr]);
|
2261
|
+
}
|
2262
|
+
},
|
2263
|
+
|
2264
|
+
option: function(key, value) {
|
2265
|
+
this.options[key] = value;
|
1766
2266
|
}
|
2267
|
+
|
1767
2268
|
};
|
1768
2269
|
|
1769
2270
|
AbstractInput.defaults = {
|
@@ -1783,14 +2284,12 @@ To create your own input you can inherit from this class.
|
|
1783
2284
|
@default input-medium
|
1784
2285
|
**/
|
1785
2286
|
inputclass: 'input-medium',
|
1786
|
-
|
1787
|
-
|
1788
|
-
|
1789
|
-
|
1790
|
-
|
1791
|
-
|
1792
|
-
**/
|
1793
|
-
name: null
|
2287
|
+
//scope for external methods (e.g. source defined as function)
|
2288
|
+
//for internal use only
|
2289
|
+
scope: null,
|
2290
|
+
|
2291
|
+
//need to re-declare showbuttons here to get it's value from common config (passed only options existing in defaults)
|
2292
|
+
showbuttons: true
|
1794
2293
|
};
|
1795
2294
|
|
1796
2295
|
$.extend($.fn.editabletypes, {abstractinput: AbstractInput});
|
@@ -1804,7 +2303,8 @@ List - abstract class for inputs that have source option loaded from js array or
|
|
1804
2303
|
@extends abstractinput
|
1805
2304
|
**/
|
1806
2305
|
(function ($) {
|
1807
|
-
|
2306
|
+
"use strict";
|
2307
|
+
|
1808
2308
|
var List = function (options) {
|
1809
2309
|
|
1810
2310
|
};
|
@@ -1813,11 +2313,9 @@ List - abstract class for inputs that have source option loaded from js array or
|
|
1813
2313
|
|
1814
2314
|
$.extend(List.prototype, {
|
1815
2315
|
render: function () {
|
1816
|
-
List.superclass.render.call(this);
|
1817
2316
|
var deferred = $.Deferred();
|
2317
|
+
|
1818
2318
|
this.error = null;
|
1819
|
-
this.sourceData = null;
|
1820
|
-
this.prependData = null;
|
1821
2319
|
this.onSourceReady(function () {
|
1822
2320
|
this.renderList();
|
1823
2321
|
deferred.resolve();
|
@@ -1833,20 +2331,24 @@ List - abstract class for inputs that have source option loaded from js array or
|
|
1833
2331
|
return null; //can't set value by text
|
1834
2332
|
},
|
1835
2333
|
|
1836
|
-
value2html: function (value, element, display) {
|
1837
|
-
var deferred = $.Deferred()
|
1838
|
-
|
1839
|
-
|
1840
|
-
|
1841
|
-
|
1842
|
-
|
1843
|
-
|
1844
|
-
|
1845
|
-
|
1846
|
-
|
1847
|
-
|
1848
|
-
|
1849
|
-
|
2334
|
+
value2html: function (value, element, display, response) {
|
2335
|
+
var deferred = $.Deferred(),
|
2336
|
+
success = function () {
|
2337
|
+
if(typeof display === 'function') {
|
2338
|
+
//custom display method
|
2339
|
+
display.call(element, value, this.sourceData, response);
|
2340
|
+
} else {
|
2341
|
+
this.value2htmlFinal(value, element);
|
2342
|
+
}
|
2343
|
+
deferred.resolve();
|
2344
|
+
};
|
2345
|
+
|
2346
|
+
//for null value just call success without loading source
|
2347
|
+
if(value === null) {
|
2348
|
+
success.call(this);
|
2349
|
+
} else {
|
2350
|
+
this.onSourceReady(success, function () { deferred.resolve(); });
|
2351
|
+
}
|
1850
2352
|
|
1851
2353
|
return deferred.promise();
|
1852
2354
|
},
|
@@ -1867,12 +2369,19 @@ List - abstract class for inputs that have source option loaded from js array or
|
|
1867
2369
|
error.call(this);
|
1868
2370
|
return;
|
1869
2371
|
}
|
2372
|
+
|
2373
|
+
var source = this.options.source;
|
2374
|
+
|
2375
|
+
//run source if it function
|
2376
|
+
if ($.isFunction(source)) {
|
2377
|
+
source = source.call(this.options.scope);
|
2378
|
+
}
|
1870
2379
|
|
1871
2380
|
//loading from url
|
1872
|
-
if (typeof
|
2381
|
+
if (typeof source === 'string') {
|
1873
2382
|
//try to get from cache
|
1874
2383
|
if(this.options.sourceCache) {
|
1875
|
-
var cacheID =
|
2384
|
+
var cacheID = source,
|
1876
2385
|
cache;
|
1877
2386
|
|
1878
2387
|
if (!$(document).data(cacheID)) {
|
@@ -1883,11 +2392,13 @@ List - abstract class for inputs that have source option loaded from js array or
|
|
1883
2392
|
//check for cached data
|
1884
2393
|
if (cache.loading === false && cache.sourceData) { //take source from cache
|
1885
2394
|
this.sourceData = cache.sourceData;
|
2395
|
+
this.doPrepend();
|
1886
2396
|
success.call(this);
|
1887
2397
|
return;
|
1888
2398
|
} else if (cache.loading === true) { //cache is loading, put callback in stack to be called later
|
1889
2399
|
cache.callbacks.push($.proxy(function () {
|
1890
2400
|
this.sourceData = cache.sourceData;
|
2401
|
+
this.doPrepend();
|
1891
2402
|
success.call(this);
|
1892
2403
|
}, this));
|
1893
2404
|
|
@@ -1903,10 +2414,9 @@ List - abstract class for inputs that have source option loaded from js array or
|
|
1903
2414
|
|
1904
2415
|
//loading sourceData from server
|
1905
2416
|
$.ajax({
|
1906
|
-
url:
|
2417
|
+
url: source,
|
1907
2418
|
type: 'get',
|
1908
2419
|
cache: false,
|
1909
|
-
data: this.options.name ? {name: this.options.name} : {},
|
1910
2420
|
dataType: 'json',
|
1911
2421
|
success: $.proxy(function (data) {
|
1912
2422
|
if(cache) {
|
@@ -1914,17 +2424,19 @@ List - abstract class for inputs that have source option loaded from js array or
|
|
1914
2424
|
}
|
1915
2425
|
this.sourceData = this.makeArray(data);
|
1916
2426
|
if($.isArray(this.sourceData)) {
|
1917
|
-
this.doPrepend();
|
1918
|
-
success.call(this);
|
1919
2427
|
if(cache) {
|
1920
2428
|
//store result in cache
|
1921
2429
|
cache.sourceData = this.sourceData;
|
1922
|
-
|
2430
|
+
//run success callbacks for other fields waiting for this source
|
2431
|
+
$.each(cache.callbacks, function () { this.call(); });
|
1923
2432
|
}
|
2433
|
+
this.doPrepend();
|
2434
|
+
success.call(this);
|
1924
2435
|
} else {
|
1925
2436
|
error.call(this);
|
1926
2437
|
if(cache) {
|
1927
|
-
|
2438
|
+
//run error callbacks for other fields waiting for this source
|
2439
|
+
$.each(cache.err_callbacks, function () { this.call(); });
|
1928
2440
|
}
|
1929
2441
|
}
|
1930
2442
|
}, this),
|
@@ -1938,7 +2450,8 @@ List - abstract class for inputs that have source option loaded from js array or
|
|
1938
2450
|
}, this)
|
1939
2451
|
});
|
1940
2452
|
} else { //options as json/array
|
1941
|
-
this.sourceData = this.makeArray(
|
2453
|
+
this.sourceData = this.makeArray(source);
|
2454
|
+
|
1942
2455
|
if($.isArray(this.sourceData)) {
|
1943
2456
|
this.doPrepend();
|
1944
2457
|
success.call(this);
|
@@ -1954,11 +2467,19 @@ List - abstract class for inputs that have source option loaded from js array or
|
|
1954
2467
|
}
|
1955
2468
|
|
1956
2469
|
if(!$.isArray(this.prependData)) {
|
2470
|
+
//run prepend if it is function (once)
|
2471
|
+
if ($.isFunction(this.options.prepend)) {
|
2472
|
+
this.options.prepend = this.options.prepend.call(this.options.scope);
|
2473
|
+
}
|
2474
|
+
|
1957
2475
|
//try parse json in single quotes
|
1958
2476
|
this.options.prepend = $.fn.editableutils.tryParseJson(this.options.prepend, true);
|
2477
|
+
|
2478
|
+
//convert prepend from string to object
|
1959
2479
|
if (typeof this.options.prepend === 'string') {
|
1960
2480
|
this.options.prepend = {'': this.options.prepend};
|
1961
|
-
}
|
2481
|
+
}
|
2482
|
+
|
1962
2483
|
this.prependData = this.makeArray(this.options.prepend);
|
1963
2484
|
}
|
1964
2485
|
|
@@ -1985,35 +2506,45 @@ List - abstract class for inputs that have source option loaded from js array or
|
|
1985
2506
|
* convert data to array suitable for sourceData, e.g. [{value: 1, text: 'abc'}, {...}]
|
1986
2507
|
*/
|
1987
2508
|
makeArray: function(data) {
|
1988
|
-
var count, obj, result = [],
|
2509
|
+
var count, obj, result = [], item, iterateItem;
|
1989
2510
|
if(!data || typeof data === 'string') {
|
1990
2511
|
return null;
|
1991
2512
|
}
|
1992
2513
|
|
1993
2514
|
if($.isArray(data)) { //array
|
1994
|
-
|
2515
|
+
/*
|
2516
|
+
function to iterate inside item of array if item is object.
|
2517
|
+
Caclulates count of keys in item and store in obj.
|
2518
|
+
*/
|
2519
|
+
iterateItem = function (k, v) {
|
1995
2520
|
obj = {value: k, text: v};
|
1996
2521
|
if(count++ >= 2) {
|
1997
|
-
return false;// exit each if
|
2522
|
+
return false;// exit from `each` if item has more than one key.
|
1998
2523
|
}
|
1999
2524
|
};
|
2000
2525
|
|
2001
2526
|
for(var i = 0; i < data.length; i++) {
|
2002
|
-
|
2003
|
-
|
2004
|
-
|
2005
|
-
|
2527
|
+
item = data[i];
|
2528
|
+
if(typeof item === 'object') {
|
2529
|
+
count = 0; //count of keys inside item
|
2530
|
+
$.each(item, iterateItem);
|
2531
|
+
//case: [{val1: 'text1'}, {val2: 'text2} ...]
|
2532
|
+
if(count === 1) {
|
2006
2533
|
result.push(obj);
|
2007
|
-
|
2008
|
-
|
2009
|
-
|
2010
|
-
|
2534
|
+
//case: [{value: 1, text: 'text1'}, {value: 2, text: 'text2'}, ...]
|
2535
|
+
} else if(count > 1) {
|
2536
|
+
//removed check of existance: item.hasOwnProperty('value') && item.hasOwnProperty('text')
|
2537
|
+
if(item.children) {
|
2538
|
+
item.children = this.makeArray(item.children);
|
2539
|
+
}
|
2540
|
+
result.push(item);
|
2011
2541
|
}
|
2012
2542
|
} else {
|
2013
|
-
|
2543
|
+
//case: ['text1', 'text2' ...]
|
2544
|
+
result.push({value: item, text: item});
|
2014
2545
|
}
|
2015
2546
|
}
|
2016
|
-
} else { //
|
2547
|
+
} else { //case: {val1: 'text1', val2: 'text2, ...}
|
2017
2548
|
$.each(data, function (k, v) {
|
2018
2549
|
result.push({value: k, text: v});
|
2019
2550
|
});
|
@@ -2021,41 +2552,45 @@ List - abstract class for inputs that have source option loaded from js array or
|
|
2021
2552
|
return result;
|
2022
2553
|
},
|
2023
2554
|
|
2024
|
-
|
2025
|
-
|
2026
|
-
if(
|
2027
|
-
|
2028
|
-
/*jshint eqeqeq: false*/
|
2029
|
-
if(this.sourceData[i].value == val) {
|
2030
|
-
/*jshint eqeqeq: true*/
|
2031
|
-
return this.sourceData[i];
|
2032
|
-
}
|
2033
|
-
}
|
2555
|
+
option: function(key, value) {
|
2556
|
+
this.options[key] = value;
|
2557
|
+
if(key === 'source') {
|
2558
|
+
this.sourceData = null;
|
2034
2559
|
}
|
2560
|
+
if(key === 'prepend') {
|
2561
|
+
this.prependData = null;
|
2562
|
+
}
|
2035
2563
|
}
|
2036
2564
|
|
2037
2565
|
});
|
2038
2566
|
|
2039
2567
|
List.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, {
|
2040
2568
|
/**
|
2041
|
-
Source data for list.
|
2042
|
-
|
2043
|
-
For compability
|
2044
|
-
|
2569
|
+
Source data for list.
|
2570
|
+
If **array** - it should be in format: `[{value: 1, text: "text1"}, {value: 2, text: "text2"}, ...]`
|
2571
|
+
For compability, object format is also supported: `{"1": "text1", "2": "text2" ...}` but it does not guarantee elements order.
|
2572
|
+
|
2573
|
+
If **string** - considered ajax url to load items. In that case results will be cached for fields with the same source and name. See also `sourceCache` option.
|
2574
|
+
|
2575
|
+
If **function**, it should return data in format above (since 1.4.0).
|
2045
2576
|
|
2577
|
+
Since 1.4.1 key `children` supported to render OPTGROUP (for **select** input only).
|
2578
|
+
`[{text: "group1", children: [{value: 1, text: "text1"}, {value: 2, text: "text2"}]}, ...]`
|
2579
|
+
|
2580
|
+
|
2046
2581
|
@property source
|
2047
|
-
@type string|array|object
|
2582
|
+
@type string | array | object | function
|
2048
2583
|
@default null
|
2049
2584
|
**/
|
2050
|
-
source:null,
|
2585
|
+
source: null,
|
2051
2586
|
/**
|
2052
2587
|
Data automatically prepended to the beginning of dropdown list.
|
2053
2588
|
|
2054
2589
|
@property prepend
|
2055
|
-
@type string|array|object
|
2590
|
+
@type string | array | object | function
|
2056
2591
|
@default false
|
2057
2592
|
**/
|
2058
|
-
prepend:false,
|
2593
|
+
prepend: false,
|
2059
2594
|
/**
|
2060
2595
|
Error message when list cannot be loaded (e.g. ajax error)
|
2061
2596
|
|
@@ -2065,8 +2600,8 @@ List - abstract class for inputs that have source option loaded from js array or
|
|
2065
2600
|
**/
|
2066
2601
|
sourceError: 'Error when loading list',
|
2067
2602
|
/**
|
2068
|
-
if <code>true</code> and source is **string url** - results will be cached for fields with the same source
|
2069
|
-
Usefull for editable
|
2603
|
+
if <code>true</code> and source is **string url** - results will be cached for fields with the same source.
|
2604
|
+
Usefull for editable column in grid to prevent extra requests.
|
2070
2605
|
|
2071
2606
|
@property sourceCache
|
2072
2607
|
@type boolean
|
@@ -2078,7 +2613,8 @@ List - abstract class for inputs that have source option loaded from js array or
|
|
2078
2613
|
|
2079
2614
|
$.fn.editabletypes.list = List;
|
2080
2615
|
|
2081
|
-
}(window.jQuery));
|
2616
|
+
}(window.jQuery));
|
2617
|
+
|
2082
2618
|
/**
|
2083
2619
|
Text input
|
2084
2620
|
|
@@ -2097,6 +2633,8 @@ $(function(){
|
|
2097
2633
|
</script>
|
2098
2634
|
**/
|
2099
2635
|
(function ($) {
|
2636
|
+
"use strict";
|
2637
|
+
|
2100
2638
|
var Text = function (options) {
|
2101
2639
|
this.init('text', options, Text.defaults);
|
2102
2640
|
};
|
@@ -2104,12 +2642,83 @@ $(function(){
|
|
2104
2642
|
$.fn.editableutils.inherit(Text, $.fn.editabletypes.abstractinput);
|
2105
2643
|
|
2106
2644
|
$.extend(Text.prototype, {
|
2645
|
+
render: function() {
|
2646
|
+
this.renderClear();
|
2647
|
+
this.setClass();
|
2648
|
+
this.setAttr('placeholder');
|
2649
|
+
},
|
2650
|
+
|
2107
2651
|
activate: function() {
|
2108
2652
|
if(this.$input.is(':visible')) {
|
2109
2653
|
this.$input.focus();
|
2110
2654
|
$.fn.editableutils.setCursorPosition(this.$input.get(0), this.$input.val().length);
|
2655
|
+
if(this.toggleClear) {
|
2656
|
+
this.toggleClear();
|
2657
|
+
}
|
2658
|
+
}
|
2659
|
+
},
|
2660
|
+
|
2661
|
+
//render clear button
|
2662
|
+
renderClear: function() {
|
2663
|
+
if (this.options.clear) {
|
2664
|
+
this.$clear = $('<span class="editable-clear-x"></span>');
|
2665
|
+
this.$input.after(this.$clear)
|
2666
|
+
.css('padding-right', 24)
|
2667
|
+
.keyup($.proxy(function(e) {
|
2668
|
+
//arrows, enter, tab, etc
|
2669
|
+
if(~$.inArray(e.keyCode, [40,38,9,13,27])) {
|
2670
|
+
return;
|
2671
|
+
}
|
2672
|
+
|
2673
|
+
clearTimeout(this.t);
|
2674
|
+
var that = this;
|
2675
|
+
this.t = setTimeout(function() {
|
2676
|
+
that.toggleClear(e);
|
2677
|
+
}, 100);
|
2678
|
+
|
2679
|
+
}, this))
|
2680
|
+
.parent().css('position', 'relative');
|
2681
|
+
|
2682
|
+
this.$clear.click($.proxy(this.clear, this));
|
2683
|
+
}
|
2684
|
+
},
|
2685
|
+
|
2686
|
+
postrender: function() {
|
2687
|
+
/*
|
2688
|
+
//now `clear` is positioned via css
|
2689
|
+
if(this.$clear) {
|
2690
|
+
//can position clear button only here, when form is shown and height can be calculated
|
2691
|
+
// var h = this.$input.outerHeight(true) || 20,
|
2692
|
+
var h = this.$clear.parent().height(),
|
2693
|
+
delta = (h - this.$clear.height()) / 2;
|
2694
|
+
|
2695
|
+
//this.$clear.css({bottom: delta, right: delta});
|
2696
|
+
}
|
2697
|
+
*/
|
2698
|
+
},
|
2699
|
+
|
2700
|
+
//show / hide clear button
|
2701
|
+
toggleClear: function(e) {
|
2702
|
+
if(!this.$clear) {
|
2703
|
+
return;
|
2111
2704
|
}
|
2112
|
-
|
2705
|
+
|
2706
|
+
var len = this.$input.val().length,
|
2707
|
+
visible = this.$clear.is(':visible');
|
2708
|
+
|
2709
|
+
if(len && !visible) {
|
2710
|
+
this.$clear.show();
|
2711
|
+
}
|
2712
|
+
|
2713
|
+
if(!len && visible) {
|
2714
|
+
this.$clear.hide();
|
2715
|
+
}
|
2716
|
+
},
|
2717
|
+
|
2718
|
+
clear: function() {
|
2719
|
+
this.$clear.hide();
|
2720
|
+
this.$input.val('').focus();
|
2721
|
+
}
|
2113
2722
|
});
|
2114
2723
|
|
2115
2724
|
Text.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, {
|
@@ -2125,7 +2734,16 @@ $(function(){
|
|
2125
2734
|
@type string
|
2126
2735
|
@default null
|
2127
2736
|
**/
|
2128
|
-
placeholder: null
|
2737
|
+
placeholder: null,
|
2738
|
+
|
2739
|
+
/**
|
2740
|
+
Whether to show `clear` button
|
2741
|
+
|
2742
|
+
@property clear
|
2743
|
+
@type boolean
|
2744
|
+
@default true
|
2745
|
+
**/
|
2746
|
+
clear: true
|
2129
2747
|
});
|
2130
2748
|
|
2131
2749
|
$.fn.editabletypes.text = Text;
|
@@ -2144,13 +2762,15 @@ Textarea input
|
|
2144
2762
|
$(function(){
|
2145
2763
|
$('#comments').editable({
|
2146
2764
|
url: '/post',
|
2147
|
-
title: 'Enter comments'
|
2765
|
+
title: 'Enter comments',
|
2766
|
+
rows: 10
|
2148
2767
|
});
|
2149
2768
|
});
|
2150
2769
|
</script>
|
2151
2770
|
**/
|
2152
2771
|
(function ($) {
|
2153
|
-
|
2772
|
+
"use strict";
|
2773
|
+
|
2154
2774
|
var Textarea = function (options) {
|
2155
2775
|
this.init('textarea', options, Textarea.defaults);
|
2156
2776
|
};
|
@@ -2159,8 +2779,10 @@ $(function(){
|
|
2159
2779
|
|
2160
2780
|
$.extend(Textarea.prototype, {
|
2161
2781
|
render: function () {
|
2162
|
-
|
2163
|
-
|
2782
|
+
this.setClass();
|
2783
|
+
this.setAttr('placeholder');
|
2784
|
+
this.setAttr('rows');
|
2785
|
+
|
2164
2786
|
//ctrl + enter
|
2165
2787
|
this.$input.keydown(function (e) {
|
2166
2788
|
if (e.ctrlKey && e.which === 13) {
|
@@ -2185,43 +2807,56 @@ $(function(){
|
|
2185
2807
|
if(!html) {
|
2186
2808
|
return '';
|
2187
2809
|
}
|
2810
|
+
|
2811
|
+
var regex = new RegExp(String.fromCharCode(10), 'g');
|
2188
2812
|
var lines = html.split(/<br\s*\/?>/i);
|
2189
2813
|
for (var i = 0; i < lines.length; i++) {
|
2190
|
-
|
2814
|
+
var text = $('<div>').html(lines[i]).text();
|
2815
|
+
|
2816
|
+
// Remove newline characters (\n) to avoid them being converted by value2html() method
|
2817
|
+
// thus adding extra <br> tags
|
2818
|
+
text = text.replace(regex, '');
|
2819
|
+
|
2820
|
+
lines[i] = text;
|
2191
2821
|
}
|
2192
|
-
return lines.join("\n");
|
2193
|
-
},
|
2822
|
+
return lines.join("\n");
|
2823
|
+
},
|
2194
2824
|
|
2195
2825
|
activate: function() {
|
2196
|
-
|
2197
|
-
|
2198
|
-
this.$input.focus();
|
2199
|
-
}
|
2200
|
-
}
|
2826
|
+
$.fn.editabletypes.text.prototype.activate.call(this);
|
2827
|
+
}
|
2201
2828
|
});
|
2202
2829
|
|
2203
2830
|
Textarea.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, {
|
2204
2831
|
/**
|
2205
|
-
@property tpl
|
2832
|
+
@property tpl
|
2206
2833
|
@default <textarea></textarea>
|
2207
|
-
**/
|
2834
|
+
**/
|
2208
2835
|
tpl:'<textarea></textarea>',
|
2209
2836
|
/**
|
2210
|
-
@property inputclass
|
2837
|
+
@property inputclass
|
2211
2838
|
@default input-large
|
2212
|
-
**/
|
2839
|
+
**/
|
2213
2840
|
inputclass: 'input-large',
|
2214
2841
|
/**
|
2215
2842
|
Placeholder attribute of input. Shown when input is empty.
|
2216
2843
|
|
2217
|
-
@property placeholder
|
2844
|
+
@property placeholder
|
2218
2845
|
@type string
|
2219
2846
|
@default null
|
2220
|
-
**/
|
2221
|
-
placeholder: null
|
2847
|
+
**/
|
2848
|
+
placeholder: null,
|
2849
|
+
/**
|
2850
|
+
Number of rows in textarea
|
2851
|
+
|
2852
|
+
@property rows
|
2853
|
+
@type integer
|
2854
|
+
@default 7
|
2855
|
+
**/
|
2856
|
+
rows: 7
|
2222
2857
|
});
|
2223
2858
|
|
2224
|
-
$.fn.editabletypes.textarea = Textarea;
|
2859
|
+
$.fn.editabletypes.textarea = Textarea;
|
2225
2860
|
|
2226
2861
|
}(window.jQuery));
|
2227
2862
|
|
@@ -2242,13 +2877,13 @@ $(function(){
|
|
2242
2877
|
{value: 2, text: 'Blocked'},
|
2243
2878
|
{value: 3, text: 'Deleted'}
|
2244
2879
|
]
|
2245
|
-
}
|
2246
2880
|
});
|
2247
2881
|
});
|
2248
2882
|
</script>
|
2249
2883
|
**/
|
2250
2884
|
(function ($) {
|
2251
|
-
|
2885
|
+
"use strict";
|
2886
|
+
|
2252
2887
|
var Select = function (options) {
|
2253
2888
|
this.init('select', options, Select.defaults);
|
2254
2889
|
};
|
@@ -2257,13 +2892,24 @@ $(function(){
|
|
2257
2892
|
|
2258
2893
|
$.extend(Select.prototype, {
|
2259
2894
|
renderList: function() {
|
2260
|
-
|
2261
|
-
return;
|
2262
|
-
}
|
2895
|
+
this.$input.empty();
|
2263
2896
|
|
2264
|
-
|
2265
|
-
|
2266
|
-
|
2897
|
+
var fillItems = function($el, data) {
|
2898
|
+
if($.isArray(data)) {
|
2899
|
+
for(var i=0; i<data.length; i++) {
|
2900
|
+
if(data[i].children) {
|
2901
|
+
$el.append(fillItems($('<optgroup>', {label: data[i].text}), data[i].children));
|
2902
|
+
} else {
|
2903
|
+
$el.append($('<option>', {value: data[i].value}).text(data[i].text));
|
2904
|
+
}
|
2905
|
+
}
|
2906
|
+
}
|
2907
|
+
return $el;
|
2908
|
+
};
|
2909
|
+
|
2910
|
+
fillItems(this.$input, this.sourceData);
|
2911
|
+
|
2912
|
+
this.setClass();
|
2267
2913
|
|
2268
2914
|
//enter submit
|
2269
2915
|
this.$input.on('keydown.editable', function (e) {
|
@@ -2274,11 +2920,14 @@ $(function(){
|
|
2274
2920
|
},
|
2275
2921
|
|
2276
2922
|
value2htmlFinal: function(value, element) {
|
2277
|
-
var text = '',
|
2278
|
-
|
2279
|
-
|
2923
|
+
var text = '',
|
2924
|
+
items = $.fn.editableutils.itemsByValue(value, this.sourceData);
|
2925
|
+
|
2926
|
+
if(items.length) {
|
2927
|
+
text = items[0].text;
|
2280
2928
|
}
|
2281
|
-
|
2929
|
+
|
2930
|
+
$(element).text(text);
|
2282
2931
|
},
|
2283
2932
|
|
2284
2933
|
autosubmit: function() {
|
@@ -2298,7 +2947,8 @@ $(function(){
|
|
2298
2947
|
|
2299
2948
|
$.fn.editabletypes.select = Select;
|
2300
2949
|
|
2301
|
-
}(window.jQuery));
|
2950
|
+
}(window.jQuery));
|
2951
|
+
|
2302
2952
|
/**
|
2303
2953
|
List of checkboxes.
|
2304
2954
|
Internally value stored as javascript array of values.
|
@@ -2317,13 +2967,13 @@ $(function(){
|
|
2317
2967
|
{value: 2, text: 'option2'},
|
2318
2968
|
{value: 3, text: 'option3'}
|
2319
2969
|
]
|
2320
|
-
}
|
2321
2970
|
});
|
2322
2971
|
});
|
2323
2972
|
</script>
|
2324
2973
|
**/
|
2325
2974
|
(function ($) {
|
2326
|
-
|
2975
|
+
"use strict";
|
2976
|
+
|
2327
2977
|
var Checklist = function (options) {
|
2328
2978
|
this.init('checklist', options, Checklist.defaults);
|
2329
2979
|
};
|
@@ -2333,6 +2983,9 @@ $(function(){
|
|
2333
2983
|
$.extend(Checklist.prototype, {
|
2334
2984
|
renderList: function() {
|
2335
2985
|
var $label, $div;
|
2986
|
+
|
2987
|
+
this.$tpl.empty();
|
2988
|
+
|
2336
2989
|
if(!$.isArray(this.sourceData)) {
|
2337
2990
|
return;
|
2338
2991
|
}
|
@@ -2340,13 +2993,15 @@ $(function(){
|
|
2340
2993
|
for(var i=0; i<this.sourceData.length; i++) {
|
2341
2994
|
$label = $('<label>').append($('<input>', {
|
2342
2995
|
type: 'checkbox',
|
2343
|
-
value: this.sourceData[i].value
|
2344
|
-
name: this.options.name
|
2996
|
+
value: this.sourceData[i].value
|
2345
2997
|
}))
|
2346
2998
|
.append($('<span>').text(' '+this.sourceData[i].text));
|
2347
2999
|
|
2348
|
-
$('<div>').append($label).appendTo(this.$
|
3000
|
+
$('<div>').append($label).appendTo(this.$tpl);
|
2349
3001
|
}
|
3002
|
+
|
3003
|
+
this.$input = this.$tpl.find('input[type="checkbox"]');
|
3004
|
+
this.setClass();
|
2350
3005
|
},
|
2351
3006
|
|
2352
3007
|
value2str: function(value) {
|
@@ -2361,23 +3016,24 @@ $(function(){
|
|
2361
3016
|
value = str.split(reg);
|
2362
3017
|
} else if($.isArray(str)) {
|
2363
3018
|
value = str;
|
3019
|
+
} else {
|
3020
|
+
value = [str];
|
2364
3021
|
}
|
2365
3022
|
return value;
|
2366
3023
|
},
|
2367
3024
|
|
2368
3025
|
//set checked on required checkboxes
|
2369
3026
|
value2input: function(value) {
|
2370
|
-
|
2371
|
-
$checks.removeAttr('checked');
|
3027
|
+
this.$input.prop('checked', false);
|
2372
3028
|
if($.isArray(value) && value.length) {
|
2373
|
-
|
3029
|
+
this.$input.each(function(i, el) {
|
2374
3030
|
var $el = $(el);
|
2375
3031
|
// cannot use $.inArray as it performs strict comparison
|
2376
3032
|
$.each(value, function(j, val){
|
2377
3033
|
/*jslint eqeq: true*/
|
2378
3034
|
if($el.val() == val) {
|
2379
3035
|
/*jslint eqeq: false*/
|
2380
|
-
$el.
|
3036
|
+
$el.prop('checked', true);
|
2381
3037
|
}
|
2382
3038
|
});
|
2383
3039
|
});
|
@@ -2386,7 +3042,7 @@ $(function(){
|
|
2386
3042
|
|
2387
3043
|
input2value: function() {
|
2388
3044
|
var checked = [];
|
2389
|
-
this.$input.
|
3045
|
+
this.$input.filter(':checked').each(function(i, el) {
|
2390
3046
|
checked.push($(el).val());
|
2391
3047
|
});
|
2392
3048
|
return checked;
|
@@ -2395,11 +3051,8 @@ $(function(){
|
|
2395
3051
|
//collect text of checked boxes
|
2396
3052
|
value2htmlFinal: function(value, element) {
|
2397
3053
|
var html = [],
|
2398
|
-
|
2399
|
-
|
2400
|
-
return $.grep(value, function(v){ return v == o.value; }).length;
|
2401
|
-
});
|
2402
|
-
/*jslint eqeq: false*/
|
3054
|
+
checked = $.fn.editableutils.itemsByValue(value, this.sourceData);
|
3055
|
+
|
2403
3056
|
if(checked.length) {
|
2404
3057
|
$.each(checked, function(i, v) { html.push($.fn.editableutils.escape(v.text)); });
|
2405
3058
|
$(element).html(html.join('<br>'));
|
@@ -2409,11 +3062,11 @@ $(function(){
|
|
2409
3062
|
},
|
2410
3063
|
|
2411
3064
|
activate: function() {
|
2412
|
-
this.$input.
|
3065
|
+
this.$input.first().focus();
|
2413
3066
|
},
|
2414
3067
|
|
2415
3068
|
autosubmit: function() {
|
2416
|
-
this.$input.
|
3069
|
+
this.$input.on('keydown', function(e){
|
2417
3070
|
if (e.which === 13) {
|
2418
3071
|
$(this).closest('form').submit();
|
2419
3072
|
}
|
@@ -2426,21 +3079,21 @@ $(function(){
|
|
2426
3079
|
@property tpl
|
2427
3080
|
@default <div></div>
|
2428
3081
|
**/
|
2429
|
-
tpl:'<div></div>',
|
3082
|
+
tpl:'<div class="editable-checklist"></div>',
|
2430
3083
|
|
2431
3084
|
/**
|
2432
3085
|
@property inputclass
|
2433
3086
|
@type string
|
2434
|
-
@default
|
3087
|
+
@default null
|
2435
3088
|
**/
|
2436
|
-
inputclass:
|
3089
|
+
inputclass: null,
|
2437
3090
|
|
2438
3091
|
/**
|
2439
|
-
Separator of values when reading from
|
3092
|
+
Separator of values when reading from `data-value` attribute
|
2440
3093
|
|
2441
3094
|
@property separator
|
2442
3095
|
@type string
|
2443
|
-
@default ',
|
3096
|
+
@default ','
|
2444
3097
|
**/
|
2445
3098
|
separator: ','
|
2446
3099
|
});
|
@@ -2490,6 +3143,8 @@ $(function(){
|
|
2490
3143
|
Password
|
2491
3144
|
*/
|
2492
3145
|
(function ($) {
|
3146
|
+
"use strict";
|
3147
|
+
|
2493
3148
|
var Password = function (options) {
|
2494
3149
|
this.init('password', options, Password.defaults);
|
2495
3150
|
};
|
@@ -2519,6 +3174,8 @@ Password
|
|
2519
3174
|
Email
|
2520
3175
|
*/
|
2521
3176
|
(function ($) {
|
3177
|
+
"use strict";
|
3178
|
+
|
2522
3179
|
var Email = function (options) {
|
2523
3180
|
this.init('email', options, Email.defaults);
|
2524
3181
|
};
|
@@ -2534,6 +3191,8 @@ Email
|
|
2534
3191
|
Url
|
2535
3192
|
*/
|
2536
3193
|
(function ($) {
|
3194
|
+
"use strict";
|
3195
|
+
|
2537
3196
|
var Url = function (options) {
|
2538
3197
|
this.init('url', options, Url.defaults);
|
2539
3198
|
};
|
@@ -2549,6 +3208,8 @@ Url
|
|
2549
3208
|
Tel
|
2550
3209
|
*/
|
2551
3210
|
(function ($) {
|
3211
|
+
"use strict";
|
3212
|
+
|
2552
3213
|
var Tel = function (options) {
|
2553
3214
|
this.init('tel', options, Tel.defaults);
|
2554
3215
|
};
|
@@ -2564,6 +3225,8 @@ Tel
|
|
2564
3225
|
Number
|
2565
3226
|
*/
|
2566
3227
|
(function ($) {
|
3228
|
+
"use strict";
|
3229
|
+
|
2567
3230
|
var NumberInput = function (options) {
|
2568
3231
|
this.init('number', options, NumberInput.defaults);
|
2569
3232
|
};
|
@@ -2571,19 +3234,24 @@ Number
|
|
2571
3234
|
$.extend(NumberInput.prototype, {
|
2572
3235
|
render: function () {
|
2573
3236
|
NumberInput.superclass.render.call(this);
|
2574
|
-
|
2575
|
-
|
2576
|
-
|
2577
|
-
|
2578
|
-
|
2579
|
-
if
|
2580
|
-
|
3237
|
+
this.setAttr('min');
|
3238
|
+
this.setAttr('max');
|
3239
|
+
this.setAttr('step');
|
3240
|
+
},
|
3241
|
+
postrender: function() {
|
3242
|
+
if(this.$clear) {
|
3243
|
+
//increase right ffset for up/down arrows
|
3244
|
+
this.$clear.css({right: 24});
|
3245
|
+
/*
|
3246
|
+
//can position clear button only here, when form is shown and height can be calculated
|
3247
|
+
var h = this.$input.outerHeight(true) || 20,
|
3248
|
+
delta = (h - this.$clear.height()) / 2;
|
3249
|
+
|
3250
|
+
//add 12px to offset right for up/down arrows
|
3251
|
+
this.$clear.css({top: delta, right: delta + 16});
|
3252
|
+
*/
|
2581
3253
|
}
|
2582
|
-
|
2583
|
-
if (this.options.step !== null) {
|
2584
|
-
this.$input.attr('step', this.options.step);
|
2585
|
-
}
|
2586
|
-
}
|
3254
|
+
}
|
2587
3255
|
});
|
2588
3256
|
NumberInput.defaults = $.extend({}, $.fn.editabletypes.text.defaults, {
|
2589
3257
|
tpl: '<input type="number">',
|
@@ -2600,35 +3268,27 @@ Number
|
|
2600
3268
|
Range (inherit from number)
|
2601
3269
|
*/
|
2602
3270
|
(function ($) {
|
3271
|
+
"use strict";
|
3272
|
+
|
2603
3273
|
var Range = function (options) {
|
2604
3274
|
this.init('range', options, Range.defaults);
|
2605
3275
|
};
|
2606
3276
|
$.fn.editableutils.inherit(Range, $.fn.editabletypes.number);
|
2607
3277
|
$.extend(Range.prototype, {
|
2608
3278
|
render: function () {
|
2609
|
-
this.$input =
|
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
|
-
}
|
3279
|
+
this.$input = this.$tpl.filter('input');
|
2617
3280
|
|
2618
|
-
|
2619
|
-
|
2620
|
-
|
2621
|
-
|
2622
|
-
if (this.options.step !== null) {
|
2623
|
-
$slider.attr('step', this.options.step);
|
2624
|
-
}
|
3281
|
+
this.setClass();
|
3282
|
+
this.setAttr('min');
|
3283
|
+
this.setAttr('max');
|
3284
|
+
this.setAttr('step');
|
2625
3285
|
|
2626
|
-
|
3286
|
+
this.$input.on('input', function(){
|
2627
3287
|
$(this).siblings('output').text($(this).val());
|
2628
3288
|
});
|
2629
3289
|
},
|
2630
3290
|
activate: function() {
|
2631
|
-
this.$input.
|
3291
|
+
this.$input.focus();
|
2632
3292
|
}
|
2633
3293
|
});
|
2634
3294
|
Range.defaults = $.extend({}, $.fn.editabletypes.number.defaults, {
|
@@ -2638,41 +3298,927 @@ Range (inherit from number)
|
|
2638
3298
|
$.fn.editabletypes.range = Range;
|
2639
3299
|
}(window.jQuery));
|
2640
3300
|
/**
|
2641
|
-
|
2642
|
-
|
2643
|
-
|
2644
|
-
|
3301
|
+
Select2 input. Based on amazing work of Igor Vaynberg https://github.com/ivaynberg/select2.
|
3302
|
+
Please see [original docs](http://ivaynberg.github.com/select2) for detailed description and options.
|
3303
|
+
You should manually include select2 distributive:
|
3304
|
+
|
3305
|
+
<link href="select2/select2.css" rel="stylesheet" type="text/css"></link>
|
3306
|
+
<script src="select2/select2.js"></script>
|
3307
|
+
|
3308
|
+
For make it **Bootstrap-styled** you can use css from [here](https://github.com/t0m/select2-bootstrap-css):
|
3309
|
+
|
3310
|
+
<link href="select2-bootstrap.css" rel="stylesheet" type="text/css"></link>
|
3311
|
+
|
3312
|
+
**Note:** currently `ajax` source for select2 is not supported, as it's not possible to load it in closed select2 state.
|
3313
|
+
The solution is to load source manually and assign statically.
|
3314
|
+
|
3315
|
+
@class select2
|
3316
|
+
@extends abstractinput
|
3317
|
+
@since 1.4.1
|
3318
|
+
@final
|
3319
|
+
@example
|
3320
|
+
<a href="#" id="country" data-type="select2" data-pk="1" data-value="ru" data-url="/post" data-original-title="Select country"></a>
|
3321
|
+
<script>
|
3322
|
+
$(function(){
|
3323
|
+
$('#country').editable({
|
3324
|
+
source: [
|
3325
|
+
{id: 'gb', text: 'Great Britain'},
|
3326
|
+
{id: 'us', text: 'United States'},
|
3327
|
+
{id: 'ru', text: 'Russia'}
|
3328
|
+
],
|
3329
|
+
select2: {
|
3330
|
+
multiple: true
|
3331
|
+
}
|
3332
|
+
});
|
3333
|
+
});
|
3334
|
+
</script>
|
3335
|
+
**/
|
2645
3336
|
(function ($) {
|
3337
|
+
"use strict";
|
2646
3338
|
|
2647
|
-
|
2648
|
-
|
2649
|
-
|
2650
|
-
|
2651
|
-
|
2652
|
-
initContainer: function(){
|
2653
|
-
this.handlePlacement();
|
2654
|
-
|
2655
|
-
$.extend(this.containerOptions, {
|
2656
|
-
showOn: 'none',
|
2657
|
-
content: '',
|
2658
|
-
alignTo: 'target'
|
2659
|
-
});
|
2660
|
-
|
2661
|
-
this.call(this.containerOptions);
|
2662
|
-
|
2663
|
-
var $content = $('<div>')
|
2664
|
-
.append($('<label>').text(this.options.title || this.$element.data( "title") || this.$element.data( "originalTitle")))
|
2665
|
-
.append(this.initForm());
|
2666
|
-
|
2667
|
-
this.call('update', $content);
|
2668
|
-
},
|
3339
|
+
var Constructor = function (options) {
|
3340
|
+
this.init('select2', options, Constructor.defaults);
|
3341
|
+
|
3342
|
+
options.select2 = options.select2 || {};
|
2669
3343
|
|
2670
|
-
|
2671
|
-
|
3344
|
+
var that = this,
|
3345
|
+
mixin = { //mixin to select2 options
|
3346
|
+
placeholder: options.placeholder
|
3347
|
+
};
|
3348
|
+
|
3349
|
+
//detect whether it is multi-valued
|
3350
|
+
this.isMultiple = options.select2.tags || options.select2.multiple;
|
3351
|
+
|
3352
|
+
//if not `tags` mode, we need define initSelection to set data from source
|
3353
|
+
if(!options.select2.tags) {
|
3354
|
+
if(options.source) {
|
3355
|
+
mixin.data = options.source;
|
3356
|
+
}
|
3357
|
+
|
3358
|
+
//this function can be defaulted in seletc2. See https://github.com/ivaynberg/select2/issues/710
|
3359
|
+
mixin.initSelection = function (element, callback) {
|
3360
|
+
//temp: try update results
|
3361
|
+
/*
|
3362
|
+
if(options.select2 && options.select2.ajax) {
|
3363
|
+
console.log('attached');
|
3364
|
+
var original = $(element).data('select2').postprocessResults;
|
3365
|
+
console.log(original);
|
3366
|
+
$(element).data('select2').postprocessResults = function(data, initial) {
|
3367
|
+
console.log('postprocess');
|
3368
|
+
// this.element.triggerHandler('loaded', [data]);
|
3369
|
+
original.apply(this, arguments);
|
3370
|
+
}
|
3371
|
+
|
3372
|
+
// $(element).on('loaded', function(){console.log('loaded');});
|
3373
|
+
$(element).data('select2').updateResults(true);
|
3374
|
+
}
|
3375
|
+
*/
|
3376
|
+
|
3377
|
+
var val = that.str2value(element.val()),
|
3378
|
+
data = $.fn.editableutils.itemsByValue(val, mixin.data, 'id');
|
3379
|
+
|
3380
|
+
//for single-valued mode should not use array. Take first element instead.
|
3381
|
+
if($.isArray(data) && data.length && !that.isMultiple) {
|
3382
|
+
data = data[0];
|
3383
|
+
}
|
3384
|
+
|
3385
|
+
callback(data);
|
3386
|
+
};
|
3387
|
+
}
|
3388
|
+
|
3389
|
+
//overriding objects in config (as by default jQuery extend() is not recursive)
|
3390
|
+
this.options.select2 = $.extend({}, Constructor.defaults.select2, mixin, options.select2);
|
3391
|
+
};
|
3392
|
+
|
3393
|
+
$.fn.editableutils.inherit(Constructor, $.fn.editabletypes.abstractinput);
|
3394
|
+
|
3395
|
+
$.extend(Constructor.prototype, {
|
3396
|
+
render: function() {
|
3397
|
+
this.setClass();
|
3398
|
+
//apply select2
|
3399
|
+
this.$input.select2(this.options.select2);
|
3400
|
+
|
3401
|
+
//when data is loaded via ajax, we need to know when it's done
|
3402
|
+
if('ajax' in this.options.select2) {
|
3403
|
+
/*
|
3404
|
+
console.log('attached');
|
3405
|
+
var original = this.$input.data('select2').postprocessResults;
|
3406
|
+
this.$input.data('select2').postprocessResults = function(data, initial) {
|
3407
|
+
this.element.triggerHandler('loaded', [data]);
|
3408
|
+
original.apply(this, arguments);
|
3409
|
+
}
|
3410
|
+
*/
|
3411
|
+
}
|
3412
|
+
|
3413
|
+
|
3414
|
+
//trigger resize of editableform to re-position container in multi-valued mode
|
3415
|
+
if(this.isMultiple) {
|
3416
|
+
this.$input.on('change', function() {
|
3417
|
+
$(this).closest('form').parent().triggerHandler('resize');
|
3418
|
+
});
|
3419
|
+
}
|
3420
|
+
},
|
3421
|
+
|
3422
|
+
value2html: function(value, element) {
|
3423
|
+
var text = '', data;
|
3424
|
+
if(this.$input) { //called when submitting form and select2 already exists
|
3425
|
+
data = this.$input.select2('data');
|
3426
|
+
} else { //on init (autotext)
|
3427
|
+
//here select2 instance not created yet and data may be even not loaded.
|
3428
|
+
//we can check data/tags property of select config and if exist lookup text
|
3429
|
+
if(this.options.select2.tags) {
|
3430
|
+
data = value;
|
3431
|
+
} else if(this.options.select2.data) {
|
3432
|
+
data = $.fn.editableutils.itemsByValue(value, this.options.select2.data, 'id');
|
3433
|
+
} else {
|
3434
|
+
//if('ajax' in this.options.select2) {
|
3435
|
+
}
|
3436
|
+
}
|
3437
|
+
|
3438
|
+
if($.isArray(data)) {
|
3439
|
+
//collect selected data and show with separator
|
3440
|
+
text = [];
|
3441
|
+
$.each(data, function(k, v){
|
3442
|
+
text.push(v && typeof v === 'object' ? v.text : v);
|
3443
|
+
});
|
3444
|
+
} else if(data) {
|
3445
|
+
text = data.text;
|
3446
|
+
}
|
3447
|
+
|
3448
|
+
text = $.isArray(text) ? text.join(this.options.viewseparator) : text;
|
3449
|
+
|
3450
|
+
$(element).text(text);
|
3451
|
+
},
|
3452
|
+
|
3453
|
+
html2value: function(html) {
|
3454
|
+
return this.options.select2.tags ? this.str2value(html, this.options.viewseparator) : null;
|
3455
|
+
},
|
3456
|
+
|
3457
|
+
value2input: function(value) {
|
3458
|
+
this.$input.val(value).trigger('change', true); //second argument needed to separate initial change from user's click (for autosubmit)
|
3459
|
+
},
|
3460
|
+
|
3461
|
+
input2value: function() {
|
3462
|
+
return this.$input.select2('val');
|
3463
|
+
},
|
3464
|
+
|
3465
|
+
str2value: function(str, separator) {
|
3466
|
+
if(typeof str !== 'string' || !this.isMultiple) {
|
3467
|
+
return str;
|
3468
|
+
}
|
3469
|
+
|
3470
|
+
separator = separator || this.options.select2.separator || $.fn.select2.defaults.separator;
|
3471
|
+
|
3472
|
+
var val, i, l;
|
3473
|
+
|
3474
|
+
if (str === null || str.length < 1) {
|
3475
|
+
return null;
|
3476
|
+
}
|
3477
|
+
val = str.split(separator);
|
3478
|
+
for (i = 0, l = val.length; i < l; i = i + 1) {
|
3479
|
+
val[i] = $.trim(val[i]);
|
3480
|
+
}
|
3481
|
+
|
3482
|
+
return val;
|
3483
|
+
},
|
3484
|
+
|
3485
|
+
autosubmit: function() {
|
3486
|
+
this.$input.on('change', function(e, isInitial){
|
3487
|
+
if(!isInitial) {
|
3488
|
+
$(this).closest('form').submit();
|
3489
|
+
}
|
3490
|
+
});
|
3491
|
+
}
|
3492
|
+
|
3493
|
+
});
|
3494
|
+
|
3495
|
+
Constructor.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, {
|
3496
|
+
/**
|
3497
|
+
@property tpl
|
3498
|
+
@default <input type="hidden">
|
3499
|
+
**/
|
3500
|
+
tpl:'<input type="hidden">',
|
3501
|
+
/**
|
3502
|
+
Configuration of select2. [Full list of options](http://ivaynberg.github.com/select2).
|
3503
|
+
|
3504
|
+
@property select2
|
3505
|
+
@type object
|
3506
|
+
@default null
|
3507
|
+
**/
|
3508
|
+
select2: null,
|
3509
|
+
/**
|
3510
|
+
Placeholder attribute of select
|
3511
|
+
|
3512
|
+
@property placeholder
|
3513
|
+
@type string
|
3514
|
+
@default null
|
3515
|
+
**/
|
3516
|
+
placeholder: null,
|
3517
|
+
/**
|
3518
|
+
Source data for select. It will be assigned to select2 `data` property and kept here just for convenience.
|
3519
|
+
Please note, that format is different from simple `select` input: use 'id' instead of 'value'.
|
3520
|
+
E.g. `[{id: 1, text: "text1"}, {id: 2, text: "text2"}, ...]`.
|
3521
|
+
|
3522
|
+
@property source
|
3523
|
+
@type array
|
3524
|
+
@default null
|
3525
|
+
**/
|
3526
|
+
source: null,
|
3527
|
+
/**
|
3528
|
+
Separator used to display tags.
|
3529
|
+
|
3530
|
+
@property viewseparator
|
3531
|
+
@type string
|
3532
|
+
@default ', '
|
3533
|
+
**/
|
3534
|
+
viewseparator: ', '
|
3535
|
+
});
|
3536
|
+
|
3537
|
+
$.fn.editabletypes.select2 = Constructor;
|
3538
|
+
|
3539
|
+
}(window.jQuery));
|
3540
|
+
|
3541
|
+
/**
|
3542
|
+
* Combodate - 1.0.3
|
3543
|
+
* Dropdown date and time picker.
|
3544
|
+
* Converts text input into dropdowns to pick day, month, year, hour, minute and second.
|
3545
|
+
* Uses momentjs as datetime library http://momentjs.com.
|
3546
|
+
* For i18n include corresponding file from https://github.com/timrwood/moment/tree/master/lang
|
3547
|
+
*
|
3548
|
+
* Author: Vitaliy Potapov
|
3549
|
+
* Project page: http://github.com/vitalets/combodate
|
3550
|
+
* Copyright (c) 2012 Vitaliy Potapov. Released under MIT License.
|
3551
|
+
**/
|
3552
|
+
(function ($) {
|
3553
|
+
|
3554
|
+
var Combodate = function (element, options) {
|
3555
|
+
this.$element = $(element);
|
3556
|
+
if(!this.$element.is('input')) {
|
3557
|
+
$.error('Combodate should be applied to INPUT element');
|
3558
|
+
return;
|
3559
|
+
}
|
3560
|
+
this.options = $.extend({}, $.fn.combodate.defaults, options, this.$element.data());
|
3561
|
+
this.init();
|
3562
|
+
};
|
3563
|
+
|
3564
|
+
Combodate.prototype = {
|
3565
|
+
constructor: Combodate,
|
3566
|
+
init: function () {
|
3567
|
+
this.map = {
|
3568
|
+
//key regexp moment.method
|
3569
|
+
day: ['D', 'date'],
|
3570
|
+
month: ['M', 'month'],
|
3571
|
+
year: ['Y', 'year'],
|
3572
|
+
hour: ['[Hh]', 'hours'],
|
3573
|
+
minute: ['m', 'minutes'],
|
3574
|
+
second: ['s', 'seconds'],
|
3575
|
+
ampm: ['[Aa]', '']
|
3576
|
+
};
|
3577
|
+
|
3578
|
+
this.$widget = $('<span class="combodate"></span>').html(this.getTemplate());
|
3579
|
+
|
3580
|
+
this.initCombos();
|
3581
|
+
|
3582
|
+
//update original input on change
|
3583
|
+
this.$widget.on('change', 'select', $.proxy(function(){
|
3584
|
+
this.$element.val(this.getValue());
|
3585
|
+
}, this));
|
3586
|
+
|
3587
|
+
this.$widget.find('select').css('width', 'auto');
|
3588
|
+
|
3589
|
+
//hide original input and insert widget
|
3590
|
+
this.$element.hide().after(this.$widget);
|
3591
|
+
|
3592
|
+
//set initial value
|
3593
|
+
this.setValue(this.$element.val() || this.options.value);
|
3594
|
+
},
|
3595
|
+
|
3596
|
+
/*
|
3597
|
+
Replace tokens in template with <select> elements
|
3598
|
+
*/
|
3599
|
+
getTemplate: function() {
|
3600
|
+
var tpl = this.options.template;
|
3601
|
+
|
3602
|
+
//first pass
|
3603
|
+
$.each(this.map, function(k, v) {
|
3604
|
+
v = v[0];
|
3605
|
+
var r = new RegExp(v+'+'),
|
3606
|
+
token = v.length > 1 ? v.substring(1, 2) : v;
|
3607
|
+
|
3608
|
+
tpl = tpl.replace(r, '{'+token+'}');
|
3609
|
+
});
|
3610
|
+
|
3611
|
+
//replace spaces with
|
3612
|
+
tpl = tpl.replace(/ /g, ' ');
|
3613
|
+
|
3614
|
+
//second pass
|
3615
|
+
$.each(this.map, function(k, v) {
|
3616
|
+
v = v[0];
|
3617
|
+
var token = v.length > 1 ? v.substring(1, 2) : v;
|
3618
|
+
|
3619
|
+
tpl = tpl.replace('{'+token+'}', '<select class="'+k+'"></select>');
|
3620
|
+
});
|
3621
|
+
|
3622
|
+
return tpl;
|
3623
|
+
},
|
3624
|
+
|
3625
|
+
/*
|
3626
|
+
Initialize combos that presents in template
|
3627
|
+
*/
|
3628
|
+
initCombos: function() {
|
3629
|
+
var that = this;
|
3630
|
+
$.each(this.map, function(k, v) {
|
3631
|
+
var $c = that.$widget.find('.'+k), f, items;
|
3632
|
+
if($c.length) {
|
3633
|
+
that['$'+k] = $c; //set properties like this.$day, this.$month etc.
|
3634
|
+
f = 'fill' + k.charAt(0).toUpperCase() + k.slice(1); //define method name to fill items, e.g `fillDays`
|
3635
|
+
items = that[f]();
|
3636
|
+
that['$'+k].html(that.renderItems(items));
|
3637
|
+
}
|
3638
|
+
});
|
3639
|
+
},
|
3640
|
+
|
3641
|
+
/*
|
3642
|
+
Initialize items of combos. Handles `firstItem` option
|
3643
|
+
*/
|
3644
|
+
initItems: function(key) {
|
3645
|
+
var values = [],
|
3646
|
+
relTime;
|
3647
|
+
|
3648
|
+
if(this.options.firstItem === 'name') {
|
3649
|
+
//need both to support moment ver < 2 and >= 2
|
3650
|
+
relTime = moment.relativeTime || moment.langData()._relativeTime;
|
3651
|
+
var header = typeof relTime[key] === 'function' ? relTime[key](1, true, key, false) : relTime[key];
|
3652
|
+
//take last entry (see momentjs lang files structure)
|
3653
|
+
header = header.split(' ').reverse()[0];
|
3654
|
+
values.push(['', header]);
|
3655
|
+
} else if(this.options.firstItem === 'empty') {
|
3656
|
+
values.push(['', '']);
|
3657
|
+
}
|
3658
|
+
return values;
|
3659
|
+
},
|
3660
|
+
|
3661
|
+
/*
|
3662
|
+
render items to string of <option> tags
|
3663
|
+
*/
|
3664
|
+
renderItems: function(items) {
|
3665
|
+
var str = [];
|
3666
|
+
for(var i=0; i<items.length; i++) {
|
3667
|
+
str.push('<option value="'+items[i][0]+'">'+items[i][1]+'</option>');
|
3668
|
+
}
|
3669
|
+
return str.join("\n");
|
3670
|
+
},
|
3671
|
+
|
3672
|
+
/*
|
3673
|
+
fill day
|
3674
|
+
*/
|
3675
|
+
fillDay: function() {
|
3676
|
+
var items = this.initItems('d'), name, i,
|
3677
|
+
twoDigit = this.options.template.indexOf('DD') !== -1;
|
3678
|
+
|
3679
|
+
for(i=1; i<=31; i++) {
|
3680
|
+
name = twoDigit ? this.leadZero(i) : i;
|
3681
|
+
items.push([i, name]);
|
3682
|
+
}
|
3683
|
+
return items;
|
3684
|
+
},
|
3685
|
+
|
3686
|
+
/*
|
3687
|
+
fill month
|
3688
|
+
*/
|
3689
|
+
fillMonth: function() {
|
3690
|
+
var items = this.initItems('M'), name, i,
|
3691
|
+
longNames = this.options.template.indexOf('MMMM') !== -1,
|
3692
|
+
shortNames = this.options.template.indexOf('MMM') !== -1,
|
3693
|
+
twoDigit = this.options.template.indexOf('MM') !== -1;
|
3694
|
+
|
3695
|
+
for(i=0; i<=11; i++) {
|
3696
|
+
if(longNames) {
|
3697
|
+
name = moment().month(i).format('MMMM');
|
3698
|
+
} else if(shortNames) {
|
3699
|
+
name = moment().month(i).format('MMM');
|
3700
|
+
} else if(twoDigit) {
|
3701
|
+
name = this.leadZero(i+1);
|
3702
|
+
} else {
|
3703
|
+
name = i+1;
|
3704
|
+
}
|
3705
|
+
items.push([i, name]);
|
3706
|
+
}
|
3707
|
+
return items;
|
3708
|
+
},
|
3709
|
+
|
3710
|
+
/*
|
3711
|
+
fill year
|
3712
|
+
*/
|
3713
|
+
fillYear: function() {
|
3714
|
+
var items = [], name, i,
|
3715
|
+
longNames = this.options.template.indexOf('YYYY') !== -1;
|
3716
|
+
|
3717
|
+
for(i=this.options.maxYear; i>=this.options.minYear; i--) {
|
3718
|
+
name = longNames ? i : (i+'').substring(2);
|
3719
|
+
items[this.options.yearDescending ? 'push' : 'unshift']([i, name]);
|
3720
|
+
}
|
3721
|
+
|
3722
|
+
items = this.initItems('y').concat(items);
|
3723
|
+
|
3724
|
+
return items;
|
3725
|
+
},
|
3726
|
+
|
3727
|
+
/*
|
3728
|
+
fill hour
|
3729
|
+
*/
|
3730
|
+
fillHour: function() {
|
3731
|
+
var items = this.initItems('h'), name, i,
|
3732
|
+
h12 = this.options.template.indexOf('h') !== -1,
|
3733
|
+
h24 = this.options.template.indexOf('H') !== -1,
|
3734
|
+
twoDigit = this.options.template.toLowerCase().indexOf('hh') !== -1,
|
3735
|
+
max = h12 ? 12 : 23;
|
3736
|
+
|
3737
|
+
for(i=0; i<=max; i++) {
|
3738
|
+
name = twoDigit ? this.leadZero(i) : i;
|
3739
|
+
items.push([i, name]);
|
3740
|
+
}
|
3741
|
+
return items;
|
3742
|
+
},
|
3743
|
+
|
3744
|
+
/*
|
3745
|
+
fill minute
|
3746
|
+
*/
|
3747
|
+
fillMinute: function() {
|
3748
|
+
var items = this.initItems('m'), name, i,
|
3749
|
+
twoDigit = this.options.template.indexOf('mm') !== -1;
|
3750
|
+
|
3751
|
+
for(i=0; i<=59; i+= this.options.minuteStep) {
|
3752
|
+
name = twoDigit ? this.leadZero(i) : i;
|
3753
|
+
items.push([i, name]);
|
3754
|
+
}
|
3755
|
+
return items;
|
3756
|
+
},
|
3757
|
+
|
3758
|
+
/*
|
3759
|
+
fill second
|
3760
|
+
*/
|
3761
|
+
fillSecond: function() {
|
3762
|
+
var items = this.initItems('s'), name, i,
|
3763
|
+
twoDigit = this.options.template.indexOf('ss') !== -1;
|
3764
|
+
|
3765
|
+
for(i=0; i<=59; i+= this.options.secondStep) {
|
3766
|
+
name = twoDigit ? this.leadZero(i) : i;
|
3767
|
+
items.push([i, name]);
|
3768
|
+
}
|
3769
|
+
return items;
|
3770
|
+
},
|
3771
|
+
|
3772
|
+
/*
|
3773
|
+
fill ampm
|
3774
|
+
*/
|
3775
|
+
fillAmpm: function() {
|
3776
|
+
var ampmL = this.options.template.indexOf('a') !== -1,
|
3777
|
+
ampmU = this.options.template.indexOf('A') !== -1,
|
3778
|
+
items = [
|
3779
|
+
['am', ampmL ? 'am' : 'AM'],
|
3780
|
+
['pm', ampmL ? 'pm' : 'PM']
|
3781
|
+
];
|
3782
|
+
return items;
|
3783
|
+
},
|
3784
|
+
|
3785
|
+
/*
|
3786
|
+
Returns current date value.
|
3787
|
+
If format not specified - `options.format` used.
|
3788
|
+
If format = `null` - Moment object returned.
|
3789
|
+
*/
|
3790
|
+
getValue: function(format) {
|
3791
|
+
var dt, values = {},
|
3792
|
+
that = this,
|
3793
|
+
notSelected = false;
|
3794
|
+
|
3795
|
+
//getting selected values
|
3796
|
+
$.each(this.map, function(k, v) {
|
3797
|
+
if(k === 'ampm') {
|
3798
|
+
return;
|
3799
|
+
}
|
3800
|
+
var def = k === 'day' ? 1 : 0;
|
3801
|
+
|
3802
|
+
values[k] = that['$'+k] ? parseInt(that['$'+k].val(), 10) : def;
|
3803
|
+
|
3804
|
+
if(isNaN(values[k])) {
|
3805
|
+
notSelected = true;
|
3806
|
+
return false;
|
3807
|
+
}
|
3808
|
+
});
|
3809
|
+
|
3810
|
+
//if at least one visible combo not selected - return empty string
|
3811
|
+
if(notSelected) {
|
3812
|
+
return '';
|
3813
|
+
}
|
3814
|
+
|
3815
|
+
//convert hours if 12h format
|
3816
|
+
if(this.$ampm) {
|
3817
|
+
values.hour = this.$ampm.val() === 'am' ? values.hour : values.hour+12;
|
3818
|
+
if(values.hour === 24) {
|
3819
|
+
values.hour = 0;
|
3820
|
+
}
|
3821
|
+
}
|
3822
|
+
|
3823
|
+
dt = moment([values.year, values.month, values.day, values.hour, values.minute, values.second]);
|
3824
|
+
|
3825
|
+
//highlight invalid date
|
3826
|
+
this.highlight(dt);
|
3827
|
+
|
3828
|
+
format = format === undefined ? this.options.format : format;
|
3829
|
+
if(format === null) {
|
3830
|
+
return dt.isValid() ? dt : null;
|
3831
|
+
} else {
|
3832
|
+
return dt.isValid() ? dt.format(format) : '';
|
3833
|
+
}
|
3834
|
+
},
|
3835
|
+
|
3836
|
+
setValue: function(value) {
|
3837
|
+
if(!value) {
|
3838
|
+
return;
|
3839
|
+
}
|
3840
|
+
|
3841
|
+
var dt = typeof value === 'string' ? moment(value, this.options.format) : moment(value),
|
3842
|
+
that = this,
|
3843
|
+
values = {};
|
3844
|
+
|
3845
|
+
//function to find nearest value in select options
|
3846
|
+
function getNearest($select, value) {
|
3847
|
+
var delta = {};
|
3848
|
+
$select.children('option').each(function(i, opt){
|
3849
|
+
var optValue = $(opt).attr('value'),
|
3850
|
+
distance;
|
3851
|
+
|
3852
|
+
if(optValue === '') return;
|
3853
|
+
distance = Math.abs(optValue - value);
|
3854
|
+
if(typeof delta.distance === 'undefined' || distance < delta.distance) {
|
3855
|
+
delta = {value: optValue, distance: distance};
|
3856
|
+
}
|
3857
|
+
});
|
3858
|
+
return delta.value;
|
3859
|
+
}
|
3860
|
+
|
3861
|
+
if(dt.isValid()) {
|
3862
|
+
//read values from date object
|
3863
|
+
$.each(this.map, function(k, v) {
|
3864
|
+
if(k === 'ampm') {
|
3865
|
+
return;
|
3866
|
+
}
|
3867
|
+
values[k] = dt[v[1]]();
|
3868
|
+
});
|
3869
|
+
|
3870
|
+
if(this.$ampm) {
|
3871
|
+
if(values.hour > 12) {
|
3872
|
+
values.hour -= 12;
|
3873
|
+
values.ampm = 'pm';
|
3874
|
+
} else {
|
3875
|
+
values.ampm = 'am';
|
3876
|
+
}
|
3877
|
+
}
|
3878
|
+
|
3879
|
+
$.each(values, function(k, v) {
|
3880
|
+
//call val() for each existing combo, e.g. this.$hour.val()
|
3881
|
+
if(that['$'+k]) {
|
3882
|
+
|
3883
|
+
if(k === 'minute' && that.options.minuteStep > 1 && that.options.roundTime) {
|
3884
|
+
v = getNearest(that['$'+k], v);
|
3885
|
+
}
|
3886
|
+
|
3887
|
+
if(k === 'second' && that.options.secondStep > 1 && that.options.roundTime) {
|
3888
|
+
v = getNearest(that['$'+k], v);
|
3889
|
+
}
|
3890
|
+
|
3891
|
+
that['$'+k].val(v);
|
3892
|
+
}
|
3893
|
+
});
|
3894
|
+
|
3895
|
+
this.$element.val(dt.format(this.options.format));
|
3896
|
+
}
|
3897
|
+
},
|
3898
|
+
|
3899
|
+
/*
|
3900
|
+
highlight combos if date is invalid
|
3901
|
+
*/
|
3902
|
+
highlight: function(dt) {
|
3903
|
+
if(!dt.isValid()) {
|
3904
|
+
if(this.options.errorClass) {
|
3905
|
+
this.$widget.addClass(this.options.errorClass);
|
3906
|
+
} else {
|
3907
|
+
//store original border color
|
3908
|
+
if(!this.borderColor) {
|
3909
|
+
this.borderColor = this.$widget.find('select').css('border-color');
|
3910
|
+
}
|
3911
|
+
this.$widget.find('select').css('border-color', 'red');
|
3912
|
+
}
|
3913
|
+
} else {
|
3914
|
+
if(this.options.errorClass) {
|
3915
|
+
this.$widget.removeClass(this.options.errorClass);
|
3916
|
+
} else {
|
3917
|
+
this.$widget.find('select').css('border-color', this.borderColor);
|
3918
|
+
}
|
3919
|
+
}
|
3920
|
+
},
|
3921
|
+
|
3922
|
+
leadZero: function(v) {
|
3923
|
+
return v <= 9 ? '0' + v : v;
|
3924
|
+
},
|
3925
|
+
|
3926
|
+
destroy: function() {
|
3927
|
+
this.$widget.remove();
|
3928
|
+
this.$element.removeData('combodate').show();
|
3929
|
+
}
|
3930
|
+
|
3931
|
+
//todo: clear method
|
3932
|
+
};
|
3933
|
+
|
3934
|
+
$.fn.combodate = function ( option ) {
|
3935
|
+
var d, args = Array.apply(null, arguments);
|
3936
|
+
args.shift();
|
3937
|
+
|
3938
|
+
//getValue returns date as string / object (not jQuery object)
|
3939
|
+
if(option === 'getValue' && this.length && (d = this.eq(0).data('combodate'))) {
|
3940
|
+
return d.getValue.apply(d, args);
|
3941
|
+
}
|
3942
|
+
|
3943
|
+
return this.each(function () {
|
3944
|
+
var $this = $(this),
|
3945
|
+
data = $this.data('combodate'),
|
3946
|
+
options = typeof option == 'object' && option;
|
3947
|
+
if (!data) {
|
3948
|
+
$this.data('combodate', (data = new Combodate(this, options)));
|
3949
|
+
}
|
3950
|
+
if (typeof option == 'string' && typeof data[option] == 'function') {
|
3951
|
+
data[option].apply(data, args);
|
3952
|
+
}
|
3953
|
+
});
|
3954
|
+
};
|
3955
|
+
|
3956
|
+
$.fn.combodate.defaults = {
|
3957
|
+
//in this format value stored in original input
|
3958
|
+
format: 'DD-MM-YYYY HH:mm',
|
3959
|
+
//in this format items in dropdowns are displayed
|
3960
|
+
template: 'D / MMM / YYYY H : mm',
|
3961
|
+
//initial value, can be `new Date()`
|
3962
|
+
value: null,
|
3963
|
+
minYear: 1970,
|
3964
|
+
maxYear: 2015,
|
3965
|
+
yearDescending: true,
|
3966
|
+
minuteStep: 5,
|
3967
|
+
secondStep: 1,
|
3968
|
+
firstItem: 'empty', //'name', 'empty', 'none'
|
3969
|
+
errorClass: null,
|
3970
|
+
roundTime: true //whether to round minutes and seconds if step > 1
|
3971
|
+
};
|
3972
|
+
|
3973
|
+
}(window.jQuery));
|
3974
|
+
/**
|
3975
|
+
Combodate input - dropdown date and time picker.
|
3976
|
+
Based on [combodate](http://vitalets.github.com/combodate) plugin (included). To use it you should manually include [momentjs](http://momentjs.com).
|
3977
|
+
|
3978
|
+
<script src="js/moment.min.js"></script>
|
3979
|
+
|
3980
|
+
Allows to input:
|
3981
|
+
|
3982
|
+
* only date
|
3983
|
+
* only time
|
3984
|
+
* both date and time
|
3985
|
+
|
3986
|
+
Please note, that format is taken from momentjs and **not compatible** with bootstrap-datepicker / jquery UI datepicker.
|
3987
|
+
Internally value stored as `momentjs` object.
|
3988
|
+
|
3989
|
+
@class combodate
|
3990
|
+
@extends abstractinput
|
3991
|
+
@final
|
3992
|
+
@since 1.4.0
|
3993
|
+
@example
|
3994
|
+
<a href="#" id="dob" data-type="combodate" data-pk="1" data-url="/post" data-value="1984-05-15" data-original-title="Select date"></a>
|
3995
|
+
<script>
|
3996
|
+
$(function(){
|
3997
|
+
$('#dob').editable({
|
3998
|
+
format: 'YYYY-MM-DD',
|
3999
|
+
viewformat: 'DD.MM.YYYY',
|
4000
|
+
template: 'D / MMMM / YYYY',
|
4001
|
+
combodate: {
|
4002
|
+
minYear: 2000,
|
4003
|
+
maxYear: 2015,
|
4004
|
+
minuteStep: 1
|
4005
|
+
}
|
4006
|
+
}
|
4007
|
+
});
|
4008
|
+
});
|
4009
|
+
</script>
|
4010
|
+
**/
|
4011
|
+
|
4012
|
+
/*global moment*/
|
4013
|
+
|
4014
|
+
(function ($) {
|
4015
|
+
"use strict";
|
4016
|
+
|
4017
|
+
var Constructor = function (options) {
|
4018
|
+
this.init('combodate', options, Constructor.defaults);
|
4019
|
+
|
4020
|
+
//by default viewformat equals to format
|
4021
|
+
if(!this.options.viewformat) {
|
4022
|
+
this.options.viewformat = this.options.format;
|
4023
|
+
}
|
4024
|
+
|
4025
|
+
//try parse combodate config defined as json string in data-combodate
|
4026
|
+
options.combodate = $.fn.editableutils.tryParseJson(options.combodate, true);
|
4027
|
+
|
4028
|
+
//overriding combodate config (as by default jQuery extend() is not recursive)
|
4029
|
+
this.options.combodate = $.extend({}, Constructor.defaults.combodate, options.combodate, {
|
4030
|
+
format: this.options.format,
|
4031
|
+
template: this.options.template
|
4032
|
+
});
|
4033
|
+
};
|
4034
|
+
|
4035
|
+
$.fn.editableutils.inherit(Constructor, $.fn.editabletypes.abstractinput);
|
4036
|
+
|
4037
|
+
$.extend(Constructor.prototype, {
|
4038
|
+
render: function () {
|
4039
|
+
this.$input.combodate(this.options.combodate);
|
4040
|
+
|
4041
|
+
//"clear" link
|
4042
|
+
/*
|
4043
|
+
if(this.options.clear) {
|
4044
|
+
this.$clear = $('<a href="#"></a>').html(this.options.clear).click($.proxy(function(e){
|
4045
|
+
e.preventDefault();
|
4046
|
+
e.stopPropagation();
|
4047
|
+
this.clear();
|
4048
|
+
}, this));
|
4049
|
+
|
4050
|
+
this.$tpl.parent().append($('<div class="editable-clear">').append(this.$clear));
|
4051
|
+
}
|
4052
|
+
*/
|
4053
|
+
},
|
4054
|
+
|
4055
|
+
value2html: function(value, element) {
|
4056
|
+
var text = value ? value.format(this.options.viewformat) : '';
|
4057
|
+
$(element).text(text);
|
4058
|
+
},
|
4059
|
+
|
4060
|
+
html2value: function(html) {
|
4061
|
+
return html ? moment(html, this.options.viewformat) : null;
|
4062
|
+
},
|
4063
|
+
|
4064
|
+
value2str: function(value) {
|
4065
|
+
return value ? value.format(this.options.format) : '';
|
4066
|
+
},
|
4067
|
+
|
4068
|
+
str2value: function(str) {
|
4069
|
+
return str ? moment(str, this.options.format) : null;
|
4070
|
+
},
|
4071
|
+
|
4072
|
+
value2submit: function(value) {
|
4073
|
+
return this.value2str(value);
|
4074
|
+
},
|
4075
|
+
|
4076
|
+
value2input: function(value) {
|
4077
|
+
this.$input.combodate('setValue', value);
|
4078
|
+
},
|
4079
|
+
|
4080
|
+
input2value: function() {
|
4081
|
+
return this.$input.combodate('getValue', null);
|
4082
|
+
},
|
4083
|
+
|
4084
|
+
activate: function() {
|
4085
|
+
this.$input.siblings('.combodate').find('select').eq(0).focus();
|
4086
|
+
},
|
4087
|
+
|
4088
|
+
/*
|
4089
|
+
clear: function() {
|
4090
|
+
this.$input.data('datepicker').date = null;
|
4091
|
+
this.$input.find('.active').removeClass('active');
|
4092
|
+
},
|
4093
|
+
*/
|
4094
|
+
|
4095
|
+
autosubmit: function() {
|
4096
|
+
|
4097
|
+
}
|
4098
|
+
|
4099
|
+
});
|
4100
|
+
|
4101
|
+
Constructor.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, {
|
4102
|
+
/**
|
4103
|
+
@property tpl
|
4104
|
+
@default <input type="text">
|
4105
|
+
**/
|
4106
|
+
tpl:'<input type="text">',
|
4107
|
+
/**
|
4108
|
+
@property inputclass
|
4109
|
+
@default null
|
4110
|
+
**/
|
4111
|
+
inputclass: null,
|
4112
|
+
/**
|
4113
|
+
Format used for sending value to server. Also applied when converting date from <code>data-value</code> attribute.<br>
|
4114
|
+
See list of tokens in [momentjs docs](http://momentjs.com/docs/#/parsing/string-format)
|
4115
|
+
|
4116
|
+
@property format
|
4117
|
+
@type string
|
4118
|
+
@default YYYY-MM-DD
|
4119
|
+
**/
|
4120
|
+
format:'YYYY-MM-DD',
|
4121
|
+
/**
|
4122
|
+
Format used for displaying date. Also applied when converting date from element's text on init.
|
4123
|
+
If not specified equals to `format`.
|
4124
|
+
|
4125
|
+
@property viewformat
|
4126
|
+
@type string
|
4127
|
+
@default null
|
4128
|
+
**/
|
4129
|
+
viewformat: null,
|
4130
|
+
/**
|
4131
|
+
Template used for displaying dropdowns.
|
4132
|
+
|
4133
|
+
@property template
|
4134
|
+
@type string
|
4135
|
+
@default D / MMM / YYYY
|
4136
|
+
**/
|
4137
|
+
template: 'D / MMM / YYYY',
|
4138
|
+
/**
|
4139
|
+
Configuration of combodate.
|
4140
|
+
Full list of options: http://vitalets.github.com/combodate/#docs
|
4141
|
+
|
4142
|
+
@property combodate
|
4143
|
+
@type object
|
4144
|
+
@default null
|
4145
|
+
**/
|
4146
|
+
combodate: null
|
4147
|
+
|
4148
|
+
/*
|
4149
|
+
(not implemented yet)
|
4150
|
+
Text shown as clear date button.
|
4151
|
+
If <code>false</code> clear button will not be rendered.
|
4152
|
+
|
4153
|
+
@property clear
|
4154
|
+
@type boolean|string
|
4155
|
+
@default 'x clear'
|
4156
|
+
*/
|
4157
|
+
//clear: '× clear'
|
4158
|
+
});
|
4159
|
+
|
4160
|
+
$.fn.editabletypes.combodate = Constructor;
|
4161
|
+
|
4162
|
+
}(window.jQuery));
|
4163
|
+
|
4164
|
+
/**
|
4165
|
+
* Editable Poshytip
|
4166
|
+
* ---------------------
|
4167
|
+
* requires jquery.poshytip.js
|
4168
|
+
*/
|
4169
|
+
(function ($) {
|
4170
|
+
"use strict";
|
4171
|
+
|
4172
|
+
//extend methods
|
4173
|
+
$.extend($.fn.editableContainer.Popup.prototype, {
|
4174
|
+
containerName: 'poshytip',
|
4175
|
+
innerCss: 'div.tip-inner',
|
4176
|
+
|
4177
|
+
initContainer: function(){
|
4178
|
+
this.handlePlacement();
|
4179
|
+
|
4180
|
+
$.extend(this.containerOptions, {
|
4181
|
+
showOn: 'none',
|
4182
|
+
content: '',
|
4183
|
+
alignTo: 'target'
|
4184
|
+
});
|
4185
|
+
|
4186
|
+
this.call(this.containerOptions);
|
4187
|
+
},
|
4188
|
+
|
4189
|
+
/*
|
4190
|
+
Overwrite totally show() method as poshytip requires content is set before show
|
4191
|
+
*/
|
4192
|
+
show: function (closeAll) {
|
4193
|
+
this.$element.addClass('editable-open');
|
4194
|
+
if(closeAll !== false) {
|
4195
|
+
//close all open containers (except this)
|
4196
|
+
this.closeOthers(this.$element[0]);
|
4197
|
+
}
|
4198
|
+
|
4199
|
+
//render form
|
4200
|
+
this.$form = $('<div>');
|
4201
|
+
this.renderForm();
|
4202
|
+
|
4203
|
+
var $label = $('<label>').text(this.options.title || this.$element.data( "title") || this.$element.data( "originalTitle")),
|
4204
|
+
$content = $('<div>').append($label).append(this.$form);
|
4205
|
+
|
4206
|
+
this.call('update', $content);
|
2672
4207
|
this.call('show');
|
4208
|
+
|
2673
4209
|
this.tip().addClass('editable-container');
|
2674
4210
|
this.$form.data('editableform').input.activate();
|
2675
|
-
},
|
4211
|
+
},
|
4212
|
+
|
4213
|
+
/* hide */
|
4214
|
+
innerHide: function () {
|
4215
|
+
this.call('hide');
|
4216
|
+
},
|
4217
|
+
|
4218
|
+
/* destroy */
|
4219
|
+
innerDestroy: function() {
|
4220
|
+
this.call('destroy');
|
4221
|
+
},
|
2676
4222
|
|
2677
4223
|
setPosition: function() {
|
2678
4224
|
this.container().refresh(false);
|
@@ -2723,106 +4269,109 @@ Range (inherit from number)
|
|
2723
4269
|
* see https://github.com/vadikom/poshytip/issues/7
|
2724
4270
|
*/
|
2725
4271
|
/*jshint eqeqeq:false, curly: false*/
|
2726
|
-
|
2727
|
-
|
2728
|
-
|
2729
|
-
|
2730
|
-
|
2731
|
-
|
2732
|
-
|
2733
|
-
|
2734
|
-
|
2735
|
-
|
2736
|
-
|
2737
|
-
|
2738
|
-
|
2739
|
-
|
2740
|
-
|
2741
|
-
|
2742
|
-
|
2743
|
-
|
2744
|
-
|
2745
|
-
|
2746
|
-
|
2747
|
-
|
2748
|
-
|
2749
|
-
|
2750
|
-
|
2751
|
-
|
2752
|
-
|
2753
|
-
|
2754
|
-
|
2755
|
-
|
2756
|
-
|
2757
|
-
|
2758
|
-
|
2759
|
-
|
2760
|
-
|
2761
|
-
|
2762
|
-
|
2763
|
-
|
2764
|
-
|
2765
|
-
|
2766
|
-
|
2767
|
-
|
2768
|
-
|
2769
|
-
|
2770
|
-
|
2771
|
-
|
2772
|
-
|
2773
|
-
|
2774
|
-
|
2775
|
-
|
2776
|
-
|
2777
|
-
|
2778
|
-
|
2779
|
-
|
2780
|
-
|
2781
|
-
|
2782
|
-
|
2783
|
-
|
2784
|
-
|
2785
|
-
|
2786
|
-
|
2787
|
-
|
2788
|
-
|
2789
|
-
|
2790
|
-
|
2791
|
-
|
2792
|
-
|
2793
|
-
|
2794
|
-
|
2795
|
-
|
2796
|
-
|
2797
|
-
|
2798
|
-
|
2799
|
-
|
2800
|
-
|
2801
|
-
|
2802
|
-
|
2803
|
-
|
2804
|
-
|
2805
|
-
|
2806
|
-
|
2807
|
-
|
2808
|
-
|
2809
|
-
|
2810
|
-
|
2811
|
-
|
2812
|
-
|
2813
|
-
|
2814
|
-
|
2815
|
-
|
2816
|
-
|
2817
|
-
|
2818
|
-
|
2819
|
-
|
4272
|
+
if($.Poshytip) { //need this check, because in inline mode poshytip may not be loaded!
|
4273
|
+
var tips = [],
|
4274
|
+
reBgImage = /^url\(["']?([^"'\)]*)["']?\);?$/i,
|
4275
|
+
rePNG = /\.png$/i,
|
4276
|
+
ie6 = !!window.createPopup && document.documentElement.currentStyle.minWidth == 'undefined';
|
4277
|
+
|
4278
|
+
$.Poshytip.prototype.refresh = function(async) {
|
4279
|
+
if (this.disabled)
|
4280
|
+
return;
|
4281
|
+
|
4282
|
+
var currPos;
|
4283
|
+
if (async) {
|
4284
|
+
if (!this.$tip.data('active'))
|
4285
|
+
return;
|
4286
|
+
// save current position as we will need to animate
|
4287
|
+
currPos = {left: this.$tip.css('left'), top: this.$tip.css('top')};
|
4288
|
+
}
|
4289
|
+
|
4290
|
+
// reset position to avoid text wrapping, etc.
|
4291
|
+
this.$tip.css({left: 0, top: 0}).appendTo(document.body);
|
4292
|
+
|
4293
|
+
// save default opacity
|
4294
|
+
if (this.opacity === undefined)
|
4295
|
+
this.opacity = this.$tip.css('opacity');
|
4296
|
+
|
4297
|
+
// check for images - this code is here (i.e. executed each time we show the tip and not on init) due to some browser inconsistencies
|
4298
|
+
var bgImage = this.$tip.css('background-image').match(reBgImage),
|
4299
|
+
arrow = this.$arrow.css('background-image').match(reBgImage);
|
4300
|
+
|
4301
|
+
if (bgImage) {
|
4302
|
+
var bgImagePNG = rePNG.test(bgImage[1]);
|
4303
|
+
// fallback to background-color/padding/border in IE6 if a PNG is used
|
4304
|
+
if (ie6 && bgImagePNG) {
|
4305
|
+
this.$tip.css('background-image', 'none');
|
4306
|
+
this.$inner.css({margin: 0, border: 0, padding: 0});
|
4307
|
+
bgImage = bgImagePNG = false;
|
4308
|
+
} else {
|
4309
|
+
this.$tip.prepend('<table class="fallback" border="0" cellpadding="0" cellspacing="0"><tr><td class="tip-top tip-bg-image" colspan="2"><span></span></td><td class="tip-right tip-bg-image" rowspan="2"><span></span></td></tr><tr><td class="tip-left tip-bg-image" rowspan="2"><span></span></td><td></td></tr><tr><td class="tip-bottom tip-bg-image" colspan="2"><span></span></td></tr></table>')
|
4310
|
+
.css({border: 0, padding: 0, 'background-image': 'none', 'background-color': 'transparent'})
|
4311
|
+
.find('.tip-bg-image').css('background-image', 'url("' + bgImage[1] +'")').end()
|
4312
|
+
.find('td').eq(3).append(this.$inner);
|
4313
|
+
}
|
4314
|
+
// disable fade effect in IE due to Alpha filter + translucent PNG issue
|
4315
|
+
if (bgImagePNG && !$.support.opacity)
|
4316
|
+
this.opts.fade = false;
|
4317
|
+
}
|
4318
|
+
// IE arrow fixes
|
4319
|
+
if (arrow && !$.support.opacity) {
|
4320
|
+
// disable arrow in IE6 if using a PNG
|
4321
|
+
if (ie6 && rePNG.test(arrow[1])) {
|
4322
|
+
arrow = false;
|
4323
|
+
this.$arrow.css('background-image', 'none');
|
4324
|
+
}
|
4325
|
+
// disable fade effect in IE due to Alpha filter + translucent PNG issue
|
4326
|
+
this.opts.fade = false;
|
4327
|
+
}
|
4328
|
+
|
4329
|
+
var $table = this.$tip.find('table.fallback');
|
4330
|
+
if (ie6) {
|
4331
|
+
// fix min/max-width in IE6
|
4332
|
+
this.$tip[0].style.width = '';
|
4333
|
+
$table.width('auto').find('td').eq(3).width('auto');
|
4334
|
+
var tipW = this.$tip.width(),
|
4335
|
+
minW = parseInt(this.$tip.css('min-width'), 10),
|
4336
|
+
maxW = parseInt(this.$tip.css('max-width'), 10);
|
4337
|
+
if (!isNaN(minW) && tipW < minW)
|
4338
|
+
tipW = minW;
|
4339
|
+
else if (!isNaN(maxW) && tipW > maxW)
|
4340
|
+
tipW = maxW;
|
4341
|
+
this.$tip.add($table).width(tipW).eq(0).find('td').eq(3).width('100%');
|
4342
|
+
} else if ($table[0]) {
|
4343
|
+
// fix the table width if we are using a background image
|
4344
|
+
// IE9, FF4 use float numbers for width/height so use getComputedStyle for them to avoid text wrapping
|
4345
|
+
// for details look at: http://vadikom.com/dailies/offsetwidth-offsetheight-useless-in-ie9-firefox4/
|
4346
|
+
$table.width('auto').find('td').eq(3).width('auto').end().end().width(document.defaultView && document.defaultView.getComputedStyle && parseFloat(document.defaultView.getComputedStyle(this.$tip[0], null).width) || this.$tip.width()).find('td').eq(3).width('100%');
|
4347
|
+
}
|
4348
|
+
this.tipOuterW = this.$tip.outerWidth();
|
4349
|
+
this.tipOuterH = this.$tip.outerHeight();
|
4350
|
+
|
4351
|
+
this.calcPos();
|
4352
|
+
|
4353
|
+
// position and show the arrow image
|
4354
|
+
if (arrow && this.pos.arrow) {
|
4355
|
+
this.$arrow[0].className = 'tip-arrow tip-arrow-' + this.pos.arrow;
|
4356
|
+
this.$arrow.css('visibility', 'inherit');
|
4357
|
+
}
|
4358
|
+
|
4359
|
+
if (async) {
|
4360
|
+
this.asyncAnimating = true;
|
4361
|
+
var self = this;
|
4362
|
+
this.$tip.css(currPos).animate({left: this.pos.l, top: this.pos.t}, 200, function() { self.asyncAnimating = false; });
|
4363
|
+
} else {
|
4364
|
+
this.$tip.css({left: this.pos.l, top: this.pos.t});
|
4365
|
+
}
|
4366
|
+
};
|
4367
|
+
}
|
2820
4368
|
/*jshinteqeqeq: true, curly: true*/
|
2821
4369
|
}(window.jQuery));
|
2822
4370
|
/**
|
2823
4371
|
jQuery UI Datepicker.
|
2824
4372
|
Description and examples: http://jqueryui.com/datepicker.
|
2825
|
-
This input is also accessible as **date** type. Do not use it together with __bootstrap-datepicker__ as both apply <code>$().datepicker()</code> method.
|
4373
|
+
This input is also accessible as **date** type. Do not use it together with __bootstrap-datepicker__ as both apply <code>$().datepicker()</code> method.
|
4374
|
+
For **i18n** you should include js file from here: https://github.com/jquery/jquery-ui/tree/master/ui/i18n.
|
2826
4375
|
|
2827
4376
|
@class dateui
|
2828
4377
|
@extends abstractinput
|
@@ -2843,44 +4392,46 @@ $(function(){
|
|
2843
4392
|
</script>
|
2844
4393
|
**/
|
2845
4394
|
(function ($) {
|
2846
|
-
|
4395
|
+
"use strict";
|
4396
|
+
|
2847
4397
|
var DateUI = function (options) {
|
2848
4398
|
this.init('dateui', options, DateUI.defaults);
|
2849
|
-
|
2850
|
-
//set popular options directly from settings or data-* attributes
|
2851
|
-
var directOptions = $.fn.editableutils.sliceObj(this.options, ['format']);
|
2852
|
-
|
2853
|
-
//overriding datepicker config (as by default jQuery extend() is not recursive)
|
2854
|
-
this.options.datepicker = $.extend({}, DateUI.defaults.datepicker, directOptions, options.datepicker);
|
2855
|
-
|
2856
|
-
//by default viewformat equals to format
|
2857
|
-
if(!this.options.viewformat) {
|
2858
|
-
this.options.viewformat = this.options.datepicker.format;
|
2859
|
-
}
|
2860
|
-
|
2861
|
-
//correct formats: replace yyyy with yy
|
2862
|
-
this.options.viewformat = this.options.viewformat.replace('yyyy', 'yy');
|
2863
|
-
this.options.datepicker.format = this.options.datepicker.format.replace('yyyy', 'yy');
|
2864
|
-
|
2865
|
-
//copy format to dateFormat (dateFormat option required for ui datepicker).
|
2866
|
-
//This allows common option 'format' for all datepickers
|
2867
|
-
this.options.datepicker.dateFormat = this.options.datepicker.format;
|
4399
|
+
this.initPicker(options, DateUI.defaults);
|
2868
4400
|
};
|
2869
4401
|
|
2870
4402
|
$.fn.editableutils.inherit(DateUI, $.fn.editabletypes.abstractinput);
|
2871
4403
|
|
2872
4404
|
$.extend(DateUI.prototype, {
|
4405
|
+
initPicker: function(options, defaults) {
|
4406
|
+
//by default viewformat equals to format
|
4407
|
+
if(!this.options.viewformat) {
|
4408
|
+
this.options.viewformat = this.options.format;
|
4409
|
+
}
|
4410
|
+
|
4411
|
+
//correct formats: replace yyyy with yy (for compatibility with bootstrap datepicker)
|
4412
|
+
this.options.viewformat = this.options.viewformat.replace('yyyy', 'yy');
|
4413
|
+
this.options.format = this.options.format.replace('yyyy', 'yy');
|
4414
|
+
|
4415
|
+
//overriding datepicker config (as by default jQuery extend() is not recursive)
|
4416
|
+
//since 1.4 datepicker internally uses viewformat instead of format. Format is for submit only
|
4417
|
+
this.options.datepicker = $.extend({}, defaults.datepicker, options.datepicker, {
|
4418
|
+
dateFormat: this.options.viewformat
|
4419
|
+
});
|
4420
|
+
},
|
4421
|
+
|
2873
4422
|
render: function () {
|
2874
|
-
DateUI.superclass.render.call(this);
|
2875
4423
|
this.$input.datepicker(this.options.datepicker);
|
2876
4424
|
|
4425
|
+
//"clear" link
|
2877
4426
|
if(this.options.clear) {
|
2878
4427
|
this.$clear = $('<a href="#"></a>').html(this.options.clear).click($.proxy(function(e){
|
2879
4428
|
e.preventDefault();
|
2880
4429
|
e.stopPropagation();
|
2881
4430
|
this.clear();
|
2882
4431
|
}, this));
|
2883
|
-
|
4432
|
+
|
4433
|
+
this.$tpl.parent().append($('<div class="editable-clear">').append(this.$clear));
|
4434
|
+
}
|
2884
4435
|
},
|
2885
4436
|
|
2886
4437
|
value2html: function(value, element) {
|
@@ -2903,7 +4454,7 @@ $(function(){
|
|
2903
4454
|
},
|
2904
4455
|
|
2905
4456
|
value2str: function(value) {
|
2906
|
-
return $.datepicker.formatDate(this.options.
|
4457
|
+
return $.datepicker.formatDate(this.options.format, value);
|
2907
4458
|
},
|
2908
4459
|
|
2909
4460
|
str2value: function(str) {
|
@@ -2914,13 +4465,13 @@ $(function(){
|
|
2914
4465
|
//if string does not match format, UI datepicker throws exception
|
2915
4466
|
var d;
|
2916
4467
|
try {
|
2917
|
-
d = $.datepicker.parseDate(this.options.
|
4468
|
+
d = $.datepicker.parseDate(this.options.format, str);
|
2918
4469
|
} catch(e) {}
|
2919
4470
|
|
2920
4471
|
return d;
|
2921
4472
|
},
|
2922
4473
|
|
2923
|
-
value2submit: function(value) {
|
4474
|
+
value2submit: function(value) {
|
2924
4475
|
return this.value2str(value);
|
2925
4476
|
},
|
2926
4477
|
|
@@ -2955,12 +4506,12 @@ $(function(){
|
|
2955
4506
|
@property tpl
|
2956
4507
|
@default <div></div>
|
2957
4508
|
**/
|
2958
|
-
tpl:'<div></div>',
|
4509
|
+
tpl:'<div class="editable-date"></div>',
|
2959
4510
|
/**
|
2960
4511
|
@property inputclass
|
2961
|
-
@default
|
4512
|
+
@default null
|
2962
4513
|
**/
|
2963
|
-
inputclass:
|
4514
|
+
inputclass: null,
|
2964
4515
|
/**
|
2965
4516
|
Format used for sending value to server. Also applied when converting date from <code>data-value</code> attribute.<br>
|
2966
4517
|
Full list of tokens: http://docs.jquery.com/UI/Datepicker/formatDate
|
@@ -2995,7 +4546,8 @@ $(function(){
|
|
2995
4546
|
datepicker: {
|
2996
4547
|
firstDay: 0,
|
2997
4548
|
changeYear: true,
|
2998
|
-
changeMonth: true
|
4549
|
+
changeMonth: true,
|
4550
|
+
showOtherMonths: true
|
2999
4551
|
},
|
3000
4552
|
/**
|
3001
4553
|
Text shown as clear date button.
|
@@ -3009,6 +4561,84 @@ $(function(){
|
|
3009
4561
|
});
|
3010
4562
|
|
3011
4563
|
$.fn.editabletypes.dateui = DateUI;
|
3012
|
-
$.fn.editabletypes.date = DateUI;
|
3013
4564
|
|
3014
4565
|
}(window.jQuery));
|
4566
|
+
|
4567
|
+
/**
|
4568
|
+
jQuery UI datefield input - modification for inline mode.
|
4569
|
+
Shows normal <input type="text"> and binds popup datepicker.
|
4570
|
+
Automatically shown in inline mode.
|
4571
|
+
|
4572
|
+
@class dateuifield
|
4573
|
+
@extends dateui
|
4574
|
+
|
4575
|
+
@since 1.4.0
|
4576
|
+
**/
|
4577
|
+
(function ($) {
|
4578
|
+
"use strict";
|
4579
|
+
|
4580
|
+
var DateUIField = function (options) {
|
4581
|
+
this.init('dateuifield', options, DateUIField.defaults);
|
4582
|
+
this.initPicker(options, DateUIField.defaults);
|
4583
|
+
};
|
4584
|
+
|
4585
|
+
$.fn.editableutils.inherit(DateUIField, $.fn.editabletypes.dateui);
|
4586
|
+
|
4587
|
+
$.extend(DateUIField.prototype, {
|
4588
|
+
render: function () {
|
4589
|
+
// this.$input = this.$tpl.find('input');
|
4590
|
+
this.$input.datepicker(this.options.datepicker);
|
4591
|
+
$.fn.editabletypes.text.prototype.renderClear.call(this);
|
4592
|
+
},
|
4593
|
+
|
4594
|
+
value2input: function(value) {
|
4595
|
+
this.$input.val($.datepicker.formatDate(this.options.viewformat, value));
|
4596
|
+
},
|
4597
|
+
|
4598
|
+
input2value: function() {
|
4599
|
+
return this.html2value(this.$input.val());
|
4600
|
+
},
|
4601
|
+
|
4602
|
+
activate: function() {
|
4603
|
+
$.fn.editabletypes.text.prototype.activate.call(this);
|
4604
|
+
},
|
4605
|
+
|
4606
|
+
toggleClear: function() {
|
4607
|
+
$.fn.editabletypes.text.prototype.toggleClear.call(this);
|
4608
|
+
},
|
4609
|
+
|
4610
|
+
autosubmit: function() {
|
4611
|
+
//reset autosubmit to empty
|
4612
|
+
}
|
4613
|
+
});
|
4614
|
+
|
4615
|
+
DateUIField.defaults = $.extend({}, $.fn.editabletypes.dateui.defaults, {
|
4616
|
+
/**
|
4617
|
+
@property tpl
|
4618
|
+
@default <input type="text">
|
4619
|
+
**/
|
4620
|
+
tpl: '<input type="text"/>',
|
4621
|
+
/**
|
4622
|
+
@property inputclass
|
4623
|
+
@default null
|
4624
|
+
**/
|
4625
|
+
inputclass: null,
|
4626
|
+
|
4627
|
+
/* datepicker config */
|
4628
|
+
datepicker: {
|
4629
|
+
showOn: "button",
|
4630
|
+
buttonImage: "http://jqueryui.com/resources/demos/datepicker/images/calendar.gif",
|
4631
|
+
buttonImageOnly: true,
|
4632
|
+
firstDay: 0,
|
4633
|
+
changeYear: true,
|
4634
|
+
changeMonth: true,
|
4635
|
+
showOtherMonths: true
|
4636
|
+
},
|
4637
|
+
|
4638
|
+
/* disable clear link */
|
4639
|
+
clear: false
|
4640
|
+
});
|
4641
|
+
|
4642
|
+
$.fn.editabletypes.dateuifield = DateUIField;
|
4643
|
+
|
4644
|
+
}(window.jQuery));
|