bootstrap-x-editable-rails 1.3.0 → 1.4.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.
data/.gitignore
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
/*! X-editable - v1.
|
1
|
+
/*! X-editable - v1.4.0
|
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.
|
@@ -20,24 +20,16 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
|
|
20
20
|
if(!this.options.scope) {
|
21
21
|
this.options.scope = this;
|
22
22
|
}
|
23
|
-
|
23
|
+
//nothing shown after init
|
24
24
|
};
|
25
25
|
|
26
26
|
EditableForm.prototype = {
|
27
27
|
constructor: EditableForm,
|
28
28
|
initInput: function() { //called once
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
TypeConstructor = $.fn.editabletypes[this.options.type];
|
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
|
-
|
29
|
+
//take input from options (as it is created in editable-element)
|
30
|
+
this.input = this.options.input;
|
31
|
+
|
32
|
+
//set initial value
|
41
33
|
this.value = this.input.str2value(this.options.value);
|
42
34
|
},
|
43
35
|
initTemplate: function() {
|
@@ -52,47 +44,49 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
|
|
52
44
|
@method render
|
53
45
|
**/
|
54
46
|
render: function() {
|
47
|
+
//init loader
|
55
48
|
this.$loading = $($.fn.editableform.loading);
|
56
49
|
this.$div.empty().append(this.$loading);
|
57
|
-
this.showLoading();
|
58
50
|
|
59
51
|
//init form template and buttons
|
60
|
-
this.initTemplate();
|
52
|
+
this.initTemplate();
|
61
53
|
if(this.options.showbuttons) {
|
62
54
|
this.initButtons();
|
63
55
|
} else {
|
64
56
|
this.$form.find('.editable-buttons').remove();
|
65
57
|
}
|
66
58
|
|
59
|
+
//show loading state
|
60
|
+
this.showLoading();
|
61
|
+
|
67
62
|
/**
|
68
63
|
Fired when rendering starts
|
69
64
|
@event rendering
|
70
65
|
@param {Object} event event object
|
71
66
|
**/
|
72
67
|
this.$div.triggerHandler('rendering');
|
68
|
+
|
69
|
+
//init input
|
70
|
+
this.initInput();
|
71
|
+
|
72
|
+
//append input to form
|
73
|
+
this.input.prerender();
|
74
|
+
this.$form.find('div.editable-input').append(this.input.$tpl);
|
73
75
|
|
76
|
+
//append form to container
|
77
|
+
this.$div.append(this.$form);
|
78
|
+
|
74
79
|
//render input
|
75
80
|
$.when(this.input.render())
|
76
81
|
.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
|
82
|
+
//setup input to submit automatically when no buttons shown
|
81
83
|
if(!this.options.showbuttons) {
|
82
84
|
this.input.autosubmit();
|
83
85
|
}
|
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
86
|
|
93
87
|
//attach 'cancel' handler
|
94
88
|
this.$form.find('.editable-cancel').click($.proxy(this.cancel, this));
|
95
|
-
|
89
|
+
|
96
90
|
if(this.input.error) {
|
97
91
|
this.error(this.input.error);
|
98
92
|
this.$form.find('.editable-submit').attr('disabled', true);
|
@@ -116,6 +110,11 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
|
|
116
110
|
this.$div.triggerHandler('rendered');
|
117
111
|
|
118
112
|
this.showForm();
|
113
|
+
|
114
|
+
//call postrender method to perform actions required visibility of form
|
115
|
+
if(this.input.postrender) {
|
116
|
+
this.input.postrender();
|
117
|
+
}
|
119
118
|
}, this));
|
120
119
|
},
|
121
120
|
cancel: function() {
|
@@ -127,11 +126,17 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
|
|
127
126
|
this.$div.triggerHandler('cancel');
|
128
127
|
},
|
129
128
|
showLoading: function() {
|
130
|
-
var w;
|
129
|
+
var w, h;
|
131
130
|
if(this.$form) {
|
132
|
-
//set loading size equal to form
|
133
|
-
this.$
|
134
|
-
this.$
|
131
|
+
//set loading size equal to form
|
132
|
+
w = this.$form.outerWidth();
|
133
|
+
h = this.$form.outerHeight();
|
134
|
+
if(w) {
|
135
|
+
this.$loading.width(w);
|
136
|
+
}
|
137
|
+
if(h) {
|
138
|
+
this.$loading.height(h);
|
139
|
+
}
|
135
140
|
this.$form.hide();
|
136
141
|
} else {
|
137
142
|
//stretch loading to fill container width
|
@@ -159,14 +164,23 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
|
|
159
164
|
|
160
165
|
error: function(msg) {
|
161
166
|
var $group = this.$form.find('.control-group'),
|
162
|
-
|
167
|
+
$block = this.$form.find('.editable-error-block'),
|
168
|
+
lines;
|
163
169
|
|
164
170
|
if(msg === false) {
|
165
171
|
$group.removeClass($.fn.editableform.errorGroupClass);
|
166
172
|
$block.removeClass($.fn.editableform.errorBlockClass).empty().hide();
|
167
173
|
} else {
|
174
|
+
//convert newline to <br> for more pretty error display
|
175
|
+
if(msg) {
|
176
|
+
lines = msg.split("\n");
|
177
|
+
for (var i = 0; i < lines.length; i++) {
|
178
|
+
lines[i] = $('<div>').text(lines[i]).html();
|
179
|
+
}
|
180
|
+
msg = lines.join('<br>');
|
181
|
+
}
|
168
182
|
$group.addClass($.fn.editableform.errorGroupClass);
|
169
|
-
$block.addClass($.fn.editableform.errorBlockClass).
|
183
|
+
$block.addClass($.fn.editableform.errorBlockClass).html(msg).show();
|
170
184
|
}
|
171
185
|
},
|
172
186
|
|
@@ -299,10 +313,15 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
|
|
299
313
|
},
|
300
314
|
|
301
315
|
option: function(key, value) {
|
302
|
-
this.options
|
316
|
+
if(key in this.options) {
|
317
|
+
this.options[key] = value;
|
318
|
+
}
|
319
|
+
|
303
320
|
if(key === 'value') {
|
304
321
|
this.setValue(value);
|
305
322
|
}
|
323
|
+
|
324
|
+
//do not pass option to input as it is passed in editable-element
|
306
325
|
},
|
307
326
|
|
308
327
|
setValue: function(value, convertStr) {
|
@@ -311,6 +330,11 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
|
|
311
330
|
} else {
|
312
331
|
this.value = value;
|
313
332
|
}
|
333
|
+
|
334
|
+
//if form is visible, update input
|
335
|
+
if(this.$form && this.$form.is(':visible')) {
|
336
|
+
this.input.value2input(this.value);
|
337
|
+
}
|
314
338
|
}
|
315
339
|
};
|
316
340
|
|
@@ -372,7 +396,7 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
|
|
372
396
|
url: function(params) {
|
373
397
|
if(params.value === 'abc') {
|
374
398
|
var d = new $.Deferred;
|
375
|
-
return d.reject('
|
399
|
+
return d.reject('error message'); //returning error via deferred object
|
376
400
|
} else {
|
377
401
|
someModel.set(params.name, params.value); //save data in some js model
|
378
402
|
}
|
@@ -463,21 +487,21 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
|
|
463
487
|
/**
|
464
488
|
Additional options for ajax request.
|
465
489
|
List of values: http://api.jquery.com/jQuery.ajax
|
466
|
-
|
490
|
+
|
467
491
|
@property ajaxOptions
|
468
492
|
@type object
|
469
493
|
@default null
|
470
494
|
@since 1.1.1
|
495
|
+
@example
|
496
|
+
ajaxOptions: {
|
497
|
+
type: 'put',
|
498
|
+
dataType: 'json'
|
499
|
+
}
|
471
500
|
**/
|
472
501
|
ajaxOptions: null,
|
473
502
|
/**
|
474
503
|
Whether to show buttons or not.
|
475
|
-
Form without buttons
|
476
|
-
@example
|
477
|
-
ajaxOptions: {
|
478
|
-
method: 'PUT',
|
479
|
-
dataType: 'xml'
|
480
|
-
}
|
504
|
+
Form without buttons is auto-submitted.
|
481
505
|
|
482
506
|
@property showbuttons
|
483
507
|
@type boolean
|
@@ -621,19 +645,22 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
|
|
621
645
|
return newObj;
|
622
646
|
},
|
623
647
|
|
624
|
-
|
625
|
-
|
648
|
+
/*
|
649
|
+
exclude complex objects from $.data() before pass to config
|
626
650
|
*/
|
627
651
|
getConfigData: function($element) {
|
628
652
|
var data = {};
|
629
653
|
$.each($element.data(), function(k, v) {
|
630
|
-
if(typeof v !== 'object' || (v && typeof v === 'object' && v.constructor === Object)) {
|
654
|
+
if(typeof v !== 'object' || (v && typeof v === 'object' && (v.constructor === Object || v.constructor === Array))) {
|
631
655
|
data[k] = v;
|
632
656
|
}
|
633
657
|
});
|
634
658
|
return data;
|
635
659
|
},
|
636
660
|
|
661
|
+
/*
|
662
|
+
returns keys of object
|
663
|
+
*/
|
637
664
|
objectKeys: function(o) {
|
638
665
|
if (Object.keys) {
|
639
666
|
return Object.keys(o);
|
@@ -657,9 +684,82 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
|
|
657
684
|
**/
|
658
685
|
escape: function(str) {
|
659
686
|
return $('<div>').text(str).html();
|
660
|
-
}
|
687
|
+
},
|
688
|
+
|
689
|
+
/*
|
690
|
+
returns array items from sourceData having value property equal or inArray of 'value'
|
691
|
+
*/
|
692
|
+
itemsByValue: function(value, sourceData) {
|
693
|
+
if(!sourceData || value === null) {
|
694
|
+
return [];
|
695
|
+
}
|
696
|
+
|
697
|
+
//convert to array
|
698
|
+
if(!$.isArray(value)) {
|
699
|
+
value = [value];
|
700
|
+
}
|
701
|
+
|
702
|
+
/*jslint eqeq: true*/
|
703
|
+
var result = $.grep(sourceData, function(o){
|
704
|
+
return $.grep(value, function(v){ return v == o.value; }).length;
|
705
|
+
});
|
706
|
+
/*jslint eqeq: false*/
|
707
|
+
|
708
|
+
return result;
|
709
|
+
},
|
710
|
+
|
711
|
+
/*
|
712
|
+
Returns input by options: type, mode.
|
713
|
+
*/
|
714
|
+
createInput: function(options) {
|
715
|
+
var TypeConstructor, typeOptions, input,
|
716
|
+
type = options.type;
|
717
|
+
|
718
|
+
//`date` is some kind of virtual type that is transformed to one of exact types
|
719
|
+
//depending on mode and core lib
|
720
|
+
if(type === 'date') {
|
721
|
+
//inline
|
722
|
+
if(options.mode === 'inline') {
|
723
|
+
if($.fn.editabletypes.datefield) {
|
724
|
+
type = 'datefield';
|
725
|
+
} else if($.fn.editabletypes.dateuifield) {
|
726
|
+
type = 'dateuifield';
|
727
|
+
}
|
728
|
+
//popup
|
729
|
+
} else {
|
730
|
+
if($.fn.editabletypes.date) {
|
731
|
+
type = 'date';
|
732
|
+
} else if($.fn.editabletypes.dateui) {
|
733
|
+
type = 'dateui';
|
734
|
+
}
|
735
|
+
}
|
736
|
+
|
737
|
+
//if type still `date` and not exist in types, replace with `combodate` that is base input
|
738
|
+
if(type === 'date' && !$.fn.editabletypes.date) {
|
739
|
+
type = 'combodate';
|
740
|
+
}
|
741
|
+
}
|
742
|
+
|
743
|
+
//change wysihtml5 to textarea for jquery UI and plain versions
|
744
|
+
if(type === 'wysihtml5' && !$.fn.editabletypes[type]) {
|
745
|
+
type = 'textarea';
|
746
|
+
}
|
747
|
+
|
748
|
+
//create input of specified type. Input will be used for converting value, not in form
|
749
|
+
if(typeof $.fn.editabletypes[type] === 'function') {
|
750
|
+
TypeConstructor = $.fn.editabletypes[type];
|
751
|
+
typeOptions = this.sliceObj(options, this.objectKeys(TypeConstructor.defaults));
|
752
|
+
input = new TypeConstructor(typeOptions);
|
753
|
+
return input;
|
754
|
+
} else {
|
755
|
+
$.error('Unknown type: '+ type);
|
756
|
+
return false;
|
757
|
+
}
|
758
|
+
}
|
759
|
+
|
661
760
|
};
|
662
761
|
}(window.jQuery));
|
762
|
+
|
663
763
|
/**
|
664
764
|
Attaches stand-alone container with editable-form to HTML element. Element is used only for positioning, value is not stored anywhere.<br>
|
665
765
|
This method applied internally in <code>$().editable()</code>. You should subscribe on it's events (save / cancel) to get profit of it.<br>
|
@@ -671,12 +771,16 @@ Applied as jQuery method.
|
|
671
771
|
**/
|
672
772
|
(function ($) {
|
673
773
|
|
674
|
-
var
|
774
|
+
var Popup = function (element, options) {
|
675
775
|
this.init(element, options);
|
676
776
|
};
|
777
|
+
|
778
|
+
var Inline = function (element, options) {
|
779
|
+
this.init(element, options);
|
780
|
+
};
|
677
781
|
|
678
782
|
//methods
|
679
|
-
|
783
|
+
Popup.prototype = {
|
680
784
|
containerName: null, //tbd in child class
|
681
785
|
innerCss: null, //tbd in child class
|
682
786
|
init: function(element, options) {
|
@@ -684,6 +788,10 @@ Applied as jQuery method.
|
|
684
788
|
//todo: what is in priority: data or js?
|
685
789
|
this.options = $.extend({}, $.fn.editableContainer.defaults, $.fn.editableutils.getConfigData(this.$element), options);
|
686
790
|
this.splitOptions();
|
791
|
+
|
792
|
+
//set scope of form callbacks to element
|
793
|
+
this.formOptions.scope = this.$element[0];
|
794
|
+
|
687
795
|
this.initContainer();
|
688
796
|
|
689
797
|
//bind 'destroyed' listener to destroy container when element is removed from dom
|
@@ -691,7 +799,7 @@ Applied as jQuery method.
|
|
691
799
|
this.destroy();
|
692
800
|
}, this));
|
693
801
|
|
694
|
-
//attach document
|
802
|
+
//attach document handler to close containers on click / escape
|
695
803
|
if(!$(document).data('editable-handlers-attached')) {
|
696
804
|
//close all on escape
|
697
805
|
$(document).on('keyup.editable', function (e) {
|
@@ -703,15 +811,22 @@ Applied as jQuery method.
|
|
703
811
|
|
704
812
|
//close containers when click outside
|
705
813
|
$(document).on('click.editable', function(e) {
|
706
|
-
var $target = $(e.target)
|
814
|
+
var $target = $(e.target), i,
|
815
|
+
exclude_classes = ['.editable-container',
|
816
|
+
'.ui-datepicker-header',
|
817
|
+
'.modal-backdrop',
|
818
|
+
'.bootstrap-wysihtml5-insert-image-modal',
|
819
|
+
'.bootstrap-wysihtml5-insert-link-modal'];
|
707
820
|
|
708
|
-
//if click inside
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
EditableContainer.prototype.closeOthers(e.target);
|
821
|
+
//if click inside one of exclude classes --> no nothing
|
822
|
+
for(i=0; i<exclude_classes.length; i++) {
|
823
|
+
if($target.is(exclude_classes[i]) || $target.parents(exclude_classes[i]).length) {
|
824
|
+
return;
|
825
|
+
}
|
714
826
|
}
|
827
|
+
|
828
|
+
//close all open containers (except one - target)
|
829
|
+
Popup.prototype.closeOthers(e.target);
|
715
830
|
});
|
716
831
|
|
717
832
|
$(document).data('editable-handlers-attached', true);
|
@@ -723,6 +838,7 @@ Applied as jQuery method.
|
|
723
838
|
this.containerOptions = {};
|
724
839
|
this.formOptions = {};
|
725
840
|
var cDef = $.fn[this.containerName].defaults;
|
841
|
+
//keys defined in container defaults go to container, others go to form
|
726
842
|
for(var k in this.options) {
|
727
843
|
if(k in cDef) {
|
728
844
|
this.containerOptions[k] = this.options[k];
|
@@ -732,18 +848,34 @@ Applied as jQuery method.
|
|
732
848
|
}
|
733
849
|
},
|
734
850
|
|
851
|
+
/*
|
852
|
+
Returns jquery object of container
|
853
|
+
@method tip()
|
854
|
+
*/
|
855
|
+
tip: function() {
|
856
|
+
return this.container() ? this.container().$tip : null;
|
857
|
+
},
|
858
|
+
|
859
|
+
/* returns container object */
|
860
|
+
container: function() {
|
861
|
+
return this.$element.data(this.containerName);
|
862
|
+
},
|
863
|
+
|
864
|
+
call: function() {
|
865
|
+
this.$element[this.containerName].apply(this.$element, arguments);
|
866
|
+
},
|
867
|
+
|
735
868
|
initContainer: function(){
|
736
869
|
this.call(this.containerOptions);
|
737
870
|
},
|
738
871
|
|
739
|
-
|
740
|
-
this
|
741
|
-
this.$form = $('<div>')
|
872
|
+
renderForm: function() {
|
873
|
+
this.$form
|
742
874
|
.editableform(this.formOptions)
|
743
875
|
.on({
|
744
|
-
save: $.proxy(this.save, this),
|
745
|
-
|
746
|
-
|
876
|
+
save: $.proxy(this.save, this), //click on submit button (value changed)
|
877
|
+
nochange: $.proxy(function(){ this.hide('nochange'); }, this), //click on submit button (value NOT changed)
|
878
|
+
cancel: $.proxy(function(){ this.hide('cancel'); }, this), //click on calcel button
|
747
879
|
show: $.proxy(this.setPosition, this), //re-position container every time form is shown (occurs each time after loading state)
|
748
880
|
rendering: $.proxy(this.setPosition, this), //this allows to place container correctly when loading shown
|
749
881
|
rendered: $.proxy(function(){
|
@@ -760,31 +892,16 @@ Applied as jQuery method.
|
|
760
892
|
**/
|
761
893
|
this.$element.triggerHandler('shown');
|
762
894
|
}, this)
|
763
|
-
})
|
764
|
-
|
895
|
+
})
|
896
|
+
.editableform('render');
|
765
897
|
},
|
766
898
|
|
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
899
|
/**
|
784
900
|
Shows container with form
|
785
901
|
@method show()
|
786
902
|
@param {boolean} closeAll Whether to close all other editable containers when showing this one. Default true.
|
787
|
-
**/
|
903
|
+
**/
|
904
|
+
/* Note: poshytip owerwrites this method totally! */
|
788
905
|
show: function (closeAll) {
|
789
906
|
this.$element.addClass('editable-open');
|
790
907
|
if(closeAll !== false) {
|
@@ -792,16 +909,37 @@ Applied as jQuery method.
|
|
792
909
|
this.closeOthers(this.$element[0]);
|
793
910
|
}
|
794
911
|
|
912
|
+
//show container itself
|
795
913
|
this.innerShow();
|
796
|
-
},
|
797
|
-
|
798
|
-
/* internal show method. To be overwritten in child classes */
|
799
|
-
innerShow: function () {
|
800
|
-
this.call('show');
|
801
914
|
this.tip().addClass('editable-container');
|
802
|
-
|
803
|
-
|
804
|
-
|
915
|
+
|
916
|
+
/*
|
917
|
+
Currently, form is re-rendered on every show.
|
918
|
+
The main reason is that we dont know, what container will do with content when closed:
|
919
|
+
remove(), detach() or just hide().
|
920
|
+
|
921
|
+
Detaching form itself before hide and re-insert before show is good solution,
|
922
|
+
but visually it looks ugly, as container changes size before hide.
|
923
|
+
*/
|
924
|
+
|
925
|
+
//if form already exist - delete previous data
|
926
|
+
if(this.$form) {
|
927
|
+
//todo: destroy prev data!
|
928
|
+
//this.$form.destroy();
|
929
|
+
}
|
930
|
+
|
931
|
+
this.$form = $('<div>');
|
932
|
+
|
933
|
+
//insert form into container body
|
934
|
+
if(this.tip().is(this.innerCss)) {
|
935
|
+
//for inline container
|
936
|
+
this.tip().append(this.$form);
|
937
|
+
} else {
|
938
|
+
this.tip().find(this.innerCss).append(this.$form);
|
939
|
+
}
|
940
|
+
|
941
|
+
//render form
|
942
|
+
this.renderForm();
|
805
943
|
},
|
806
944
|
|
807
945
|
/**
|
@@ -813,8 +951,10 @@ Applied as jQuery method.
|
|
813
951
|
if(!this.tip() || !this.tip().is(':visible') || !this.$element.hasClass('editable-open')) {
|
814
952
|
return;
|
815
953
|
}
|
954
|
+
|
816
955
|
this.$element.removeClass('editable-open');
|
817
956
|
this.innerHide();
|
957
|
+
|
818
958
|
/**
|
819
959
|
Fired when container was hidden. It occurs on both save or cancel.
|
820
960
|
|
@@ -832,9 +972,14 @@ Applied as jQuery method.
|
|
832
972
|
this.$element.triggerHandler('hidden', reason);
|
833
973
|
},
|
834
974
|
|
975
|
+
/* internal show method. To be overwritten in child classes */
|
976
|
+
innerShow: function () {
|
977
|
+
|
978
|
+
},
|
979
|
+
|
835
980
|
/* internal hide method. To be overwritten in child classes */
|
836
981
|
innerHide: function () {
|
837
|
-
|
982
|
+
|
838
983
|
},
|
839
984
|
|
840
985
|
/**
|
@@ -843,7 +988,7 @@ Applied as jQuery method.
|
|
843
988
|
@param {boolean} closeAll Whether to close all other editable containers when showing this one. Default true.
|
844
989
|
**/
|
845
990
|
toggle: function(closeAll) {
|
846
|
-
if(this.tip && this.tip().is(':visible')) {
|
991
|
+
if(this.container() && this.tip() && this.tip().is(':visible')) {
|
847
992
|
this.hide();
|
848
993
|
} else {
|
849
994
|
this.show(closeAll);
|
@@ -911,9 +1056,17 @@ Applied as jQuery method.
|
|
911
1056
|
@method destroy()
|
912
1057
|
**/
|
913
1058
|
destroy: function() {
|
914
|
-
this.
|
1059
|
+
this.hide();
|
1060
|
+
this.innerDestroy();
|
1061
|
+
this.$element.off('destroyed');
|
1062
|
+
this.$element.removeData('editableContainer');
|
915
1063
|
},
|
916
1064
|
|
1065
|
+
/* to be overwritten in child classes */
|
1066
|
+
innerDestroy: function() {
|
1067
|
+
|
1068
|
+
},
|
1069
|
+
|
917
1070
|
/*
|
918
1071
|
Closes other containers except one related to passed element.
|
919
1072
|
Other containers can be cancelled or submitted (depends on onblur option)
|
@@ -972,11 +1125,12 @@ Applied as jQuery method.
|
|
972
1125
|
return this.each(function () {
|
973
1126
|
var $this = $(this),
|
974
1127
|
dataKey = 'editableContainer',
|
975
|
-
data = $this.data(dataKey),
|
976
|
-
options = typeof option === 'object' && option
|
1128
|
+
data = $this.data(dataKey),
|
1129
|
+
options = typeof option === 'object' && option,
|
1130
|
+
Constructor = (options.mode === 'inline') ? Inline : Popup;
|
977
1131
|
|
978
1132
|
if (!data) {
|
979
|
-
$this.data(dataKey, (data = new
|
1133
|
+
$this.data(dataKey, (data = new Constructor(this, options)));
|
980
1134
|
}
|
981
1135
|
|
982
1136
|
if (typeof option === 'string') { //call method
|
@@ -985,8 +1139,9 @@ Applied as jQuery method.
|
|
985
1139
|
});
|
986
1140
|
};
|
987
1141
|
|
988
|
-
//store
|
989
|
-
$.fn.editableContainer.
|
1142
|
+
//store constructors
|
1143
|
+
$.fn.editableContainer.Popup = Popup;
|
1144
|
+
$.fn.editableContainer.Inline = Inline;
|
990
1145
|
|
991
1146
|
//defaults
|
992
1147
|
$.fn.editableContainer.defaults = {
|
@@ -1025,7 +1180,25 @@ Applied as jQuery method.
|
|
1025
1180
|
@default 'cancel'
|
1026
1181
|
@since 1.1.1
|
1027
1182
|
**/
|
1028
|
-
onblur: 'cancel'
|
1183
|
+
onblur: 'cancel',
|
1184
|
+
|
1185
|
+
/**
|
1186
|
+
Animation speed (inline mode)
|
1187
|
+
@property anim
|
1188
|
+
@type string
|
1189
|
+
@default 'fast'
|
1190
|
+
**/
|
1191
|
+
anim: 'fast',
|
1192
|
+
|
1193
|
+
/**
|
1194
|
+
Mode of editable, can be `popup` or `inline`
|
1195
|
+
|
1196
|
+
@property mode
|
1197
|
+
@type string
|
1198
|
+
@default 'popup'
|
1199
|
+
@since 1.4.0
|
1200
|
+
**/
|
1201
|
+
mode: 'popup'
|
1029
1202
|
};
|
1030
1203
|
|
1031
1204
|
/*
|
@@ -1042,6 +1215,56 @@ Applied as jQuery method.
|
|
1042
1215
|
|
1043
1216
|
}(window.jQuery));
|
1044
1217
|
|
1218
|
+
/**
|
1219
|
+
* Editable Inline
|
1220
|
+
* ---------------------
|
1221
|
+
*/
|
1222
|
+
(function ($) {
|
1223
|
+
|
1224
|
+
//copy prototype from EditableContainer
|
1225
|
+
//extend methods
|
1226
|
+
$.extend($.fn.editableContainer.Inline.prototype, $.fn.editableContainer.Popup.prototype, {
|
1227
|
+
containerName: 'editableform',
|
1228
|
+
innerCss: '.editable-inline',
|
1229
|
+
|
1230
|
+
initContainer: function(){
|
1231
|
+
//container is <span> element
|
1232
|
+
this.$tip = $('<span></span>').addClass('editable-inline');
|
1233
|
+
|
1234
|
+
//convert anim to miliseconds (int)
|
1235
|
+
if(!this.options.anim) {
|
1236
|
+
this.options.anim = 0;
|
1237
|
+
}
|
1238
|
+
},
|
1239
|
+
|
1240
|
+
splitOptions: function() {
|
1241
|
+
//all options are passed to form
|
1242
|
+
this.containerOptions = {};
|
1243
|
+
this.formOptions = this.options;
|
1244
|
+
},
|
1245
|
+
|
1246
|
+
tip: function() {
|
1247
|
+
return this.$tip;
|
1248
|
+
},
|
1249
|
+
|
1250
|
+
innerShow: function () {
|
1251
|
+
this.$element.hide();
|
1252
|
+
this.tip().insertAfter(this.$element).show();
|
1253
|
+
},
|
1254
|
+
|
1255
|
+
innerHide: function () {
|
1256
|
+
this.$tip.hide(this.options.anim, $.proxy(function() {
|
1257
|
+
this.$element.show();
|
1258
|
+
this.tip().empty().remove();
|
1259
|
+
}, this));
|
1260
|
+
},
|
1261
|
+
|
1262
|
+
innerDestroy: function() {
|
1263
|
+
this.tip().remove();
|
1264
|
+
}
|
1265
|
+
});
|
1266
|
+
|
1267
|
+
}(window.jQuery));
|
1045
1268
|
/**
|
1046
1269
|
Makes editable any HTML element on the page. Applied as jQuery method.
|
1047
1270
|
|
@@ -1059,27 +1282,15 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1059
1282
|
Editable.prototype = {
|
1060
1283
|
constructor: Editable,
|
1061
1284
|
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
|
-
|
1285
|
+
var isValueByText = false,
|
1286
|
+
doAutotext, finalize;
|
1287
|
+
|
1073
1288
|
//name
|
1074
1289
|
this.options.name = this.options.name || this.$element.attr('id');
|
1075
1290
|
|
1076
1291
|
//create input of specified type. Input will be used for converting value, not in form
|
1077
|
-
|
1078
|
-
|
1079
|
-
this.typeOptions = $.fn.editableutils.sliceObj(this.options, $.fn.editableutils.objectKeys(TypeConstructor.defaults));
|
1080
|
-
this.input = new TypeConstructor(this.typeOptions);
|
1081
|
-
} else {
|
1082
|
-
$.error('Unknown type: '+ this.options.type);
|
1292
|
+
this.input = $.fn.editableutils.createInput(this.options);
|
1293
|
+
if(!this.input) {
|
1083
1294
|
return;
|
1084
1295
|
}
|
1085
1296
|
|
@@ -1140,8 +1351,12 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1140
1351
|
|
1141
1352
|
@event init
|
1142
1353
|
@param {Object} event event object
|
1143
|
-
@param {Object} editable editable instance
|
1354
|
+
@param {Object} editable editable instance (as here it cannot accessed via data('editable'))
|
1144
1355
|
@since 1.2.0
|
1356
|
+
@example
|
1357
|
+
$('#username').on('init', function(e, editable) {
|
1358
|
+
alert('initialized ' + editable.options.name);
|
1359
|
+
});
|
1145
1360
|
**/
|
1146
1361
|
this.$element.triggerHandler('init', this);
|
1147
1362
|
}, this));
|
@@ -1152,18 +1367,20 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1152
1367
|
Can call custom display method from options.
|
1153
1368
|
Can return deferred object.
|
1154
1369
|
@method render()
|
1370
|
+
@param {mixed} response server response (if exist) to pass into display function
|
1155
1371
|
*/
|
1156
|
-
render: function() {
|
1372
|
+
render: function(response) {
|
1157
1373
|
//do not display anything
|
1158
1374
|
if(this.options.display === false) {
|
1159
1375
|
return;
|
1160
1376
|
}
|
1377
|
+
|
1161
1378
|
//if it is input with source, we pass callback in third param to be called when source is loaded
|
1162
1379
|
if(this.input.options.hasOwnProperty('source')) {
|
1163
|
-
return this.input.value2html(this.value, this.$element[0], this.options.display);
|
1380
|
+
return this.input.value2html(this.value, this.$element[0], this.options.display, response);
|
1164
1381
|
//if display method defined --> use it
|
1165
1382
|
} else if(typeof this.options.display === 'function') {
|
1166
|
-
return this.options.display.call(this.$element[0], this.value);
|
1383
|
+
return this.options.display.call(this.$element[0], this.value, response);
|
1167
1384
|
//else use input's original value2html() method
|
1168
1385
|
} else {
|
1169
1386
|
return this.input.value2html(this.value, this.$element[0]);
|
@@ -1233,12 +1450,7 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1233
1450
|
|
1234
1451
|
//disabled
|
1235
1452
|
if(key === 'disabled') {
|
1236
|
-
|
1237
|
-
this.disable();
|
1238
|
-
} else {
|
1239
|
-
this.enable();
|
1240
|
-
}
|
1241
|
-
return;
|
1453
|
+
return value ? this.disable() : this.enable();
|
1242
1454
|
}
|
1243
1455
|
|
1244
1456
|
//value
|
@@ -1250,6 +1462,12 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1250
1462
|
if(this.container) {
|
1251
1463
|
this.container.option(key, value);
|
1252
1464
|
}
|
1465
|
+
|
1466
|
+
//pass option to input directly (as it points to the same in form)
|
1467
|
+
if(this.input.option) {
|
1468
|
+
this.input.option(key, value);
|
1469
|
+
}
|
1470
|
+
|
1253
1471
|
},
|
1254
1472
|
|
1255
1473
|
/*
|
@@ -1291,7 +1509,8 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1291
1509
|
//init editableContainer: popover, tooltip, inline, etc..
|
1292
1510
|
if(!this.container) {
|
1293
1511
|
var containerOptions = $.extend({}, this.options, {
|
1294
|
-
value: this.value
|
1512
|
+
value: this.value,
|
1513
|
+
input: this.input //pass input to form (as it is already created)
|
1295
1514
|
});
|
1296
1515
|
this.$element.editableContainer(containerOptions);
|
1297
1516
|
this.$element.on("save.internal", $.proxy(this.save, this));
|
@@ -1338,8 +1557,7 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1338
1557
|
this.$element.removeClass('editable-unsaved');
|
1339
1558
|
}
|
1340
1559
|
|
1341
|
-
|
1342
|
-
this.setValue(params.newValue);
|
1560
|
+
this.setValue(params.newValue, false, params.response);
|
1343
1561
|
|
1344
1562
|
/**
|
1345
1563
|
Fired when new value was submitted. You can use <code>$(this).data('editable')</code> to access to editable instance
|
@@ -1351,13 +1569,7 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1351
1569
|
@param {Object} params.response ajax response
|
1352
1570
|
@example
|
1353
1571
|
$('#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
|
-
}
|
1572
|
+
alert('Saved value: ' + params.newValue);
|
1361
1573
|
});
|
1362
1574
|
**/
|
1363
1575
|
//event itself is triggered by editableContainer. Description here is only for documentation
|
@@ -1375,7 +1587,7 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1375
1587
|
@param {mixed} value new value
|
1376
1588
|
@param {boolean} convertStr whether to convert value from string to internal format
|
1377
1589
|
**/
|
1378
|
-
setValue: function(value, convertStr) {
|
1590
|
+
setValue: function(value, convertStr, response) {
|
1379
1591
|
if(convertStr) {
|
1380
1592
|
this.value = this.input.str2value(value);
|
1381
1593
|
} else {
|
@@ -1384,7 +1596,7 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1384
1596
|
if(this.container) {
|
1385
1597
|
this.container.option('value', this.value);
|
1386
1598
|
}
|
1387
|
-
$.when(this.render())
|
1599
|
+
$.when(this.render(response))
|
1388
1600
|
.then($.proxy(function() {
|
1389
1601
|
this.handleEmpty();
|
1390
1602
|
}, this));
|
@@ -1398,7 +1610,28 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1398
1610
|
if(this.container) {
|
1399
1611
|
this.container.activate();
|
1400
1612
|
}
|
1401
|
-
}
|
1613
|
+
},
|
1614
|
+
|
1615
|
+
/**
|
1616
|
+
Removes editable feature from element
|
1617
|
+
@method destroy()
|
1618
|
+
**/
|
1619
|
+
destroy: function() {
|
1620
|
+
if(this.container) {
|
1621
|
+
this.container.destroy();
|
1622
|
+
}
|
1623
|
+
|
1624
|
+
if(this.options.toggle !== 'manual') {
|
1625
|
+
this.$element.removeClass('editable-click');
|
1626
|
+
this.$element.off(this.options.toggle + '.editable');
|
1627
|
+
}
|
1628
|
+
|
1629
|
+
this.$element.off("save.internal");
|
1630
|
+
|
1631
|
+
this.$element.removeClass('editable');
|
1632
|
+
this.$element.removeClass('editable-open');
|
1633
|
+
this.$element.removeData('editable');
|
1634
|
+
}
|
1402
1635
|
};
|
1403
1636
|
|
1404
1637
|
/* EDITABLE PLUGIN DEFINITION
|
@@ -1584,7 +1817,7 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1584
1817
|
**/
|
1585
1818
|
autotext: 'auto',
|
1586
1819
|
/**
|
1587
|
-
Initial value of input.
|
1820
|
+
Initial value of input. If not set, taken from element's text.
|
1588
1821
|
|
1589
1822
|
@property value
|
1590
1823
|
@type mixed
|
@@ -1593,10 +1826,21 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1593
1826
|
value: null,
|
1594
1827
|
/**
|
1595
1828
|
Callback to perform custom displaying of value in element's text.
|
1596
|
-
If
|
1597
|
-
If
|
1829
|
+
If `null`, default input's display used.
|
1830
|
+
If `false`, no displaying methods will be called, element's text will never change.
|
1598
1831
|
Runs under element's scope.
|
1599
|
-
|
1832
|
+
_Parameters:_
|
1833
|
+
|
1834
|
+
* `value` current value to be displayed
|
1835
|
+
* `response` server response (if display called after ajax submit), since 1.4.0
|
1836
|
+
|
1837
|
+
For **inputs with source** (select, checklist) parameters are different:
|
1838
|
+
|
1839
|
+
* `value` current value to be displayed
|
1840
|
+
* `sourceData` array of items for current input (e.g. dropdown items)
|
1841
|
+
* `response` server response (if display called after ajax submit), since 1.4.0
|
1842
|
+
|
1843
|
+
To get currently selected items use `$.fn.editableutils.itemsByValue(value, sourceData)`.
|
1600
1844
|
|
1601
1845
|
@property display
|
1602
1846
|
@type function|boolean
|
@@ -1604,8 +1848,16 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1604
1848
|
@since 1.2.0
|
1605
1849
|
@example
|
1606
1850
|
display: function(value, sourceData) {
|
1607
|
-
|
1608
|
-
|
1851
|
+
//display checklist as comma-separated values
|
1852
|
+
var html = [],
|
1853
|
+
checked = $.fn.editableutils.itemsByValue(value, sourceData);
|
1854
|
+
|
1855
|
+
if(checked.length) {
|
1856
|
+
$.each(checked, function(i, v) { html.push($.fn.editableutils.escape(v.text)); });
|
1857
|
+
$(this).html(html.join(', '));
|
1858
|
+
} else {
|
1859
|
+
$(this).empty();
|
1860
|
+
}
|
1609
1861
|
}
|
1610
1862
|
**/
|
1611
1863
|
display: null
|
@@ -1635,26 +1887,27 @@ To create your own input you can inherit from this class.
|
|
1635
1887
|
**/
|
1636
1888
|
init: function(type, options, defaults) {
|
1637
1889
|
this.type = type;
|
1638
|
-
this.options = $.extend({}, defaults, options);
|
1639
|
-
|
1640
|
-
|
1641
|
-
|
1890
|
+
this.options = $.extend({}, defaults, options);
|
1891
|
+
},
|
1892
|
+
|
1893
|
+
/*
|
1894
|
+
this method called before render to init $tpl that is inserted in DOM
|
1895
|
+
*/
|
1896
|
+
prerender: function() {
|
1897
|
+
this.$tpl = $(this.options.tpl); //whole tpl as jquery object
|
1898
|
+
this.$input = this.$tpl; //control itself, can be changed in render method
|
1899
|
+
this.$clear = null; //clear button
|
1900
|
+
this.error = null; //error message, if input cannot be rendered
|
1642
1901
|
},
|
1643
1902
|
|
1644
1903
|
/**
|
1645
1904
|
Renders input from tpl. Can return jQuery deferred object.
|
1905
|
+
Can be overwritten in child objects
|
1646
1906
|
|
1647
1907
|
@method render()
|
1648
1908
|
**/
|
1649
1909
|
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
|
-
}
|
1910
|
+
|
1658
1911
|
},
|
1659
1912
|
|
1660
1913
|
/**
|
@@ -1691,7 +1944,7 @@ To create your own input you can inherit from this class.
|
|
1691
1944
|
},
|
1692
1945
|
|
1693
1946
|
/**
|
1694
|
-
Converts string received from server into value.
|
1947
|
+
Converts string received from server into value. Usually from `data-value` attribute.
|
1695
1948
|
|
1696
1949
|
@method str2value(str)
|
1697
1950
|
@param {string} str
|
@@ -1702,7 +1955,7 @@ To create your own input you can inherit from this class.
|
|
1702
1955
|
},
|
1703
1956
|
|
1704
1957
|
/**
|
1705
|
-
Converts value for submitting to server
|
1958
|
+
Converts value for submitting to server. Result can be string or object.
|
1706
1959
|
|
1707
1960
|
@method value2submit(value)
|
1708
1961
|
@param {mixed} value
|
@@ -1763,7 +2016,25 @@ To create your own input you can inherit from this class.
|
|
1763
2016
|
**/
|
1764
2017
|
autosubmit: function() {
|
1765
2018
|
|
2019
|
+
},
|
2020
|
+
|
2021
|
+
// -------- helper functions --------
|
2022
|
+
setClass: function() {
|
2023
|
+
if(this.options.inputclass) {
|
2024
|
+
this.$input.addClass(this.options.inputclass);
|
2025
|
+
}
|
2026
|
+
},
|
2027
|
+
|
2028
|
+
setAttr: function(attr) {
|
2029
|
+
if (this.options[attr]) {
|
2030
|
+
this.$input.attr(attr, this.options[attr]);
|
2031
|
+
}
|
2032
|
+
},
|
2033
|
+
|
2034
|
+
option: function(key, value) {
|
2035
|
+
this.options[key] = value;
|
1766
2036
|
}
|
2037
|
+
|
1767
2038
|
};
|
1768
2039
|
|
1769
2040
|
AbstractInput.defaults = {
|
@@ -1813,11 +2084,9 @@ List - abstract class for inputs that have source option loaded from js array or
|
|
1813
2084
|
|
1814
2085
|
$.extend(List.prototype, {
|
1815
2086
|
render: function () {
|
1816
|
-
List.superclass.render.call(this);
|
1817
2087
|
var deferred = $.Deferred();
|
2088
|
+
|
1818
2089
|
this.error = null;
|
1819
|
-
this.sourceData = null;
|
1820
|
-
this.prependData = null;
|
1821
2090
|
this.onSourceReady(function () {
|
1822
2091
|
this.renderList();
|
1823
2092
|
deferred.resolve();
|
@@ -1833,20 +2102,24 @@ List - abstract class for inputs that have source option loaded from js array or
|
|
1833
2102
|
return null; //can't set value by text
|
1834
2103
|
},
|
1835
2104
|
|
1836
|
-
value2html: function (value, element, display) {
|
1837
|
-
var deferred = $.Deferred()
|
1838
|
-
|
1839
|
-
|
1840
|
-
|
1841
|
-
|
1842
|
-
|
1843
|
-
|
1844
|
-
|
1845
|
-
|
1846
|
-
|
1847
|
-
|
1848
|
-
|
1849
|
-
|
2105
|
+
value2html: function (value, element, display, response) {
|
2106
|
+
var deferred = $.Deferred(),
|
2107
|
+
success = function () {
|
2108
|
+
if(typeof display === 'function') {
|
2109
|
+
//custom display method
|
2110
|
+
display.call(element, value, this.sourceData, response);
|
2111
|
+
} else {
|
2112
|
+
this.value2htmlFinal(value, element);
|
2113
|
+
}
|
2114
|
+
deferred.resolve();
|
2115
|
+
};
|
2116
|
+
|
2117
|
+
//for null value just call success without loading source
|
2118
|
+
if(value === null) {
|
2119
|
+
success.call(this);
|
2120
|
+
} else {
|
2121
|
+
this.onSourceReady(success, function () { deferred.resolve(); });
|
2122
|
+
}
|
1850
2123
|
|
1851
2124
|
return deferred.promise();
|
1852
2125
|
},
|
@@ -1872,7 +2145,7 @@ List - abstract class for inputs that have source option loaded from js array or
|
|
1872
2145
|
if (typeof this.options.source === 'string') {
|
1873
2146
|
//try to get from cache
|
1874
2147
|
if(this.options.sourceCache) {
|
1875
|
-
var cacheID = this.options.source
|
2148
|
+
var cacheID = this.options.source,
|
1876
2149
|
cache;
|
1877
2150
|
|
1878
2151
|
if (!$(document).data(cacheID)) {
|
@@ -1883,11 +2156,13 @@ List - abstract class for inputs that have source option loaded from js array or
|
|
1883
2156
|
//check for cached data
|
1884
2157
|
if (cache.loading === false && cache.sourceData) { //take source from cache
|
1885
2158
|
this.sourceData = cache.sourceData;
|
2159
|
+
this.doPrepend();
|
1886
2160
|
success.call(this);
|
1887
2161
|
return;
|
1888
2162
|
} else if (cache.loading === true) { //cache is loading, put callback in stack to be called later
|
1889
2163
|
cache.callbacks.push($.proxy(function () {
|
1890
2164
|
this.sourceData = cache.sourceData;
|
2165
|
+
this.doPrepend();
|
1891
2166
|
success.call(this);
|
1892
2167
|
}, this));
|
1893
2168
|
|
@@ -1906,7 +2181,6 @@ List - abstract class for inputs that have source option loaded from js array or
|
|
1906
2181
|
url: this.options.source,
|
1907
2182
|
type: 'get',
|
1908
2183
|
cache: false,
|
1909
|
-
data: this.options.name ? {name: this.options.name} : {},
|
1910
2184
|
dataType: 'json',
|
1911
2185
|
success: $.proxy(function (data) {
|
1912
2186
|
if(cache) {
|
@@ -1914,17 +2188,19 @@ List - abstract class for inputs that have source option loaded from js array or
|
|
1914
2188
|
}
|
1915
2189
|
this.sourceData = this.makeArray(data);
|
1916
2190
|
if($.isArray(this.sourceData)) {
|
1917
|
-
this.doPrepend();
|
1918
|
-
success.call(this);
|
1919
2191
|
if(cache) {
|
1920
2192
|
//store result in cache
|
1921
2193
|
cache.sourceData = this.sourceData;
|
1922
|
-
|
2194
|
+
//run success callbacks for other fields waiting for this source
|
2195
|
+
$.each(cache.callbacks, function () { this.call(); });
|
1923
2196
|
}
|
2197
|
+
this.doPrepend();
|
2198
|
+
success.call(this);
|
1924
2199
|
} else {
|
1925
2200
|
error.call(this);
|
1926
2201
|
if(cache) {
|
1927
|
-
|
2202
|
+
//run error callbacks for other fields waiting for this source
|
2203
|
+
$.each(cache.err_callbacks, function () { this.call(); });
|
1928
2204
|
}
|
1929
2205
|
}
|
1930
2206
|
}, this),
|
@@ -1937,8 +2213,13 @@ List - abstract class for inputs that have source option loaded from js array or
|
|
1937
2213
|
}
|
1938
2214
|
}, this)
|
1939
2215
|
});
|
1940
|
-
} else { //options as json/array
|
1941
|
-
|
2216
|
+
} else { //options as json/array/function
|
2217
|
+
if (typeof this.options.source === 'function') {
|
2218
|
+
this.sourceData = this.makeArray(this.options.source());
|
2219
|
+
} else {
|
2220
|
+
this.sourceData = this.makeArray(this.options.source);
|
2221
|
+
}
|
2222
|
+
|
1942
2223
|
if($.isArray(this.sourceData)) {
|
1943
2224
|
this.doPrepend();
|
1944
2225
|
success.call(this);
|
@@ -1959,7 +2240,11 @@ List - abstract class for inputs that have source option loaded from js array or
|
|
1959
2240
|
if (typeof this.options.prepend === 'string') {
|
1960
2241
|
this.options.prepend = {'': this.options.prepend};
|
1961
2242
|
}
|
1962
|
-
|
2243
|
+
if (typeof this.options.prepend === 'function') {
|
2244
|
+
this.prependData = this.makeArray(this.options.prepend());
|
2245
|
+
} else {
|
2246
|
+
this.prependData = this.makeArray(this.options.prepend);
|
2247
|
+
}
|
1963
2248
|
}
|
1964
2249
|
|
1965
2250
|
if($.isArray(this.prependData) && $.isArray(this.sourceData)) {
|
@@ -2021,41 +2306,41 @@ List - abstract class for inputs that have source option loaded from js array or
|
|
2021
2306
|
return result;
|
2022
2307
|
},
|
2023
2308
|
|
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
|
-
}
|
2309
|
+
option: function(key, value) {
|
2310
|
+
this.options[key] = value;
|
2311
|
+
if(key === 'source') {
|
2312
|
+
this.sourceData = null;
|
2034
2313
|
}
|
2314
|
+
if(key === 'prepend') {
|
2315
|
+
this.prependData = null;
|
2316
|
+
}
|
2035
2317
|
}
|
2036
2318
|
|
2037
2319
|
});
|
2038
2320
|
|
2039
2321
|
List.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, {
|
2040
2322
|
/**
|
2041
|
-
Source data for list.
|
2042
|
-
|
2043
|
-
For compability
|
2044
|
-
If source is **string**, results will be cached for fields with the same source and name. See also <code>sourceCache</code> option.
|
2323
|
+
Source data for list.
|
2324
|
+
If **array** - it should be in format: `[{value: 1, text: "text1"}, {...}]`
|
2325
|
+
For compability, object format is also supported: `{"1": "text1", "2": "text2" ...}` but it does not guarantee elements order.
|
2045
2326
|
|
2327
|
+
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.
|
2328
|
+
|
2329
|
+
If **function**, it should return data in format above (since 1.4.0).
|
2330
|
+
|
2046
2331
|
@property source
|
2047
|
-
@type string|array|object
|
2332
|
+
@type string | array | object | function
|
2048
2333
|
@default null
|
2049
2334
|
**/
|
2050
|
-
source:null,
|
2335
|
+
source: null,
|
2051
2336
|
/**
|
2052
2337
|
Data automatically prepended to the beginning of dropdown list.
|
2053
2338
|
|
2054
2339
|
@property prepend
|
2055
|
-
@type string|array|object
|
2340
|
+
@type string | array | object | function
|
2056
2341
|
@default false
|
2057
2342
|
**/
|
2058
|
-
prepend:false,
|
2343
|
+
prepend: false,
|
2059
2344
|
/**
|
2060
2345
|
Error message when list cannot be loaded (e.g. ajax error)
|
2061
2346
|
|
@@ -2079,6 +2364,7 @@ List - abstract class for inputs that have source option loaded from js array or
|
|
2079
2364
|
$.fn.editabletypes.list = List;
|
2080
2365
|
|
2081
2366
|
}(window.jQuery));
|
2367
|
+
|
2082
2368
|
/**
|
2083
2369
|
Text input
|
2084
2370
|
|
@@ -2104,11 +2390,64 @@ $(function(){
|
|
2104
2390
|
$.fn.editableutils.inherit(Text, $.fn.editabletypes.abstractinput);
|
2105
2391
|
|
2106
2392
|
$.extend(Text.prototype, {
|
2107
|
-
|
2108
|
-
|
2393
|
+
render: function() {
|
2394
|
+
this.renderClear();
|
2395
|
+
this.setClass();
|
2396
|
+
this.setAttr('placeholder');
|
2397
|
+
},
|
2398
|
+
|
2399
|
+
activate: function() {
|
2400
|
+
if(this.$input.is(':visible')) {
|
2109
2401
|
this.$input.focus();
|
2110
2402
|
$.fn.editableutils.setCursorPosition(this.$input.get(0), this.$input.val().length);
|
2403
|
+
if(this.toggleClear) {
|
2404
|
+
this.toggleClear();
|
2405
|
+
}
|
2406
|
+
}
|
2407
|
+
},
|
2408
|
+
|
2409
|
+
//render clear button
|
2410
|
+
renderClear: function() {
|
2411
|
+
if (this.options.clear) {
|
2412
|
+
this.$clear = $('<span class="editable-clear-x"></span>');
|
2413
|
+
this.$input.after(this.$clear)
|
2414
|
+
.css('padding-right', 20)
|
2415
|
+
.keyup($.proxy(this.toggleClear, this))
|
2416
|
+
.parent().css('position', 'relative');
|
2417
|
+
|
2418
|
+
this.$clear.click($.proxy(function(){
|
2419
|
+
this.$clear.hide();
|
2420
|
+
this.$input.val('').focus();
|
2421
|
+
}, this));
|
2422
|
+
}
|
2423
|
+
},
|
2424
|
+
|
2425
|
+
postrender: function() {
|
2426
|
+
if(this.$clear) {
|
2427
|
+
//can position clear button only here, when form is shown and height can be calculated
|
2428
|
+
var h = this.$input.outerHeight() || 20,
|
2429
|
+
delta = (h - this.$clear.height()) / 2;
|
2430
|
+
|
2431
|
+
//workaround for plain-popup
|
2432
|
+
if(delta < 3) {
|
2433
|
+
delta = 3;
|
2434
|
+
}
|
2435
|
+
|
2436
|
+
this.$clear.css({top: delta, right: delta});
|
2437
|
+
}
|
2438
|
+
},
|
2439
|
+
|
2440
|
+
//show / hide clear button
|
2441
|
+
toggleClear: function() {
|
2442
|
+
if(!this.$clear) {
|
2443
|
+
return;
|
2111
2444
|
}
|
2445
|
+
|
2446
|
+
if(this.$input.val()) {
|
2447
|
+
this.$clear.show();
|
2448
|
+
} else {
|
2449
|
+
this.$clear.hide();
|
2450
|
+
}
|
2112
2451
|
}
|
2113
2452
|
});
|
2114
2453
|
|
@@ -2125,7 +2464,16 @@ $(function(){
|
|
2125
2464
|
@type string
|
2126
2465
|
@default null
|
2127
2466
|
**/
|
2128
|
-
placeholder: null
|
2467
|
+
placeholder: null,
|
2468
|
+
|
2469
|
+
/**
|
2470
|
+
Whether to show `clear` button
|
2471
|
+
|
2472
|
+
@property clear
|
2473
|
+
@type boolean
|
2474
|
+
@default true
|
2475
|
+
**/
|
2476
|
+
clear: true
|
2129
2477
|
});
|
2130
2478
|
|
2131
2479
|
$.fn.editabletypes.text = Text;
|
@@ -2144,7 +2492,8 @@ Textarea input
|
|
2144
2492
|
$(function(){
|
2145
2493
|
$('#comments').editable({
|
2146
2494
|
url: '/post',
|
2147
|
-
title: 'Enter comments'
|
2495
|
+
title: 'Enter comments',
|
2496
|
+
rows: 10
|
2148
2497
|
});
|
2149
2498
|
});
|
2150
2499
|
</script>
|
@@ -2159,8 +2508,10 @@ $(function(){
|
|
2159
2508
|
|
2160
2509
|
$.extend(Textarea.prototype, {
|
2161
2510
|
render: function () {
|
2162
|
-
|
2163
|
-
|
2511
|
+
this.setClass();
|
2512
|
+
this.setAttr('placeholder');
|
2513
|
+
this.setAttr('rows');
|
2514
|
+
|
2164
2515
|
//ctrl + enter
|
2165
2516
|
this.$input.keydown(function (e) {
|
2166
2517
|
if (e.ctrlKey && e.which === 13) {
|
@@ -2185,43 +2536,56 @@ $(function(){
|
|
2185
2536
|
if(!html) {
|
2186
2537
|
return '';
|
2187
2538
|
}
|
2539
|
+
|
2540
|
+
var regex = new RegExp(String.fromCharCode(10), 'g');
|
2188
2541
|
var lines = html.split(/<br\s*\/?>/i);
|
2189
2542
|
for (var i = 0; i < lines.length; i++) {
|
2190
|
-
|
2543
|
+
var text = $('<div>').html(lines[i]).text();
|
2544
|
+
|
2545
|
+
// Remove newline characters (\n) to avoid them being converted by value2html() method
|
2546
|
+
// thus adding extra <br> tags
|
2547
|
+
text = text.replace(regex, '');
|
2548
|
+
|
2549
|
+
lines[i] = text;
|
2191
2550
|
}
|
2192
|
-
return lines.join("\n");
|
2193
|
-
},
|
2551
|
+
return lines.join("\n");
|
2552
|
+
},
|
2194
2553
|
|
2195
2554
|
activate: function() {
|
2196
|
-
|
2197
|
-
|
2198
|
-
this.$input.focus();
|
2199
|
-
}
|
2200
|
-
}
|
2555
|
+
$.fn.editabletypes.text.prototype.activate.call(this);
|
2556
|
+
}
|
2201
2557
|
});
|
2202
2558
|
|
2203
2559
|
Textarea.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, {
|
2204
2560
|
/**
|
2205
|
-
@property tpl
|
2561
|
+
@property tpl
|
2206
2562
|
@default <textarea></textarea>
|
2207
|
-
**/
|
2563
|
+
**/
|
2208
2564
|
tpl:'<textarea></textarea>',
|
2209
2565
|
/**
|
2210
|
-
@property inputclass
|
2566
|
+
@property inputclass
|
2211
2567
|
@default input-large
|
2212
|
-
**/
|
2568
|
+
**/
|
2213
2569
|
inputclass: 'input-large',
|
2214
2570
|
/**
|
2215
2571
|
Placeholder attribute of input. Shown when input is empty.
|
2216
2572
|
|
2217
|
-
@property placeholder
|
2573
|
+
@property placeholder
|
2218
2574
|
@type string
|
2219
2575
|
@default null
|
2220
|
-
**/
|
2221
|
-
placeholder: null
|
2576
|
+
**/
|
2577
|
+
placeholder: null,
|
2578
|
+
/**
|
2579
|
+
Number of rows in textarea
|
2580
|
+
|
2581
|
+
@property rows
|
2582
|
+
@type integer
|
2583
|
+
@default 7
|
2584
|
+
**/
|
2585
|
+
rows: 7
|
2222
2586
|
});
|
2223
2587
|
|
2224
|
-
$.fn.editabletypes.textarea = Textarea;
|
2588
|
+
$.fn.editabletypes.textarea = Textarea;
|
2225
2589
|
|
2226
2590
|
}(window.jQuery));
|
2227
2591
|
|
@@ -2257,6 +2621,8 @@ $(function(){
|
|
2257
2621
|
|
2258
2622
|
$.extend(Select.prototype, {
|
2259
2623
|
renderList: function() {
|
2624
|
+
this.$input.empty();
|
2625
|
+
|
2260
2626
|
if(!$.isArray(this.sourceData)) {
|
2261
2627
|
return;
|
2262
2628
|
}
|
@@ -2265,6 +2631,8 @@ $(function(){
|
|
2265
2631
|
this.$input.append($('<option>', {value: this.sourceData[i].value}).text(this.sourceData[i].text));
|
2266
2632
|
}
|
2267
2633
|
|
2634
|
+
this.setClass();
|
2635
|
+
|
2268
2636
|
//enter submit
|
2269
2637
|
this.$input.on('keydown.editable', function (e) {
|
2270
2638
|
if (e.which === 13) {
|
@@ -2274,11 +2642,14 @@ $(function(){
|
|
2274
2642
|
},
|
2275
2643
|
|
2276
2644
|
value2htmlFinal: function(value, element) {
|
2277
|
-
var text = '',
|
2278
|
-
|
2279
|
-
|
2645
|
+
var text = '',
|
2646
|
+
items = $.fn.editableutils.itemsByValue(value, this.sourceData);
|
2647
|
+
|
2648
|
+
if(items.length) {
|
2649
|
+
text = items[0].text;
|
2280
2650
|
}
|
2281
|
-
|
2651
|
+
|
2652
|
+
$(element).text(text);
|
2282
2653
|
},
|
2283
2654
|
|
2284
2655
|
autosubmit: function() {
|
@@ -2333,6 +2704,9 @@ $(function(){
|
|
2333
2704
|
$.extend(Checklist.prototype, {
|
2334
2705
|
renderList: function() {
|
2335
2706
|
var $label, $div;
|
2707
|
+
|
2708
|
+
this.$tpl.empty();
|
2709
|
+
|
2336
2710
|
if(!$.isArray(this.sourceData)) {
|
2337
2711
|
return;
|
2338
2712
|
}
|
@@ -2345,8 +2719,11 @@ $(function(){
|
|
2345
2719
|
}))
|
2346
2720
|
.append($('<span>').text(' '+this.sourceData[i].text));
|
2347
2721
|
|
2348
|
-
$('<div>').append($label).appendTo(this.$
|
2722
|
+
$('<div>').append($label).appendTo(this.$tpl);
|
2349
2723
|
}
|
2724
|
+
|
2725
|
+
this.$input = this.$tpl.find('input[type="checkbox"]');
|
2726
|
+
this.setClass();
|
2350
2727
|
},
|
2351
2728
|
|
2352
2729
|
value2str: function(value) {
|
@@ -2367,10 +2744,9 @@ $(function(){
|
|
2367
2744
|
|
2368
2745
|
//set checked on required checkboxes
|
2369
2746
|
value2input: function(value) {
|
2370
|
-
|
2371
|
-
$checks.removeAttr('checked');
|
2747
|
+
this.$input.removeAttr('checked');
|
2372
2748
|
if($.isArray(value) && value.length) {
|
2373
|
-
|
2749
|
+
this.$input.each(function(i, el) {
|
2374
2750
|
var $el = $(el);
|
2375
2751
|
// cannot use $.inArray as it performs strict comparison
|
2376
2752
|
$.each(value, function(j, val){
|
@@ -2386,7 +2762,7 @@ $(function(){
|
|
2386
2762
|
|
2387
2763
|
input2value: function() {
|
2388
2764
|
var checked = [];
|
2389
|
-
this.$input.
|
2765
|
+
this.$input.filter(':checked').each(function(i, el) {
|
2390
2766
|
checked.push($(el).val());
|
2391
2767
|
});
|
2392
2768
|
return checked;
|
@@ -2395,11 +2771,8 @@ $(function(){
|
|
2395
2771
|
//collect text of checked boxes
|
2396
2772
|
value2htmlFinal: function(value, element) {
|
2397
2773
|
var html = [],
|
2398
|
-
|
2399
|
-
|
2400
|
-
return $.grep(value, function(v){ return v == o.value; }).length;
|
2401
|
-
});
|
2402
|
-
/*jslint eqeq: false*/
|
2774
|
+
checked = $.fn.editableutils.itemsByValue(value, this.sourceData);
|
2775
|
+
|
2403
2776
|
if(checked.length) {
|
2404
2777
|
$.each(checked, function(i, v) { html.push($.fn.editableutils.escape(v.text)); });
|
2405
2778
|
$(element).html(html.join('<br>'));
|
@@ -2409,11 +2782,11 @@ $(function(){
|
|
2409
2782
|
},
|
2410
2783
|
|
2411
2784
|
activate: function() {
|
2412
|
-
this.$input.
|
2785
|
+
this.$input.first().focus();
|
2413
2786
|
},
|
2414
2787
|
|
2415
2788
|
autosubmit: function() {
|
2416
|
-
this.$input.
|
2789
|
+
this.$input.on('keydown', function(e){
|
2417
2790
|
if (e.which === 13) {
|
2418
2791
|
$(this).closest('form').submit();
|
2419
2792
|
}
|
@@ -2426,21 +2799,21 @@ $(function(){
|
|
2426
2799
|
@property tpl
|
2427
2800
|
@default <div></div>
|
2428
2801
|
**/
|
2429
|
-
tpl:'<div></div>',
|
2802
|
+
tpl:'<div class="editable-checklist"></div>',
|
2430
2803
|
|
2431
2804
|
/**
|
2432
2805
|
@property inputclass
|
2433
2806
|
@type string
|
2434
|
-
@default
|
2807
|
+
@default null
|
2435
2808
|
**/
|
2436
|
-
inputclass:
|
2809
|
+
inputclass: null,
|
2437
2810
|
|
2438
2811
|
/**
|
2439
|
-
Separator of values when reading from
|
2812
|
+
Separator of values when reading from `data-value` attribute
|
2440
2813
|
|
2441
2814
|
@property separator
|
2442
2815
|
@type string
|
2443
|
-
@default ',
|
2816
|
+
@default ','
|
2444
2817
|
**/
|
2445
2818
|
separator: ','
|
2446
2819
|
});
|
@@ -2571,18 +2944,9 @@ Number
|
|
2571
2944
|
$.extend(NumberInput.prototype, {
|
2572
2945
|
render: function () {
|
2573
2946
|
NumberInput.superclass.render.call(this);
|
2574
|
-
|
2575
|
-
|
2576
|
-
|
2577
|
-
}
|
2578
|
-
|
2579
|
-
if (this.options.max !== null) {
|
2580
|
-
this.$input.attr('max', this.options.max);
|
2581
|
-
}
|
2582
|
-
|
2583
|
-
if (this.options.step !== null) {
|
2584
|
-
this.$input.attr('step', this.options.step);
|
2585
|
-
}
|
2947
|
+
this.setAttr('min');
|
2948
|
+
this.setAttr('max');
|
2949
|
+
this.setAttr('step');
|
2586
2950
|
}
|
2587
2951
|
});
|
2588
2952
|
NumberInput.defaults = $.extend({}, $.fn.editabletypes.text.defaults, {
|
@@ -2606,29 +2970,19 @@ Range (inherit from number)
|
|
2606
2970
|
$.fn.editableutils.inherit(Range, $.fn.editabletypes.number);
|
2607
2971
|
$.extend(Range.prototype, {
|
2608
2972
|
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
|
-
}
|
2617
|
-
|
2618
|
-
if (this.options.max !== null) {
|
2619
|
-
$slider.attr('max', this.options.max);
|
2620
|
-
}
|
2973
|
+
this.$input = this.$tpl.filter('input');
|
2621
2974
|
|
2622
|
-
|
2623
|
-
|
2624
|
-
|
2975
|
+
this.setClass();
|
2976
|
+
this.setAttr('min');
|
2977
|
+
this.setAttr('max');
|
2978
|
+
this.setAttr('step');
|
2625
2979
|
|
2626
|
-
|
2980
|
+
this.$input.on('input', function(){
|
2627
2981
|
$(this).siblings('output').text($(this).val());
|
2628
2982
|
});
|
2629
2983
|
},
|
2630
2984
|
activate: function() {
|
2631
|
-
this.$input.
|
2985
|
+
this.$input.focus();
|
2632
2986
|
}
|
2633
2987
|
});
|
2634
2988
|
Range.defaults = $.extend({}, $.fn.editabletypes.number.defaults, {
|
@@ -2637,6 +2991,590 @@ Range (inherit from number)
|
|
2637
2991
|
});
|
2638
2992
|
$.fn.editabletypes.range = Range;
|
2639
2993
|
}(window.jQuery));
|
2994
|
+
/**
|
2995
|
+
* Combodate - 1.0.1
|
2996
|
+
* Dropdown date and time picker.
|
2997
|
+
* Converts text input into dropdowns to pick day, month, year, hour, minute and second.
|
2998
|
+
* Uses momentjs as datetime library http://momentjs.com.
|
2999
|
+
* For i18n include corresponding file from https://github.com/timrwood/moment/tree/master/lang
|
3000
|
+
*
|
3001
|
+
* Author: Vitaliy Potapov
|
3002
|
+
* Project page: http://github.com/vitalets/combodate
|
3003
|
+
* Copyright (c) 2012 Vitaliy Potapov. Released under MIT License.
|
3004
|
+
**/
|
3005
|
+
(function ($) {
|
3006
|
+
|
3007
|
+
var Combodate = function (element, options) {
|
3008
|
+
this.$element = $(element);
|
3009
|
+
if(!this.$element.is('input')) {
|
3010
|
+
$.error('Combodate should be applied to INPUT element');
|
3011
|
+
return;
|
3012
|
+
}
|
3013
|
+
this.options = $.extend({}, $.fn.combodate.defaults, options, this.$element.data());
|
3014
|
+
this.init();
|
3015
|
+
};
|
3016
|
+
|
3017
|
+
Combodate.prototype = {
|
3018
|
+
constructor: Combodate,
|
3019
|
+
init: function () {
|
3020
|
+
this.map = {
|
3021
|
+
//key regexp moment.method
|
3022
|
+
day: ['D', 'date'],
|
3023
|
+
month: ['M', 'month'],
|
3024
|
+
year: ['Y', 'year'],
|
3025
|
+
hour: ['[Hh]', 'hours'],
|
3026
|
+
minute: ['m', 'minutes'],
|
3027
|
+
second: ['s', 'seconds'],
|
3028
|
+
ampm: ['[Aa]', '']
|
3029
|
+
};
|
3030
|
+
|
3031
|
+
this.$widget = $('<span class="combodate"></span>').html(this.getTemplate());
|
3032
|
+
|
3033
|
+
this.initCombos();
|
3034
|
+
|
3035
|
+
//update original input on change
|
3036
|
+
this.$widget.on('change', 'select', $.proxy(function(){
|
3037
|
+
this.$element.val(this.getValue());
|
3038
|
+
}, this));
|
3039
|
+
|
3040
|
+
this.$widget.find('select').css('width', 'auto');
|
3041
|
+
|
3042
|
+
//hide original input and insert widget
|
3043
|
+
this.$element.hide().after(this.$widget);
|
3044
|
+
|
3045
|
+
//set initial value
|
3046
|
+
this.setValue(this.$element.val() || this.options.value);
|
3047
|
+
},
|
3048
|
+
|
3049
|
+
/*
|
3050
|
+
Replace tokens in template with <select> elements
|
3051
|
+
*/
|
3052
|
+
getTemplate: function() {
|
3053
|
+
var tpl = this.options.template;
|
3054
|
+
|
3055
|
+
//first pass
|
3056
|
+
$.each(this.map, function(k, v) {
|
3057
|
+
v = v[0];
|
3058
|
+
var r = new RegExp(v+'+'),
|
3059
|
+
token = v.length > 1 ? v.substring(1, 2) : v;
|
3060
|
+
|
3061
|
+
tpl = tpl.replace(r, '{'+token+'}');
|
3062
|
+
});
|
3063
|
+
|
3064
|
+
//replace spaces with
|
3065
|
+
tpl = tpl.replace(/ /g, ' ');
|
3066
|
+
|
3067
|
+
//second pass
|
3068
|
+
$.each(this.map, function(k, v) {
|
3069
|
+
v = v[0];
|
3070
|
+
var token = v.length > 1 ? v.substring(1, 2) : v;
|
3071
|
+
|
3072
|
+
tpl = tpl.replace('{'+token+'}', '<select class="'+k+'"></select>');
|
3073
|
+
});
|
3074
|
+
|
3075
|
+
return tpl;
|
3076
|
+
},
|
3077
|
+
|
3078
|
+
/*
|
3079
|
+
Initialize combos that presents in template
|
3080
|
+
*/
|
3081
|
+
initCombos: function() {
|
3082
|
+
var that = this;
|
3083
|
+
$.each(this.map, function(k, v) {
|
3084
|
+
var $c = that.$widget.find('.'+k), f, items;
|
3085
|
+
if($c.length) {
|
3086
|
+
that['$'+k] = $c; //set properties like this.$day, this.$month etc.
|
3087
|
+
f = 'fill' + k.charAt(0).toUpperCase() + k.slice(1); //define method name to fill items, e.g `fillDays`
|
3088
|
+
items = that[f]();
|
3089
|
+
that['$'+k].html(that.renderItems(items));
|
3090
|
+
}
|
3091
|
+
});
|
3092
|
+
},
|
3093
|
+
|
3094
|
+
/*
|
3095
|
+
Initialize items of combos. Handles `firstItem` option
|
3096
|
+
*/
|
3097
|
+
initItems: function(key) {
|
3098
|
+
var values = [];
|
3099
|
+
if(this.options.firstItem === 'name') {
|
3100
|
+
var header = typeof moment.relativeTime[key] === 'function' ? moment.relativeTime[key](1, true, key, false) : moment.relativeTime[key];
|
3101
|
+
//take last entry (see momentjs lang files structure)
|
3102
|
+
header = header.split(' ').reverse()[0];
|
3103
|
+
values.push(['', header]);
|
3104
|
+
} else if(this.options.firstItem === 'empty') {
|
3105
|
+
values.push(['', '']);
|
3106
|
+
}
|
3107
|
+
return values;
|
3108
|
+
},
|
3109
|
+
|
3110
|
+
/*
|
3111
|
+
render items to string of <option> tags
|
3112
|
+
*/
|
3113
|
+
renderItems: function(items) {
|
3114
|
+
var str = [];
|
3115
|
+
for(var i=0; i<items.length; i++) {
|
3116
|
+
str.push('<option value="'+items[i][0]+'">'+items[i][1]+'</option>');
|
3117
|
+
}
|
3118
|
+
return str.join("\n");
|
3119
|
+
},
|
3120
|
+
|
3121
|
+
/*
|
3122
|
+
fill day
|
3123
|
+
*/
|
3124
|
+
fillDay: function() {
|
3125
|
+
var items = this.initItems('d'), name, i,
|
3126
|
+
twoDigit = this.options.template.indexOf('DD') !== -1;
|
3127
|
+
|
3128
|
+
for(i=1; i<=31; i++) {
|
3129
|
+
name = twoDigit ? this.leadZero(i) : i;
|
3130
|
+
items.push([i, name]);
|
3131
|
+
}
|
3132
|
+
return items;
|
3133
|
+
},
|
3134
|
+
|
3135
|
+
/*
|
3136
|
+
fill month
|
3137
|
+
*/
|
3138
|
+
fillMonth: function() {
|
3139
|
+
var items = this.initItems('M'), name, i,
|
3140
|
+
longNames = this.options.template.indexOf('MMMM') !== -1,
|
3141
|
+
shortNames = this.options.template.indexOf('MMM') !== -1,
|
3142
|
+
twoDigit = this.options.template.indexOf('MM') !== -1;
|
3143
|
+
|
3144
|
+
for(i=0; i<=11; i++) {
|
3145
|
+
if(longNames) {
|
3146
|
+
name = moment.months[i];
|
3147
|
+
} else if(shortNames) {
|
3148
|
+
name = moment.monthsShort[i];
|
3149
|
+
} else if(twoDigit) {
|
3150
|
+
name = this.leadZero(i+1);
|
3151
|
+
} else {
|
3152
|
+
name = i+1;
|
3153
|
+
}
|
3154
|
+
items.push([i, name]);
|
3155
|
+
}
|
3156
|
+
return items;
|
3157
|
+
},
|
3158
|
+
|
3159
|
+
/*
|
3160
|
+
fill year
|
3161
|
+
*/
|
3162
|
+
fillYear: function() {
|
3163
|
+
var items = this.initItems('y'), name, i,
|
3164
|
+
longNames = this.options.template.indexOf('YYYY') !== -1;
|
3165
|
+
|
3166
|
+
for(i=this.options.maxYear; i>=this.options.minYear; i--) {
|
3167
|
+
name = longNames ? i : (i+'').substring(2);
|
3168
|
+
items.push([i, name]);
|
3169
|
+
}
|
3170
|
+
return items;
|
3171
|
+
},
|
3172
|
+
|
3173
|
+
/*
|
3174
|
+
fill hour
|
3175
|
+
*/
|
3176
|
+
fillHour: function() {
|
3177
|
+
var items = this.initItems('h'), name, i,
|
3178
|
+
h12 = this.options.template.indexOf('h') !== -1,
|
3179
|
+
h24 = this.options.template.indexOf('H') !== -1,
|
3180
|
+
twoDigit = this.options.template.toLowerCase().indexOf('hh') !== -1,
|
3181
|
+
max = h12 ? 12 : 23;
|
3182
|
+
|
3183
|
+
for(i=0; i<=max; i++) {
|
3184
|
+
name = twoDigit ? this.leadZero(i) : i;
|
3185
|
+
items.push([i, name]);
|
3186
|
+
}
|
3187
|
+
return items;
|
3188
|
+
},
|
3189
|
+
|
3190
|
+
/*
|
3191
|
+
fill minute
|
3192
|
+
*/
|
3193
|
+
fillMinute: function() {
|
3194
|
+
var items = this.initItems('m'), name, i,
|
3195
|
+
twoDigit = this.options.template.indexOf('mm') !== -1;
|
3196
|
+
|
3197
|
+
for(i=0; i<=59; i+= this.options.minuteStep) {
|
3198
|
+
name = twoDigit ? this.leadZero(i) : i;
|
3199
|
+
items.push([i, name]);
|
3200
|
+
}
|
3201
|
+
return items;
|
3202
|
+
},
|
3203
|
+
|
3204
|
+
/*
|
3205
|
+
fill second
|
3206
|
+
*/
|
3207
|
+
fillSecond: function() {
|
3208
|
+
var items = this.initItems('s'), name, i,
|
3209
|
+
twoDigit = this.options.template.indexOf('ss') !== -1;
|
3210
|
+
|
3211
|
+
for(i=0; i<=59; i+= this.options.secondStep) {
|
3212
|
+
name = twoDigit ? this.leadZero(i) : i;
|
3213
|
+
items.push([i, name]);
|
3214
|
+
}
|
3215
|
+
return items;
|
3216
|
+
},
|
3217
|
+
|
3218
|
+
/*
|
3219
|
+
fill ampm
|
3220
|
+
*/
|
3221
|
+
fillAmpm: function() {
|
3222
|
+
var ampmL = this.options.template.indexOf('a') !== -1,
|
3223
|
+
ampmU = this.options.template.indexOf('A') !== -1,
|
3224
|
+
items = [
|
3225
|
+
['am', ampmL ? 'am' : 'AM'],
|
3226
|
+
['pm', ampmL ? 'pm' : 'PM']
|
3227
|
+
];
|
3228
|
+
return items;
|
3229
|
+
},
|
3230
|
+
|
3231
|
+
/*
|
3232
|
+
Returns current date value.
|
3233
|
+
If format not specified - `options.format` used.
|
3234
|
+
If format = `null` - Moment object returned.
|
3235
|
+
*/
|
3236
|
+
getValue: function(format) {
|
3237
|
+
var dt, values = {},
|
3238
|
+
that = this,
|
3239
|
+
notSelected = false;
|
3240
|
+
|
3241
|
+
//getting selected values
|
3242
|
+
$.each(this.map, function(k, v) {
|
3243
|
+
if(k === 'ampm') {
|
3244
|
+
return;
|
3245
|
+
}
|
3246
|
+
var def = k === 'day' ? 1 : 0;
|
3247
|
+
|
3248
|
+
values[k] = that['$'+k] ? parseInt(that['$'+k].val(), 10) : def;
|
3249
|
+
|
3250
|
+
if(isNaN(values[k])) {
|
3251
|
+
notSelected = true;
|
3252
|
+
return false;
|
3253
|
+
}
|
3254
|
+
});
|
3255
|
+
|
3256
|
+
//if at least one visible combo not selected - return empty string
|
3257
|
+
if(notSelected) {
|
3258
|
+
return '';
|
3259
|
+
}
|
3260
|
+
|
3261
|
+
//convert hours if 12h format
|
3262
|
+
if(this.$ampm) {
|
3263
|
+
values.hour = this.$ampm.val() === 'am' ? values.hour : values.hour+12;
|
3264
|
+
if(values.hour === 24) {
|
3265
|
+
values.hour = 0;
|
3266
|
+
}
|
3267
|
+
}
|
3268
|
+
|
3269
|
+
dt = moment([values.year, values.month, values.day, values.hour, values.minute, values.second]);
|
3270
|
+
|
3271
|
+
//highlight invalid date
|
3272
|
+
this.highlight(dt);
|
3273
|
+
|
3274
|
+
format = format === undefined ? this.options.format : format;
|
3275
|
+
if(format === null) {
|
3276
|
+
return dt.isValid() ? dt : null;
|
3277
|
+
} else {
|
3278
|
+
return dt.isValid() ? dt.format(format) : '';
|
3279
|
+
}
|
3280
|
+
},
|
3281
|
+
|
3282
|
+
setValue: function(value) {
|
3283
|
+
if(!value) {
|
3284
|
+
return;
|
3285
|
+
}
|
3286
|
+
|
3287
|
+
var dt = typeof value === 'string' ? moment(value, this.options.format) : moment(value),
|
3288
|
+
that = this,
|
3289
|
+
values = {};
|
3290
|
+
|
3291
|
+
if(dt.isValid()) {
|
3292
|
+
//read values from date object
|
3293
|
+
$.each(this.map, function(k, v) {
|
3294
|
+
if(k === 'ampm') {
|
3295
|
+
return;
|
3296
|
+
}
|
3297
|
+
values[k] = dt[v[1]]();
|
3298
|
+
});
|
3299
|
+
|
3300
|
+
if(this.$ampm) {
|
3301
|
+
if(values.hour > 12) {
|
3302
|
+
values.hour -= 12;
|
3303
|
+
values.ampm = 'pm';
|
3304
|
+
} else {
|
3305
|
+
values.ampm = 'am';
|
3306
|
+
}
|
3307
|
+
}
|
3308
|
+
|
3309
|
+
$.each(values, function(k, v) {
|
3310
|
+
if(that['$'+k]) {
|
3311
|
+
that['$'+k].val(v);
|
3312
|
+
}
|
3313
|
+
});
|
3314
|
+
|
3315
|
+
this.$element.val(dt.format(this.options.format));
|
3316
|
+
}
|
3317
|
+
},
|
3318
|
+
|
3319
|
+
/*
|
3320
|
+
highlight combos if date is invalid
|
3321
|
+
*/
|
3322
|
+
highlight: function(dt) {
|
3323
|
+
if(!dt.isValid()) {
|
3324
|
+
if(this.options.errorClass) {
|
3325
|
+
this.$widget.addClass(this.options.errorClass);
|
3326
|
+
} else {
|
3327
|
+
//store original border color
|
3328
|
+
if(!this.borderColor) {
|
3329
|
+
this.borderColor = this.$widget.find('select').css('border-color');
|
3330
|
+
}
|
3331
|
+
this.$widget.find('select').css('border-color', 'red');
|
3332
|
+
}
|
3333
|
+
} else {
|
3334
|
+
if(this.options.errorClass) {
|
3335
|
+
this.$widget.removeClass(this.options.errorClass);
|
3336
|
+
} else {
|
3337
|
+
this.$widget.find('select').css('border-color', this.borderColor);
|
3338
|
+
}
|
3339
|
+
}
|
3340
|
+
},
|
3341
|
+
|
3342
|
+
leadZero: function(v) {
|
3343
|
+
return v <= 9 ? '0' + v : v;
|
3344
|
+
},
|
3345
|
+
|
3346
|
+
destroy: function() {
|
3347
|
+
this.$widget.remove();
|
3348
|
+
this.$element.removeData('combodate').show();
|
3349
|
+
}
|
3350
|
+
|
3351
|
+
//todo: clear method
|
3352
|
+
};
|
3353
|
+
|
3354
|
+
$.fn.combodate = function ( option ) {
|
3355
|
+
var d, args = Array.apply(null, arguments);
|
3356
|
+
args.shift();
|
3357
|
+
|
3358
|
+
//getValue returns date as string / object (not jQuery object)
|
3359
|
+
if(option === 'getValue' && this.length && (d = this.eq(0).data('combodate'))) {
|
3360
|
+
return d.getValue.apply(d, args);
|
3361
|
+
}
|
3362
|
+
|
3363
|
+
return this.each(function () {
|
3364
|
+
var $this = $(this),
|
3365
|
+
data = $this.data('combodate'),
|
3366
|
+
options = typeof option == 'object' && option;
|
3367
|
+
if (!data) {
|
3368
|
+
$this.data('combodate', (data = new Combodate(this, options)));
|
3369
|
+
}
|
3370
|
+
if (typeof option == 'string' && typeof data[option] == 'function') {
|
3371
|
+
data[option].apply(data, args);
|
3372
|
+
}
|
3373
|
+
});
|
3374
|
+
};
|
3375
|
+
|
3376
|
+
$.fn.combodate.defaults = {
|
3377
|
+
//in this format value stored in original input
|
3378
|
+
format: 'DD-MM-YYYY HH:mm',
|
3379
|
+
//in this format items in dropdowns are displayed
|
3380
|
+
template: 'D / MMM / YYYY H : mm',
|
3381
|
+
//initial value, can be `new Date()`
|
3382
|
+
value: null,
|
3383
|
+
minYear: 1970,
|
3384
|
+
maxYear: 2015,
|
3385
|
+
minuteStep: 5,
|
3386
|
+
secondStep: 1,
|
3387
|
+
firstItem: 'empty', //'name', 'empty', 'none'
|
3388
|
+
errorClass: null
|
3389
|
+
};
|
3390
|
+
|
3391
|
+
}(window.jQuery));
|
3392
|
+
/**
|
3393
|
+
Combodate input - dropdown date and time picker.
|
3394
|
+
Based on [combodate](http://vitalets.github.com/combodate) plugin. To use it you should manually include [momentjs](http://momentjs.com).
|
3395
|
+
|
3396
|
+
<script src="js/moment.min.js"></script>
|
3397
|
+
|
3398
|
+
Allows to input:
|
3399
|
+
|
3400
|
+
* only date
|
3401
|
+
* only time
|
3402
|
+
* both date and time
|
3403
|
+
|
3404
|
+
Please note, that format is taken from momentjs and **not compatible** with bootstrap-datepicker / jquery UI datepicker.
|
3405
|
+
Internally value stored as `momentjs` object.
|
3406
|
+
|
3407
|
+
@class combodate
|
3408
|
+
@extends abstractinput
|
3409
|
+
@final
|
3410
|
+
@since 1.4.0
|
3411
|
+
@example
|
3412
|
+
<a href="#" id="dob" data-type="combodate" data-pk="1" data-url="/post" data-value="1984-05-15" data-original-title="Select date"></a>
|
3413
|
+
<script>
|
3414
|
+
$(function(){
|
3415
|
+
$('#dob').editable({
|
3416
|
+
format: 'YYYY-MM-DD',
|
3417
|
+
viewformat: 'DD.MM.YYYY',
|
3418
|
+
template: 'D / MMMM / YYYY',
|
3419
|
+
combodate: {
|
3420
|
+
minYear: 2000,
|
3421
|
+
maxYear: 2015,
|
3422
|
+
minuteStep: 1
|
3423
|
+
}
|
3424
|
+
}
|
3425
|
+
});
|
3426
|
+
});
|
3427
|
+
</script>
|
3428
|
+
**/
|
3429
|
+
|
3430
|
+
/*global moment*/
|
3431
|
+
|
3432
|
+
(function ($) {
|
3433
|
+
|
3434
|
+
var Constructor = function (options) {
|
3435
|
+
this.init('combodate', options, Constructor.defaults);
|
3436
|
+
|
3437
|
+
//by default viewformat equals to format
|
3438
|
+
if(!this.options.viewformat) {
|
3439
|
+
this.options.viewformat = this.options.format;
|
3440
|
+
}
|
3441
|
+
|
3442
|
+
//overriding combodate config (as by default jQuery extend() is not recursive)
|
3443
|
+
this.options.combodate = $.extend({}, Constructor.defaults.combodate, options.combodate, {
|
3444
|
+
format: this.options.format,
|
3445
|
+
template: this.options.template
|
3446
|
+
});
|
3447
|
+
};
|
3448
|
+
|
3449
|
+
$.fn.editableutils.inherit(Constructor, $.fn.editabletypes.abstractinput);
|
3450
|
+
|
3451
|
+
$.extend(Constructor.prototype, {
|
3452
|
+
render: function () {
|
3453
|
+
this.$input.combodate(this.options.combodate);
|
3454
|
+
|
3455
|
+
//"clear" link
|
3456
|
+
/*
|
3457
|
+
if(this.options.clear) {
|
3458
|
+
this.$clear = $('<a href="#"></a>').html(this.options.clear).click($.proxy(function(e){
|
3459
|
+
e.preventDefault();
|
3460
|
+
e.stopPropagation();
|
3461
|
+
this.clear();
|
3462
|
+
}, this));
|
3463
|
+
|
3464
|
+
this.$tpl.parent().append($('<div class="editable-clear">').append(this.$clear));
|
3465
|
+
}
|
3466
|
+
*/
|
3467
|
+
},
|
3468
|
+
|
3469
|
+
value2html: function(value, element) {
|
3470
|
+
var text = value ? value.format(this.options.viewformat) : '';
|
3471
|
+
$(element).text(text);
|
3472
|
+
},
|
3473
|
+
|
3474
|
+
html2value: function(html) {
|
3475
|
+
return html ? moment(html, this.options.viewformat) : null;
|
3476
|
+
},
|
3477
|
+
|
3478
|
+
value2str: function(value) {
|
3479
|
+
return value ? value.format(this.options.format) : '';
|
3480
|
+
},
|
3481
|
+
|
3482
|
+
str2value: function(str) {
|
3483
|
+
return str ? moment(str, this.options.format) : null;
|
3484
|
+
},
|
3485
|
+
|
3486
|
+
value2submit: function(value) {
|
3487
|
+
return this.value2str(value);
|
3488
|
+
},
|
3489
|
+
|
3490
|
+
value2input: function(value) {
|
3491
|
+
this.$input.combodate('setValue', value);
|
3492
|
+
},
|
3493
|
+
|
3494
|
+
input2value: function() {
|
3495
|
+
return this.$input.combodate('getValue', null);
|
3496
|
+
},
|
3497
|
+
|
3498
|
+
activate: function() {
|
3499
|
+
this.$input.siblings('.combodate').find('select').eq(0).focus();
|
3500
|
+
},
|
3501
|
+
|
3502
|
+
/*
|
3503
|
+
clear: function() {
|
3504
|
+
this.$input.data('datepicker').date = null;
|
3505
|
+
this.$input.find('.active').removeClass('active');
|
3506
|
+
},
|
3507
|
+
*/
|
3508
|
+
|
3509
|
+
autosubmit: function() {
|
3510
|
+
|
3511
|
+
}
|
3512
|
+
|
3513
|
+
});
|
3514
|
+
|
3515
|
+
Constructor.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, {
|
3516
|
+
/**
|
3517
|
+
@property tpl
|
3518
|
+
@default <input type="text">
|
3519
|
+
**/
|
3520
|
+
tpl:'<input type="text">',
|
3521
|
+
/**
|
3522
|
+
@property inputclass
|
3523
|
+
@default null
|
3524
|
+
**/
|
3525
|
+
inputclass: null,
|
3526
|
+
/**
|
3527
|
+
Format used for sending value to server. Also applied when converting date from <code>data-value</code> attribute.<br>
|
3528
|
+
See list of tokens in [momentjs docs](http://momentjs.com/docs/#/parsing/string-format)
|
3529
|
+
|
3530
|
+
@property format
|
3531
|
+
@type string
|
3532
|
+
@default YYYY-MM-DD
|
3533
|
+
**/
|
3534
|
+
format:'YYYY-MM-DD',
|
3535
|
+
/**
|
3536
|
+
Format used for displaying date. Also applied when converting date from element's text on init.
|
3537
|
+
If not specified equals to `format`.
|
3538
|
+
|
3539
|
+
@property viewformat
|
3540
|
+
@type string
|
3541
|
+
@default null
|
3542
|
+
**/
|
3543
|
+
viewformat: null,
|
3544
|
+
/**
|
3545
|
+
Template used for displaying dropdowns.
|
3546
|
+
|
3547
|
+
@property template
|
3548
|
+
@type string
|
3549
|
+
@default D / MMM / YYYY
|
3550
|
+
**/
|
3551
|
+
template: 'D / MMM / YYYY',
|
3552
|
+
/**
|
3553
|
+
Configuration of combodate.
|
3554
|
+
Full list of options: http://vitalets.github.com/combodate/#docs
|
3555
|
+
|
3556
|
+
@property combodate
|
3557
|
+
@type object
|
3558
|
+
@default null
|
3559
|
+
**/
|
3560
|
+
combodate: null
|
3561
|
+
|
3562
|
+
/*
|
3563
|
+
(not implemented yet)
|
3564
|
+
Text shown as clear date button.
|
3565
|
+
If <code>false</code> clear button will not be rendered.
|
3566
|
+
|
3567
|
+
@property clear
|
3568
|
+
@type boolean|string
|
3569
|
+
@default 'x clear'
|
3570
|
+
*/
|
3571
|
+
//clear: '× clear'
|
3572
|
+
});
|
3573
|
+
|
3574
|
+
$.fn.editabletypes.combodate = Constructor;
|
3575
|
+
|
3576
|
+
}(window.jQuery));
|
3577
|
+
|
2640
3578
|
/*
|
2641
3579
|
Editableform based on Twitter Bootstrap
|
2642
3580
|
*/
|
@@ -2666,7 +3604,7 @@ Editableform based on Twitter Bootstrap
|
|
2666
3604
|
(function ($) {
|
2667
3605
|
|
2668
3606
|
//extend methods
|
2669
|
-
$.extend($.fn.editableContainer.
|
3607
|
+
$.extend($.fn.editableContainer.Popup.prototype, {
|
2670
3608
|
containerName: 'popover',
|
2671
3609
|
//for compatibility with bootstrap <= 2.2.1 (content inserted into <p> instead of directly .popover-content)
|
2672
3610
|
innerCss: $($.fn.popover.defaults.template).find('p').length ? '.popover-content p' : '.popover-content',
|
@@ -2675,10 +3613,39 @@ Editableform based on Twitter Bootstrap
|
|
2675
3613
|
$.extend(this.containerOptions, {
|
2676
3614
|
trigger: 'manual',
|
2677
3615
|
selector: false,
|
2678
|
-
content: ' '
|
3616
|
+
content: ' ',
|
3617
|
+
template: $.fn.popover.defaults.template
|
2679
3618
|
});
|
3619
|
+
|
3620
|
+
//as template property is used in inputs, hide it from popover
|
3621
|
+
var t;
|
3622
|
+
if(this.$element.data('template')) {
|
3623
|
+
t = this.$element.data('template');
|
3624
|
+
this.$element.removeData('template');
|
3625
|
+
}
|
3626
|
+
|
2680
3627
|
this.call(this.containerOptions);
|
2681
|
-
|
3628
|
+
|
3629
|
+
if(t) {
|
3630
|
+
//restore data('template')
|
3631
|
+
this.$element.data('template', t);
|
3632
|
+
}
|
3633
|
+
},
|
3634
|
+
|
3635
|
+
/* show */
|
3636
|
+
innerShow: function () {
|
3637
|
+
this.call('show');
|
3638
|
+
},
|
3639
|
+
|
3640
|
+
/* hide */
|
3641
|
+
innerHide: function () {
|
3642
|
+
this.call('hide');
|
3643
|
+
},
|
3644
|
+
|
3645
|
+
/* destroy */
|
3646
|
+
innerDestroy: function() {
|
3647
|
+
this.call('destroy');
|
3648
|
+
},
|
2682
3649
|
|
2683
3650
|
setContainerOption: function(key, value) {
|
2684
3651
|
this.container().options[key] = value;
|
@@ -2742,18 +3709,13 @@ Editableform based on Twitter Bootstrap
|
|
2742
3709
|
}
|
2743
3710
|
});
|
2744
3711
|
|
2745
|
-
//defaults
|
2746
|
-
/*
|
2747
|
-
$.fn.editableContainer.defaults = $.extend({}, $.fn.popover.defaults, $.fn.editableContainer.defaults, {
|
2748
|
-
|
2749
|
-
});
|
2750
|
-
*/
|
2751
|
-
|
2752
3712
|
}(window.jQuery));
|
2753
3713
|
/**
|
2754
3714
|
Bootstrap-datepicker.
|
2755
|
-
Description and examples:
|
2756
|
-
For
|
3715
|
+
Description and examples: https://github.com/eternicode/bootstrap-datepicker.
|
3716
|
+
For **i18n** you should include js file from here: https://github.com/eternicode/bootstrap-datepicker/tree/master/js/locales
|
3717
|
+
and set `language` option.
|
3718
|
+
Since 1.4.0 date has different appearance in **popup** and **inline** modes.
|
2757
3719
|
|
2758
3720
|
@class date
|
2759
3721
|
@extends abstractinput
|
@@ -2777,45 +3739,52 @@ $(function(){
|
|
2777
3739
|
|
2778
3740
|
var Date = function (options) {
|
2779
3741
|
this.init('date', options, Date.defaults);
|
2780
|
-
|
2781
|
-
//set popular options directly from settings or data-* attributes
|
2782
|
-
var directOptions = $.fn.editableutils.sliceObj(this.options, ['format']);
|
2783
|
-
|
2784
|
-
//overriding datepicker config (as by default jQuery extend() is not recursive)
|
2785
|
-
this.options.datepicker = $.extend({}, Date.defaults.datepicker, directOptions, options.datepicker);
|
2786
|
-
|
2787
|
-
//by default viewformat equals to format
|
2788
|
-
if(!this.options.viewformat) {
|
2789
|
-
this.options.viewformat = this.options.datepicker.format;
|
2790
|
-
}
|
2791
|
-
|
2792
|
-
//language
|
2793
|
-
this.options.datepicker.language = this.options.datepicker.language || 'en';
|
2794
|
-
|
2795
|
-
//store DPglobal
|
2796
|
-
this.dpg = $.fn.datepicker.DPGlobal;
|
2797
|
-
|
2798
|
-
//store parsed formats
|
2799
|
-
this.parsedFormat = this.dpg.parseFormat(this.options.datepicker.format);
|
2800
|
-
this.parsedViewFormat = this.dpg.parseFormat(this.options.viewformat);
|
3742
|
+
this.initPicker(options, Date.defaults);
|
2801
3743
|
};
|
2802
3744
|
|
2803
3745
|
$.fn.editableutils.inherit(Date, $.fn.editabletypes.abstractinput);
|
2804
3746
|
|
2805
3747
|
$.extend(Date.prototype, {
|
3748
|
+
initPicker: function(options, defaults) {
|
3749
|
+
//'format' is set directly from settings or data-* attributes
|
3750
|
+
|
3751
|
+
//by default viewformat equals to format
|
3752
|
+
if(!this.options.viewformat) {
|
3753
|
+
this.options.viewformat = this.options.format;
|
3754
|
+
}
|
3755
|
+
|
3756
|
+
//overriding datepicker config (as by default jQuery extend() is not recursive)
|
3757
|
+
//since 1.4 datepicker internally uses viewformat instead of format. Format is for submit only
|
3758
|
+
this.options.datepicker = $.extend({}, defaults.datepicker, options.datepicker, {
|
3759
|
+
format: this.options.viewformat
|
3760
|
+
});
|
3761
|
+
|
3762
|
+
//language
|
3763
|
+
this.options.datepicker.language = this.options.datepicker.language || 'en';
|
3764
|
+
|
3765
|
+
//store DPglobal
|
3766
|
+
this.dpg = $.fn.datepicker.DPGlobal;
|
3767
|
+
|
3768
|
+
//store parsed formats
|
3769
|
+
this.parsedFormat = this.dpg.parseFormat(this.options.format);
|
3770
|
+
this.parsedViewFormat = this.dpg.parseFormat(this.options.viewformat);
|
3771
|
+
},
|
3772
|
+
|
2806
3773
|
render: function () {
|
2807
|
-
Date.superclass.render.call(this);
|
2808
3774
|
this.$input.datepicker(this.options.datepicker);
|
2809
|
-
|
3775
|
+
|
3776
|
+
//"clear" link
|
2810
3777
|
if(this.options.clear) {
|
2811
3778
|
this.$clear = $('<a href="#"></a>').html(this.options.clear).click($.proxy(function(e){
|
2812
3779
|
e.preventDefault();
|
2813
3780
|
e.stopPropagation();
|
2814
3781
|
this.clear();
|
2815
3782
|
}, this));
|
2816
|
-
|
3783
|
+
|
3784
|
+
this.$tpl.parent().append($('<div class="editable-clear">').append(this.$clear));
|
3785
|
+
}
|
2817
3786
|
},
|
2818
|
-
|
3787
|
+
|
2819
3788
|
value2html: function(value, element) {
|
2820
3789
|
var text = value ? this.dpg.formatDate(value, this.parsedViewFormat, this.options.datepicker.language) : '';
|
2821
3790
|
Date.superclass.value2html(text, element);
|
@@ -2869,12 +3838,12 @@ $(function(){
|
|
2869
3838
|
@property tpl
|
2870
3839
|
@default <div></div>
|
2871
3840
|
**/
|
2872
|
-
tpl:'<div></div>',
|
3841
|
+
tpl:'<div class="editable-date well"></div>',
|
2873
3842
|
/**
|
2874
3843
|
@property inputclass
|
2875
|
-
@default
|
3844
|
+
@default null
|
2876
3845
|
**/
|
2877
|
-
inputclass:
|
3846
|
+
inputclass: null,
|
2878
3847
|
/**
|
2879
3848
|
Format used for sending value to server. Also applied when converting date from <code>data-value</code> attribute.<br>
|
2880
3849
|
Possible tokens are: <code>d, dd, m, mm, yy, yyyy</code>
|
@@ -2925,6 +3894,84 @@ $(function(){
|
|
2925
3894
|
|
2926
3895
|
}(window.jQuery));
|
2927
3896
|
|
3897
|
+
/**
|
3898
|
+
Bootstrap datefield input - modification for inline mode.
|
3899
|
+
Shows normal <input type="text"> and binds popup datepicker.
|
3900
|
+
Automatically shown in inline mode.
|
3901
|
+
|
3902
|
+
@class datefield
|
3903
|
+
@extends date
|
3904
|
+
|
3905
|
+
@since 1.4.0
|
3906
|
+
**/
|
3907
|
+
(function ($) {
|
3908
|
+
|
3909
|
+
var DateField = function (options) {
|
3910
|
+
this.init('datefield', options, DateField.defaults);
|
3911
|
+
this.initPicker(options, DateField.defaults);
|
3912
|
+
};
|
3913
|
+
|
3914
|
+
$.fn.editableutils.inherit(DateField, $.fn.editabletypes.date);
|
3915
|
+
|
3916
|
+
$.extend(DateField.prototype, {
|
3917
|
+
render: function () {
|
3918
|
+
this.$input = this.$tpl.find('input');
|
3919
|
+
this.setClass();
|
3920
|
+
this.setAttr('placeholder');
|
3921
|
+
|
3922
|
+
this.$tpl.datepicker(this.options.datepicker);
|
3923
|
+
|
3924
|
+
//need to disable original event handlers
|
3925
|
+
this.$input.off('focus keydown');
|
3926
|
+
|
3927
|
+
//update value of datepicker
|
3928
|
+
this.$input.keyup($.proxy(function(){
|
3929
|
+
this.$tpl.removeData('date');
|
3930
|
+
this.$tpl.datepicker('update');
|
3931
|
+
}, this));
|
3932
|
+
|
3933
|
+
},
|
3934
|
+
|
3935
|
+
value2input: function(value) {
|
3936
|
+
this.$input.val(value ? this.dpg.formatDate(value, this.parsedViewFormat, this.options.datepicker.language) : '');
|
3937
|
+
this.$tpl.datepicker('update');
|
3938
|
+
},
|
3939
|
+
|
3940
|
+
input2value: function() {
|
3941
|
+
return this.html2value(this.$input.val());
|
3942
|
+
},
|
3943
|
+
|
3944
|
+
activate: function() {
|
3945
|
+
$.fn.editabletypes.text.prototype.activate.call(this);
|
3946
|
+
},
|
3947
|
+
|
3948
|
+
autosubmit: function() {
|
3949
|
+
//reset autosubmit to empty
|
3950
|
+
}
|
3951
|
+
});
|
3952
|
+
|
3953
|
+
DateField.defaults = $.extend({}, $.fn.editabletypes.date.defaults, {
|
3954
|
+
/**
|
3955
|
+
@property tpl
|
3956
|
+
**/
|
3957
|
+
tpl:'<div class="input-append date"><input type="text"/><span class="add-on"><i class="icon-th"></i></span></div>',
|
3958
|
+
/**
|
3959
|
+
@property inputclass
|
3960
|
+
@default 'input-small'
|
3961
|
+
**/
|
3962
|
+
inputclass: 'input-small',
|
3963
|
+
|
3964
|
+
/* datepicker config */
|
3965
|
+
datepicker: {
|
3966
|
+
weekStart: 0,
|
3967
|
+
startView: 0,
|
3968
|
+
autoclose: true
|
3969
|
+
}
|
3970
|
+
});
|
3971
|
+
|
3972
|
+
$.fn.editabletypes.datefield = DateField;
|
3973
|
+
|
3974
|
+
}(window.jQuery));
|
2928
3975
|
/* =========================================================
|
2929
3976
|
* bootstrap-datepicker.js
|
2930
3977
|
* http://www.eyecon.ro/bootstrap-datepicker
|
@@ -2963,51 +4010,45 @@ $(function(){
|
|
2963
4010
|
this.element = $(element);
|
2964
4011
|
this.language = options.language||this.element.data('date-language')||"en";
|
2965
4012
|
this.language = this.language in dates ? this.language : "en";
|
4013
|
+
this.isRTL = dates[this.language].rtl||false;
|
2966
4014
|
this.format = DPGlobal.parseFormat(options.format||this.element.data('date-format')||'mm/dd/yyyy');
|
2967
|
-
|
4015
|
+
this.isInline = false;
|
2968
4016
|
this.isInput = this.element.is('input');
|
2969
4017
|
this.component = this.element.is('.date') ? this.element.find('.add-on') : false;
|
2970
4018
|
this.hasInput = this.component && this.element.find('input').length;
|
2971
4019
|
if(this.component && this.component.length === 0)
|
2972
4020
|
this.component = false;
|
2973
4021
|
|
2974
|
-
|
2975
|
-
this.element.on({
|
2976
|
-
focus: $.proxy(this.show, this),
|
2977
|
-
keyup: $.proxy(this.update, this),
|
2978
|
-
keydown: $.proxy(this.keydown, this)
|
2979
|
-
});
|
2980
|
-
} else if(this.component && this.hasInput) { //component: input + button
|
2981
|
-
// For components that are not readonly, allow keyboard nav
|
2982
|
-
this.element.find('input').on({
|
2983
|
-
focus: $.proxy(this.show, this),
|
2984
|
-
keyup: $.proxy(this.update, this),
|
2985
|
-
keydown: $.proxy(this.keydown, this)
|
2986
|
-
});
|
2987
|
-
|
2988
|
-
this.component.on('click', $.proxy(this.show, this));
|
2989
|
-
} else if(this.element.is('div')) { //inline datepicker
|
2990
|
-
this.isInline = true;
|
2991
|
-
} else {
|
2992
|
-
this.element.on('click', $.proxy(this.show, this));
|
2993
|
-
}
|
2994
|
-
|
2995
|
-
this.picker = $(DPGlobal.template)
|
2996
|
-
.appendTo(this.isInline ? this.element : 'body')
|
2997
|
-
.on({
|
2998
|
-
click: $.proxy(this.click, this),
|
2999
|
-
mousedown: $.proxy(this.mousedown, this)
|
3000
|
-
});
|
3001
|
-
|
3002
|
-
if(this.isInline) {
|
3003
|
-
this.picker.addClass('datepicker-inline');
|
3004
|
-
} else {
|
3005
|
-
this.picker.addClass('dropdown-menu');
|
3006
|
-
}
|
4022
|
+
this._attachEvents();
|
3007
4023
|
|
4024
|
+
this.forceParse = true;
|
4025
|
+
if ('forceParse' in options) {
|
4026
|
+
this.forceParse = options.forceParse;
|
4027
|
+
} else if ('dateForceParse' in this.element.data()) {
|
4028
|
+
this.forceParse = this.element.data('date-force-parse');
|
4029
|
+
}
|
4030
|
+
|
4031
|
+
|
4032
|
+
this.picker = $(DPGlobal.template)
|
4033
|
+
.appendTo(this.isInline ? this.element : 'body')
|
4034
|
+
.on({
|
4035
|
+
click: $.proxy(this.click, this),
|
4036
|
+
mousedown: $.proxy(this.mousedown, this)
|
4037
|
+
});
|
4038
|
+
|
4039
|
+
if(this.isInline) {
|
4040
|
+
this.picker.addClass('datepicker-inline');
|
4041
|
+
} else {
|
4042
|
+
this.picker.addClass('datepicker-dropdown dropdown-menu');
|
4043
|
+
}
|
4044
|
+
if (this.isRTL){
|
4045
|
+
this.picker.addClass('datepicker-rtl');
|
4046
|
+
this.picker.find('.prev i, .next i')
|
4047
|
+
.toggleClass('icon-arrow-left icon-arrow-right');
|
4048
|
+
}
|
3008
4049
|
$(document).on('mousedown', function (e) {
|
3009
4050
|
// Clicked outside the datepicker, hide it
|
3010
|
-
if ($(e.target).closest('.datepicker').length
|
4051
|
+
if ($(e.target).closest('.datepicker').length === 0) {
|
3011
4052
|
that.hide();
|
3012
4053
|
}
|
3013
4054
|
});
|
@@ -3026,6 +4067,7 @@ $(function(){
|
|
3026
4067
|
this.keyboardNavigation = this.element.data('date-keyboard-navigation');
|
3027
4068
|
}
|
3028
4069
|
|
4070
|
+
this.viewMode = this.startViewMode = 0;
|
3029
4071
|
switch(options.startView || this.element.data('date-start-view')){
|
3030
4072
|
case 2:
|
3031
4073
|
case 'decade':
|
@@ -3035,11 +4077,6 @@ $(function(){
|
|
3035
4077
|
case 'year':
|
3036
4078
|
this.viewMode = this.startViewMode = 1;
|
3037
4079
|
break;
|
3038
|
-
case 0:
|
3039
|
-
case 'month':
|
3040
|
-
default:
|
3041
|
-
this.viewMode = this.startViewMode = 0;
|
3042
|
-
break;
|
3043
4080
|
}
|
3044
4081
|
|
3045
4082
|
this.todayBtn = (options.todayBtn||this.element.data('date-today-btn')||false);
|
@@ -3049,21 +4086,73 @@ $(function(){
|
|
3049
4086
|
this.weekEnd = ((this.weekStart + 6) % 7);
|
3050
4087
|
this.startDate = -Infinity;
|
3051
4088
|
this.endDate = Infinity;
|
4089
|
+
this.daysOfWeekDisabled = [];
|
3052
4090
|
this.setStartDate(options.startDate||this.element.data('date-startdate'));
|
3053
4091
|
this.setEndDate(options.endDate||this.element.data('date-enddate'));
|
4092
|
+
this.setDaysOfWeekDisabled(options.daysOfWeekDisabled||this.element.data('date-days-of-week-disabled'));
|
3054
4093
|
this.fillDow();
|
3055
4094
|
this.fillMonths();
|
3056
4095
|
this.update();
|
3057
4096
|
this.showMode();
|
3058
4097
|
|
3059
|
-
|
3060
|
-
|
3061
|
-
|
4098
|
+
if(this.isInline) {
|
4099
|
+
this.show();
|
4100
|
+
}
|
3062
4101
|
};
|
3063
4102
|
|
3064
4103
|
Datepicker.prototype = {
|
3065
4104
|
constructor: Datepicker,
|
3066
4105
|
|
4106
|
+
_events: [],
|
4107
|
+
_attachEvents: function(){
|
4108
|
+
this._detachEvents();
|
4109
|
+
if (this.isInput) { // single input
|
4110
|
+
this._events = [
|
4111
|
+
[this.element, {
|
4112
|
+
focus: $.proxy(this.show, this),
|
4113
|
+
keyup: $.proxy(this.update, this),
|
4114
|
+
keydown: $.proxy(this.keydown, this)
|
4115
|
+
}]
|
4116
|
+
];
|
4117
|
+
}
|
4118
|
+
else if (this.component && this.hasInput){ // component: input + button
|
4119
|
+
this._events = [
|
4120
|
+
// For components that are not readonly, allow keyboard nav
|
4121
|
+
[this.element.find('input'), {
|
4122
|
+
focus: $.proxy(this.show, this),
|
4123
|
+
keyup: $.proxy(this.update, this),
|
4124
|
+
keydown: $.proxy(this.keydown, this)
|
4125
|
+
}],
|
4126
|
+
[this.component, {
|
4127
|
+
click: $.proxy(this.show, this)
|
4128
|
+
}]
|
4129
|
+
];
|
4130
|
+
}
|
4131
|
+
else if (this.element.is('div')) { // inline datepicker
|
4132
|
+
this.isInline = true;
|
4133
|
+
}
|
4134
|
+
else {
|
4135
|
+
this._events = [
|
4136
|
+
[this.element, {
|
4137
|
+
click: $.proxy(this.show, this)
|
4138
|
+
}]
|
4139
|
+
];
|
4140
|
+
}
|
4141
|
+
for (var i=0, el, ev; i<this._events.length; i++){
|
4142
|
+
el = this._events[i][0];
|
4143
|
+
ev = this._events[i][1];
|
4144
|
+
el.on(ev);
|
4145
|
+
}
|
4146
|
+
},
|
4147
|
+
_detachEvents: function(){
|
4148
|
+
for (var i=0, el, ev; i<this._events.length; i++){
|
4149
|
+
el = this._events[i][0];
|
4150
|
+
ev = this._events[i][1];
|
4151
|
+
el.off(ev);
|
4152
|
+
}
|
4153
|
+
this._events = [];
|
4154
|
+
},
|
4155
|
+
|
3067
4156
|
show: function(e) {
|
3068
4157
|
this.picker.show();
|
3069
4158
|
this.height = this.component ? this.component.outerHeight() : this.element.outerHeight();
|
@@ -3081,7 +4170,7 @@ $(function(){
|
|
3081
4170
|
},
|
3082
4171
|
|
3083
4172
|
hide: function(e){
|
3084
|
-
|
4173
|
+
if(this.isInline) return;
|
3085
4174
|
this.picker.hide();
|
3086
4175
|
$(window).off('resize', this.place);
|
3087
4176
|
this.viewMode = this.startViewMode;
|
@@ -3089,7 +4178,14 @@ $(function(){
|
|
3089
4178
|
if (!this.isInput) {
|
3090
4179
|
$(document).off('mousedown', this.hide);
|
3091
4180
|
}
|
3092
|
-
|
4181
|
+
|
4182
|
+
if (
|
4183
|
+
this.forceParse &&
|
4184
|
+
(
|
4185
|
+
this.isInput && this.element.val() ||
|
4186
|
+
this.hasInput && this.element.find('input').val()
|
4187
|
+
)
|
4188
|
+
)
|
3093
4189
|
this.setValue();
|
3094
4190
|
this.element.trigger({
|
3095
4191
|
type: 'hide',
|
@@ -3097,9 +4193,15 @@ $(function(){
|
|
3097
4193
|
});
|
3098
4194
|
},
|
3099
4195
|
|
4196
|
+
remove: function() {
|
4197
|
+
this._detachEvents();
|
4198
|
+
this.picker.remove();
|
4199
|
+
delete this.element.data().datepicker;
|
4200
|
+
},
|
4201
|
+
|
3100
4202
|
getDate: function() {
|
3101
4203
|
var d = this.getUTCDate();
|
3102
|
-
return new Date(d.getTime() + (d.getTimezoneOffset()*60000))
|
4204
|
+
return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
|
3103
4205
|
},
|
3104
4206
|
|
3105
4207
|
getUTCDate: function() {
|
@@ -3119,18 +4221,19 @@ $(function(){
|
|
3119
4221
|
var formatted = this.getFormattedDate();
|
3120
4222
|
if (!this.isInput) {
|
3121
4223
|
if (this.component){
|
3122
|
-
this.element.find('input').
|
4224
|
+
this.element.find('input').val(formatted);
|
3123
4225
|
}
|
3124
4226
|
this.element.data('date', formatted);
|
3125
4227
|
} else {
|
3126
|
-
this.element.
|
4228
|
+
this.element.val(formatted);
|
3127
4229
|
}
|
3128
4230
|
},
|
3129
4231
|
|
3130
|
-
|
3131
|
-
|
3132
|
-
|
3133
|
-
|
4232
|
+
getFormattedDate: function(format) {
|
4233
|
+
if (format === undefined)
|
4234
|
+
format = this.format;
|
4235
|
+
return DPGlobal.formatDate(this.date, format, this.language);
|
4236
|
+
},
|
3134
4237
|
|
3135
4238
|
setStartDate: function(startDate){
|
3136
4239
|
this.startDate = startDate||-Infinity;
|
@@ -3150,32 +4253,46 @@ $(function(){
|
|
3150
4253
|
this.updateNavArrows();
|
3151
4254
|
},
|
3152
4255
|
|
4256
|
+
setDaysOfWeekDisabled: function(daysOfWeekDisabled){
|
4257
|
+
this.daysOfWeekDisabled = daysOfWeekDisabled||[];
|
4258
|
+
if (!$.isArray(this.daysOfWeekDisabled)) {
|
4259
|
+
this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
|
4260
|
+
}
|
4261
|
+
this.daysOfWeekDisabled = $.map(this.daysOfWeekDisabled, function (d) {
|
4262
|
+
return parseInt(d, 10);
|
4263
|
+
});
|
4264
|
+
this.update();
|
4265
|
+
this.updateNavArrows();
|
4266
|
+
},
|
4267
|
+
|
3153
4268
|
place: function(){
|
3154
|
-
|
4269
|
+
if(this.isInline) return;
|
3155
4270
|
var zIndex = parseInt(this.element.parents().filter(function() {
|
3156
4271
|
return $(this).css('z-index') != 'auto';
|
3157
4272
|
}).first().css('z-index'))+10;
|
3158
4273
|
var offset = this.component ? this.component.offset() : this.element.offset();
|
4274
|
+
var height = this.component ? this.component.outerHeight(true) : this.element.outerHeight(true);
|
3159
4275
|
this.picker.css({
|
3160
|
-
top: offset.top +
|
4276
|
+
top: offset.top + height,
|
3161
4277
|
left: offset.left,
|
3162
4278
|
zIndex: zIndex
|
3163
4279
|
});
|
3164
4280
|
},
|
3165
4281
|
|
3166
4282
|
update: function(){
|
3167
|
-
|
3168
|
-
|
3169
|
-
|
3170
|
-
|
3171
|
-
|
3172
|
-
|
3173
|
-
|
4283
|
+
var date, fromArgs = false;
|
4284
|
+
if(arguments && arguments.length && (typeof arguments[0] === 'string' || arguments[0] instanceof Date)) {
|
4285
|
+
date = arguments[0];
|
4286
|
+
fromArgs = true;
|
4287
|
+
} else {
|
4288
|
+
date = this.isInput ? this.element.val() : this.element.data('date') || this.element.find('input').val();
|
4289
|
+
}
|
3174
4290
|
|
3175
4291
|
this.date = DPGlobal.parseDate(date, this.format, this.language);
|
3176
4292
|
|
3177
|
-
|
4293
|
+
if(fromArgs) this.setValue();
|
3178
4294
|
|
4295
|
+
var oldViewDate = this.viewDate;
|
3179
4296
|
if (this.date < this.startDate) {
|
3180
4297
|
this.viewDate = new Date(this.startDate);
|
3181
4298
|
} else if (this.date > this.endDate) {
|
@@ -3183,12 +4300,19 @@ $(function(){
|
|
3183
4300
|
} else {
|
3184
4301
|
this.viewDate = new Date(this.date);
|
3185
4302
|
}
|
4303
|
+
|
4304
|
+
if (oldViewDate && oldViewDate.getTime() != this.viewDate.getTime()){
|
4305
|
+
this.element.trigger({
|
4306
|
+
type: 'changeDate',
|
4307
|
+
date: this.viewDate
|
4308
|
+
});
|
4309
|
+
}
|
3186
4310
|
this.fill();
|
3187
4311
|
},
|
3188
4312
|
|
3189
4313
|
fillDow: function(){
|
3190
|
-
var dowCnt = this.weekStart
|
3191
|
-
|
4314
|
+
var dowCnt = this.weekStart,
|
4315
|
+
html = '<tr>';
|
3192
4316
|
while (dowCnt < this.weekStart + 7) {
|
3193
4317
|
html += '<th class="dow">'+dates[this.language].daysMin[(dowCnt++)%7]+'</th>';
|
3194
4318
|
}
|
@@ -3197,8 +4321,8 @@ $(function(){
|
|
3197
4321
|
},
|
3198
4322
|
|
3199
4323
|
fillMonths: function(){
|
3200
|
-
var html = ''
|
3201
|
-
|
4324
|
+
var html = '',
|
4325
|
+
i = 0;
|
3202
4326
|
while (i < 12) {
|
3203
4327
|
html += '<span class="month">'+dates[this.language].monthsShort[i++]+'</span>';
|
3204
4328
|
}
|
@@ -3251,7 +4375,8 @@ $(function(){
|
|
3251
4375
|
if (currentDate && prevMonth.valueOf() == currentDate) {
|
3252
4376
|
clsName += ' active';
|
3253
4377
|
}
|
3254
|
-
if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate
|
4378
|
+
if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
|
4379
|
+
$.inArray(prevMonth.getUTCDay(), this.daysOfWeekDisabled) !== -1) {
|
3255
4380
|
clsName += ' disabled';
|
3256
4381
|
}
|
3257
4382
|
html.push('<td class="day'+clsName+'">'+prevMonth.getUTCDate() + '</td>');
|
@@ -3392,7 +4517,7 @@ $(function(){
|
|
3392
4517
|
var year = this.viewDate.getUTCFullYear(),
|
3393
4518
|
month = this.viewDate.getUTCMonth();
|
3394
4519
|
if (target.is('.old')) {
|
3395
|
-
if (month
|
4520
|
+
if (month === 0) {
|
3396
4521
|
month = 11;
|
3397
4522
|
year -= 1;
|
3398
4523
|
} else {
|
@@ -3432,8 +4557,8 @@ $(function(){
|
|
3432
4557
|
}
|
3433
4558
|
if (element) {
|
3434
4559
|
element.change();
|
3435
|
-
if (this.autoclose) {
|
3436
|
-
|
4560
|
+
if (this.autoclose && (!which || which == 'date')) {
|
4561
|
+
this.hide();
|
3437
4562
|
}
|
3438
4563
|
}
|
3439
4564
|
},
|
@@ -3579,16 +4704,16 @@ $(function(){
|
|
3579
4704
|
if (dir) {
|
3580
4705
|
this.viewMode = Math.max(0, Math.min(2, this.viewMode + dir));
|
3581
4706
|
}
|
3582
|
-
|
3583
|
-
|
3584
|
-
|
3585
|
-
|
3586
|
-
|
3587
|
-
|
3588
|
-
|
3589
|
-
|
3590
|
-
|
3591
|
-
|
4707
|
+
/*
|
4708
|
+
vitalets: fixing bug of very special conditions:
|
4709
|
+
jquery 1.7.1 + webkit + show inline datepicker in bootstrap popover.
|
4710
|
+
Method show() does not set display css correctly and datepicker is not shown.
|
4711
|
+
Changed to .css('display', 'block') solve the problem.
|
4712
|
+
See https://github.com/vitalets/x-editable/issues/37
|
4713
|
+
|
4714
|
+
In jquery 1.7.2+ everything works fine.
|
4715
|
+
*/
|
4716
|
+
//this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).show();
|
3592
4717
|
this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).css('display', 'block');
|
3593
4718
|
this.updateNavArrows();
|
3594
4719
|
}
|
@@ -3622,7 +4747,7 @@ $(function(){
|
|
3622
4747
|
monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
|
3623
4748
|
today: "Today"
|
3624
4749
|
}
|
3625
|
-
}
|
4750
|
+
};
|
3626
4751
|
|
3627
4752
|
var DPGlobal = {
|
3628
4753
|
modes: [
|
@@ -3642,28 +4767,28 @@ $(function(){
|
|
3642
4767
|
navStep: 10
|
3643
4768
|
}],
|
3644
4769
|
isLeapYear: function (year) {
|
3645
|
-
return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0))
|
4770
|
+
return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0));
|
3646
4771
|
},
|
3647
4772
|
getDaysInMonth: function (year, month) {
|
3648
|
-
return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]
|
4773
|
+
return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
|
3649
4774
|
},
|
3650
|
-
validParts: /dd?|mm?|MM?|yy(?:yy)?/g,
|
3651
|
-
nonpunctuation: /[^ -\/:-@\[-`{-~\t\n\r]+/g,
|
4775
|
+
validParts: /dd?|DD?|mm?|MM?|yy(?:yy)?/g,
|
4776
|
+
nonpunctuation: /[^ -\/:-@\[\u3400-\u9fff-`{-~\t\n\r]+/g,
|
3652
4777
|
parseFormat: function(format){
|
3653
4778
|
// IE treats \0 as a string end in inputs (truncating the value),
|
3654
4779
|
// so it's a bad format delimiter, anyway
|
3655
4780
|
var separators = format.replace(this.validParts, '\0').split('\0'),
|
3656
4781
|
parts = format.match(this.validParts);
|
3657
|
-
if (!separators || !separators.length || !parts || parts.length
|
4782
|
+
if (!separators || !separators.length || !parts || parts.length === 0){
|
3658
4783
|
throw new Error("Invalid date format.");
|
3659
4784
|
}
|
3660
4785
|
return {separators: separators, parts: parts};
|
3661
4786
|
},
|
3662
4787
|
parseDate: function(date, format, language) {
|
3663
4788
|
if (date instanceof Date) return date;
|
3664
|
-
if (/^[
|
3665
|
-
var part_re = /([
|
3666
|
-
parts = date.match(/([
|
4789
|
+
if (/^[\-+]\d+[dmwy]([\s,]+[\-+]\d+[dmwy])*$/.test(date)) {
|
4790
|
+
var part_re = /([\-+]\d+)([dmwy])/,
|
4791
|
+
parts = date.match(/([\-+]\d+)([dmwy])/g),
|
3667
4792
|
part, dir;
|
3668
4793
|
date = new Date();
|
3669
4794
|
for (var i=0; i<parts.length; i++) {
|
@@ -3708,10 +4833,18 @@ $(function(){
|
|
3708
4833
|
setters_map['M'] = setters_map['MM'] = setters_map['mm'] = setters_map['m'];
|
3709
4834
|
setters_map['dd'] = setters_map['d'];
|
3710
4835
|
date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
|
3711
|
-
|
3712
|
-
|
4836
|
+
var fparts = format.parts.slice();
|
4837
|
+
// Remove noop parts
|
4838
|
+
if (parts.length != fparts.length) {
|
4839
|
+
fparts = $(fparts).filter(function(i,p){
|
4840
|
+
return $.inArray(p, setters_order) !== -1;
|
4841
|
+
}).toArray();
|
4842
|
+
}
|
4843
|
+
// Process remainder
|
4844
|
+
if (parts.length == fparts.length) {
|
4845
|
+
for (var i=0, cnt = fparts.length; i < cnt; i++) {
|
3713
4846
|
val = parseInt(parts[i], 10);
|
3714
|
-
part =
|
4847
|
+
part = fparts[i];
|
3715
4848
|
if (isNaN(val)) {
|
3716
4849
|
switch(part) {
|
3717
4850
|
case 'MM':
|
@@ -3736,8 +4869,8 @@ $(function(){
|
|
3736
4869
|
}
|
3737
4870
|
for (var i=0, s; i<setters_order.length; i++){
|
3738
4871
|
s = setters_order[i];
|
3739
|
-
if (s in parsed)
|
3740
|
-
setters_map[s](date, parsed[s])
|
4872
|
+
if (s in parsed && !isNaN(parsed[s]))
|
4873
|
+
setters_map[s](date, parsed[s]);
|
3741
4874
|
}
|
3742
4875
|
}
|
3743
4876
|
return date;
|
@@ -3745,6 +4878,8 @@ $(function(){
|
|
3745
4878
|
formatDate: function(date, format, language){
|
3746
4879
|
var val = {
|
3747
4880
|
d: date.getUTCDate(),
|
4881
|
+
D: dates[language].daysShort[date.getUTCDay()],
|
4882
|
+
DD: dates[language].days[date.getUTCDay()],
|
3748
4883
|
m: date.getUTCMonth() + 1,
|
3749
4884
|
M: dates[language].monthsShort[date.getUTCMonth()],
|
3750
4885
|
MM: dates[language].months[date.getUTCMonth()],
|
@@ -3757,7 +4892,7 @@ $(function(){
|
|
3757
4892
|
seps = $.extend([], format.separators);
|
3758
4893
|
for (var i=0, cnt = format.parts.length; i < cnt; i++) {
|
3759
4894
|
if (seps.length)
|
3760
|
-
date.push(seps.shift())
|
4895
|
+
date.push(seps.shift());
|
3761
4896
|
date.push(val[format.parts[i]]);
|
3762
4897
|
}
|
3763
4898
|
return date.join('');
|
@@ -3795,7 +4930,7 @@ $(function(){
|
|
3795
4930
|
'</table>'+
|
3796
4931
|
'</div>'+
|
3797
4932
|
'</div>';
|
3798
|
-
|
3799
|
-
|
3800
|
-
|
4933
|
+
|
4934
|
+
$.fn.datepicker.DPGlobal = DPGlobal;
|
4935
|
+
|
3801
4936
|
}( window.jQuery );
|