x-editable-rails 1.0.1 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/x-editable-rails/version.rb +1 -1
- data/vendor/assets/javascripts/editable/bootstrap-editable.js +1142 -713
- data/vendor/assets/javascripts/editable/jquery-editable-poshytip.js +353 -182
- data/vendor/assets/javascripts/editable/jqueryui-editable.js +352 -181
- data/vendor/assets/stylesheets/editable/{bootstrap-editable.css → bootstrap-editable.scss} +164 -8
- data/vendor/assets/stylesheets/editable/{jquery-editable.css → jquery-editable.scss} +11 -3
- data/vendor/assets/stylesheets/editable/{jqueryui-editable.css → jqueryui-editable.scss} +11 -3
- metadata +5 -5
@@ -1,4 +1,4 @@
|
|
1
|
-
/*! X-editable - v1.4.
|
1
|
+
/*! X-editable - v1.4.5
|
2
2
|
* In-place editing with Twitter Bootstrap, jQuery UI or pure jQuery
|
3
3
|
* http://github.com/vitalets/x-editable
|
4
4
|
* Copyright (c) 2013 Vitaliy Potapov; Licensed MIT */
|
@@ -65,6 +65,10 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
|
|
65
65
|
//show loading state
|
66
66
|
this.showLoading();
|
67
67
|
|
68
|
+
//flag showing is form now saving value to server.
|
69
|
+
//It is needed to wait when closing form.
|
70
|
+
this.isSaving = false;
|
71
|
+
|
68
72
|
/**
|
69
73
|
Fired when rendering starts
|
70
74
|
@event rendering
|
@@ -217,31 +221,38 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
|
|
217
221
|
return;
|
218
222
|
}
|
219
223
|
|
224
|
+
//convert value for submitting to server
|
225
|
+
var submitValue = this.input.value2submit(newValue);
|
226
|
+
|
227
|
+
this.isSaving = true;
|
228
|
+
|
220
229
|
//sending data to server
|
221
|
-
$.when(this.save(
|
230
|
+
$.when(this.save(submitValue))
|
222
231
|
.done($.proxy(function(response) {
|
232
|
+
this.isSaving = false;
|
233
|
+
|
223
234
|
//run success callback
|
224
235
|
var res = typeof this.options.success === 'function' ? this.options.success.call(this.options.scope, response, newValue) : null;
|
225
|
-
|
236
|
+
|
226
237
|
//if success callback returns false --> keep form open and do not activate input
|
227
238
|
if(res === false) {
|
228
239
|
this.error(false);
|
229
240
|
this.showForm(false);
|
230
241
|
return;
|
231
|
-
}
|
232
|
-
|
242
|
+
}
|
243
|
+
|
233
244
|
//if success callback returns string --> keep form open, show error and activate input
|
234
245
|
if(typeof res === 'string') {
|
235
246
|
this.error(res);
|
236
247
|
this.showForm();
|
237
248
|
return;
|
238
|
-
}
|
239
|
-
|
249
|
+
}
|
250
|
+
|
240
251
|
//if success callback returns object like {newValue: <something>} --> use that value instead of submitted
|
241
252
|
//it is usefull if you want to chnage value in url-function
|
242
253
|
if(res && typeof res === 'object' && res.hasOwnProperty('newValue')) {
|
243
254
|
newValue = res.newValue;
|
244
|
-
}
|
255
|
+
}
|
245
256
|
|
246
257
|
//clear error message
|
247
258
|
this.error(false);
|
@@ -251,37 +262,42 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
|
|
251
262
|
@event save
|
252
263
|
@param {Object} event event object
|
253
264
|
@param {Object} params additional params
|
254
|
-
@param {mixed} params.newValue
|
265
|
+
@param {mixed} params.newValue raw new value
|
266
|
+
@param {mixed} params.submitValue submitted value as string
|
255
267
|
@param {Object} params.response ajax response
|
256
268
|
|
257
269
|
@example
|
258
270
|
$('#form-div').on('save'), function(e, params){
|
259
271
|
if(params.newValue === 'username') {...}
|
260
|
-
});
|
261
|
-
**/
|
262
|
-
this.$div.triggerHandler('save', {newValue: newValue, response: response});
|
272
|
+
});
|
273
|
+
**/
|
274
|
+
this.$div.triggerHandler('save', {newValue: newValue, submitValue: submitValue, response: response});
|
263
275
|
}, this))
|
264
276
|
.fail($.proxy(function(xhr) {
|
277
|
+
this.isSaving = false;
|
278
|
+
|
265
279
|
var msg;
|
266
280
|
if(typeof this.options.error === 'function') {
|
267
281
|
msg = this.options.error.call(this.options.scope, xhr, newValue);
|
268
282
|
} else {
|
269
283
|
msg = typeof xhr === 'string' ? xhr : xhr.responseText || xhr.statusText || 'Unknown error!';
|
270
284
|
}
|
271
|
-
|
285
|
+
|
272
286
|
this.error(msg);
|
273
287
|
this.showForm();
|
274
288
|
}, this));
|
275
289
|
},
|
276
290
|
|
277
|
-
save: function(
|
278
|
-
//convert value for submitting to server
|
279
|
-
var submitValue = this.input.value2submit(newValue);
|
280
|
-
|
291
|
+
save: function(submitValue) {
|
281
292
|
//try parse composite pk defined as json string in data-pk
|
282
293
|
this.options.pk = $.fn.editableutils.tryParseJson(this.options.pk, true);
|
283
294
|
|
284
295
|
var pk = (typeof this.options.pk === 'function') ? this.options.pk.call(this.options.scope) : this.options.pk,
|
296
|
+
/*
|
297
|
+
send on server in following cases:
|
298
|
+
1. url is function
|
299
|
+
2. url is string AND (pk defined OR send option = always)
|
300
|
+
*/
|
285
301
|
send = !!(typeof this.options.url === 'function' || (this.options.url && ((this.options.send === 'always') || (this.options.send === 'auto' && pk !== null && pk !== undefined)))),
|
286
302
|
params;
|
287
303
|
|
@@ -816,6 +832,27 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
|
|
816
832
|
$.error('Unknown type: '+ type);
|
817
833
|
return false;
|
818
834
|
}
|
835
|
+
},
|
836
|
+
|
837
|
+
//see http://stackoverflow.com/questions/7264899/detect-css-transitions-using-javascript-and-without-modernizr
|
838
|
+
supportsTransitions: function () {
|
839
|
+
var b = document.body || document.documentElement,
|
840
|
+
s = b.style,
|
841
|
+
p = 'transition',
|
842
|
+
v = ['Moz', 'Webkit', 'Khtml', 'O', 'ms'];
|
843
|
+
|
844
|
+
if(typeof s[p] === 'string') {
|
845
|
+
return true;
|
846
|
+
}
|
847
|
+
|
848
|
+
// Tests for vendor specific prop
|
849
|
+
p = p.charAt(0).toUpperCase() + p.substr(1);
|
850
|
+
for(var i=0; i<v.length; i++) {
|
851
|
+
if(typeof s[v[i] + p] === 'string') {
|
852
|
+
return true;
|
853
|
+
}
|
854
|
+
}
|
855
|
+
return false;
|
819
856
|
}
|
820
857
|
|
821
858
|
};
|
@@ -856,6 +893,9 @@ Applied as jQuery method.
|
|
856
893
|
this.formOptions.scope = this.$element[0];
|
857
894
|
|
858
895
|
this.initContainer();
|
896
|
+
|
897
|
+
//flag to hide container, when saving value will finish
|
898
|
+
this.delayedHide = false;
|
859
899
|
|
860
900
|
//bind 'destroyed' listener to destroy container when element is removed from dom
|
861
901
|
this.$element.on('destroyed', $.proxy(function(){
|
@@ -960,7 +1000,14 @@ Applied as jQuery method.
|
|
960
1000
|
save: $.proxy(this.save, this), //click on submit button (value changed)
|
961
1001
|
nochange: $.proxy(function(){ this.hide('nochange'); }, this), //click on submit button (value NOT changed)
|
962
1002
|
cancel: $.proxy(function(){ this.hide('cancel'); }, this), //click on calcel button
|
963
|
-
show: $.proxy(
|
1003
|
+
show: $.proxy(function() {
|
1004
|
+
if(this.delayedHide) {
|
1005
|
+
this.hide(this.delayedHide.reason);
|
1006
|
+
this.delayedHide = false;
|
1007
|
+
} else {
|
1008
|
+
this.setPosition();
|
1009
|
+
}
|
1010
|
+
}, this), //re-position container every time form is shown (occurs each time after loading state)
|
964
1011
|
rendering: $.proxy(this.setPosition, this), //this allows to place container correctly when loading shown
|
965
1012
|
resize: $.proxy(this.setPosition, this), //this allows to re-position container when form size is changed
|
966
1013
|
rendered: $.proxy(function(){
|
@@ -1004,11 +1051,11 @@ Applied as jQuery method.
|
|
1004
1051
|
|
1005
1052
|
/*
|
1006
1053
|
Currently, form is re-rendered on every show.
|
1007
|
-
The main reason is that we dont know, what container
|
1008
|
-
remove(), detach() or just hide().
|
1054
|
+
The main reason is that we dont know, what will container do with content when closed:
|
1055
|
+
remove(), detach() or just hide() - it depends on container.
|
1009
1056
|
|
1010
1057
|
Detaching form itself before hide and re-insert before show is good solution,
|
1011
|
-
but visually it looks ugly
|
1058
|
+
but visually it looks ugly --> container changes size before hide.
|
1012
1059
|
*/
|
1013
1060
|
|
1014
1061
|
//if form already exist - delete previous data
|
@@ -1041,10 +1088,18 @@ Applied as jQuery method.
|
|
1041
1088
|
return;
|
1042
1089
|
}
|
1043
1090
|
|
1091
|
+
//if form is saving value, schedule hide
|
1092
|
+
if(this.$form.data('editableform').isSaving) {
|
1093
|
+
this.delayedHide = {reason: reason};
|
1094
|
+
return;
|
1095
|
+
} else {
|
1096
|
+
this.delayedHide = false;
|
1097
|
+
}
|
1098
|
+
|
1044
1099
|
this.$element.removeClass('editable-open');
|
1045
1100
|
this.innerHide();
|
1046
|
-
|
1047
|
-
/**
|
1101
|
+
|
1102
|
+
/**
|
1048
1103
|
Fired when container was hidden. It occurs on both save or cancel.
|
1049
1104
|
**Note:** Bootstrap popover has own `hidden` event that now cannot be separated from x-editable's one.
|
1050
1105
|
The workaround is to check `arguments.length` that is always `2` for x-editable.
|
@@ -1058,20 +1113,20 @@ Applied as jQuery method.
|
|
1058
1113
|
//auto-open next editable
|
1059
1114
|
$(this).closest('tr').next().find('.editable').editable('show');
|
1060
1115
|
}
|
1061
|
-
});
|
1062
|
-
**/
|
1116
|
+
});
|
1117
|
+
**/
|
1063
1118
|
this.$element.triggerHandler('hidden', reason || 'manual');
|
1064
1119
|
},
|
1065
|
-
|
1120
|
+
|
1066
1121
|
/* internal show method. To be overwritten in child classes */
|
1067
1122
|
innerShow: function () {
|
1068
1123
|
|
1069
1124
|
},
|
1070
|
-
|
1125
|
+
|
1071
1126
|
/* internal hide method. To be overwritten in child classes */
|
1072
1127
|
innerHide: function () {
|
1073
|
-
|
1074
|
-
},
|
1128
|
+
|
1129
|
+
},
|
1075
1130
|
|
1076
1131
|
/**
|
1077
1132
|
Toggles container visibility (show / hide)
|
@@ -1116,7 +1171,7 @@ Applied as jQuery method.
|
|
1116
1171
|
**/
|
1117
1172
|
this.$element.triggerHandler('save', params);
|
1118
1173
|
|
1119
|
-
//hide must be after trigger, as saving value may require methods
|
1174
|
+
//hide must be after trigger, as saving value may require methods of plugin, applied to input
|
1120
1175
|
this.hide('save');
|
1121
1176
|
},
|
1122
1177
|
|
@@ -1276,7 +1331,7 @@ Applied as jQuery method.
|
|
1276
1331
|
onblur: 'cancel',
|
1277
1332
|
|
1278
1333
|
/**
|
1279
|
-
Animation speed (inline mode)
|
1334
|
+
Animation speed (inline mode only)
|
1280
1335
|
@property anim
|
1281
1336
|
@type string
|
1282
1337
|
@default false
|
@@ -1380,6 +1435,11 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1380
1435
|
} else {
|
1381
1436
|
this.init();
|
1382
1437
|
}
|
1438
|
+
|
1439
|
+
//check for transition support
|
1440
|
+
if(this.options.highlight && !$.fn.editableutils.supportsTransitions()) {
|
1441
|
+
this.options.highlight = false;
|
1442
|
+
}
|
1383
1443
|
};
|
1384
1444
|
|
1385
1445
|
Editable.prototype = {
|
@@ -1424,25 +1484,33 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1424
1484
|
if(this.options.toggle !== 'manual') {
|
1425
1485
|
this.$element.addClass('editable-click');
|
1426
1486
|
this.$element.on(this.options.toggle + '.editable', $.proxy(function(e){
|
1427
|
-
//prevent following link
|
1428
|
-
|
1487
|
+
//prevent following link if editable enabled
|
1488
|
+
if(!this.options.disabled) {
|
1489
|
+
e.preventDefault();
|
1490
|
+
}
|
1429
1491
|
|
1430
1492
|
//stop propagation not required because in document click handler it checks event target
|
1431
1493
|
//e.stopPropagation();
|
1432
1494
|
|
1433
1495
|
if(this.options.toggle === 'mouseenter') {
|
1434
1496
|
//for hover only show container
|
1435
|
-
this.show();
|
1497
|
+
this.show();
|
1436
1498
|
} else {
|
1437
1499
|
//when toggle='click' we should not close all other containers as they will be closed automatically in document click listener
|
1438
1500
|
var closeAll = (this.options.toggle !== 'click');
|
1439
1501
|
this.toggle(closeAll);
|
1440
|
-
}
|
1502
|
+
}
|
1441
1503
|
}, this));
|
1442
1504
|
} else {
|
1443
1505
|
this.$element.attr('tabindex', -1); //do not stop focus on element when toggled manually
|
1444
1506
|
}
|
1445
1507
|
|
1508
|
+
//if display is function it's far more convinient to have autotext = always to render correctly on init
|
1509
|
+
//see https://github.com/vitalets/x-editable-yii/issues/34
|
1510
|
+
if(typeof this.options.display === 'function') {
|
1511
|
+
this.options.autotext = 'always';
|
1512
|
+
}
|
1513
|
+
|
1446
1514
|
//check conditions for autotext:
|
1447
1515
|
switch(this.options.autotext) {
|
1448
1516
|
case 'always':
|
@@ -1621,12 +1689,29 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1621
1689
|
return;
|
1622
1690
|
}
|
1623
1691
|
|
1624
|
-
|
1692
|
+
/*
|
1693
|
+
isEmpty may be set directly as param of method.
|
1694
|
+
It is required when we enable/disable field and can't rely on content
|
1695
|
+
as node content is text: "Empty" that is not empty %)
|
1696
|
+
*/
|
1697
|
+
if(isEmpty !== undefined) {
|
1698
|
+
this.isEmpty = isEmpty;
|
1699
|
+
} else {
|
1700
|
+
//detect empty
|
1701
|
+
if($.trim(this.$element.html()) === '') {
|
1702
|
+
this.isEmpty = true;
|
1703
|
+
} else if($.trim(this.$element.text()) !== '') {
|
1704
|
+
this.isEmpty = false;
|
1705
|
+
} else {
|
1706
|
+
//e.g. '<img>'
|
1707
|
+
this.isEmpty = !this.$element.height() || !this.$element.width();
|
1708
|
+
}
|
1709
|
+
}
|
1625
1710
|
|
1626
1711
|
//emptytext shown only for enabled
|
1627
1712
|
if(!this.options.disabled) {
|
1628
1713
|
if (this.isEmpty) {
|
1629
|
-
this.$element.
|
1714
|
+
this.$element.html(this.options.emptytext);
|
1630
1715
|
if(this.options.emptyclass) {
|
1631
1716
|
this.$element.addClass(this.options.emptyclass);
|
1632
1717
|
}
|
@@ -1721,6 +1806,21 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1721
1806
|
}
|
1722
1807
|
}
|
1723
1808
|
|
1809
|
+
//highlight when saving
|
1810
|
+
if(this.options.highlight) {
|
1811
|
+
var $e = this.$element,
|
1812
|
+
$bgColor = $e.css('background-color');
|
1813
|
+
|
1814
|
+
$e.css('background-color', this.options.highlight);
|
1815
|
+
setTimeout(function(){
|
1816
|
+
$e.css('background-color', $bgColor);
|
1817
|
+
$e.addClass('editable-bg-transition');
|
1818
|
+
setTimeout(function(){
|
1819
|
+
$e.removeClass('editable-bg-transition');
|
1820
|
+
}, 1700);
|
1821
|
+
}, 0);
|
1822
|
+
}
|
1823
|
+
|
1724
1824
|
//set new value
|
1725
1825
|
this.setValue(params.newValue, false, params.response);
|
1726
1826
|
|
@@ -1787,6 +1887,8 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1787
1887
|
if(this.container) {
|
1788
1888
|
this.container.destroy();
|
1789
1889
|
}
|
1890
|
+
|
1891
|
+
this.input.destroy();
|
1790
1892
|
|
1791
1893
|
if(this.options.toggle !== 'manual') {
|
1792
1894
|
this.$element.removeClass('editable-click');
|
@@ -1844,28 +1946,37 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
1844
1946
|
/**
|
1845
1947
|
Returns current values of editable elements.
|
1846
1948
|
Note that it returns an **object** with name-value pairs, not a value itself. It allows to get data from several elements.
|
1847
|
-
If value of some editable is `null` or `undefined` it is excluded from result object.
|
1949
|
+
If value of some editable is `null` or `undefined` it is excluded from result object.
|
1950
|
+
When param `isSingle` is set to **true** - it is supposed you have single element and will return value of editable instead of object.
|
1848
1951
|
|
1849
1952
|
@method getValue()
|
1953
|
+
@param {bool} isSingle whether to return just value of single element
|
1850
1954
|
@returns {Object} object of element names and values
|
1851
1955
|
@example
|
1852
1956
|
$('#username, #fullname').editable('getValue');
|
1853
|
-
//
|
1957
|
+
//result:
|
1854
1958
|
{
|
1855
1959
|
username: "superuser",
|
1856
1960
|
fullname: "John"
|
1857
1961
|
}
|
1962
|
+
//isSingle = true
|
1963
|
+
$('#username').editable('getValue', true);
|
1964
|
+
//result "superuser"
|
1858
1965
|
**/
|
1859
1966
|
case 'getValue':
|
1860
|
-
|
1861
|
-
|
1862
|
-
|
1863
|
-
|
1864
|
-
|
1865
|
-
|
1967
|
+
if(arguments.length === 2 && arguments[1] === true) { //isSingle = true
|
1968
|
+
result = this.eq(0).data(datakey).value;
|
1969
|
+
} else {
|
1970
|
+
this.each(function () {
|
1971
|
+
var $this = $(this), data = $this.data(datakey);
|
1972
|
+
if (data && data.value !== undefined && data.value !== null) {
|
1973
|
+
result[data.options.name] = data.input.value2submit(data.value);
|
1974
|
+
}
|
1975
|
+
});
|
1976
|
+
}
|
1866
1977
|
return result;
|
1867
1978
|
|
1868
|
-
/**
|
1979
|
+
/**
|
1869
1980
|
This method collects values from several editable elements and submit them all to server.
|
1870
1981
|
Internally it runs client-side validation for all fields and submits only in case of success.
|
1871
1982
|
See <a href="#newrecord">creating new records</a> for details.
|
@@ -2089,7 +2200,16 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|
2089
2200
|
});
|
2090
2201
|
</script>
|
2091
2202
|
**/
|
2092
|
-
selector: null
|
2203
|
+
selector: null,
|
2204
|
+
/**
|
2205
|
+
Color used to highlight element after update. Implemented via CSS3 transition, works in modern browsers.
|
2206
|
+
|
2207
|
+
@property highlight
|
2208
|
+
@type string|boolean
|
2209
|
+
@since 1.4.5
|
2210
|
+
@default #FFFF80
|
2211
|
+
**/
|
2212
|
+
highlight: '#FFFF80'
|
2093
2213
|
};
|
2094
2214
|
|
2095
2215
|
}(window.jQuery));
|
@@ -2103,23 +2223,23 @@ To create your own input you can inherit from this class.
|
|
2103
2223
|
**/
|
2104
2224
|
(function ($) {
|
2105
2225
|
"use strict";
|
2106
|
-
|
2226
|
+
|
2107
2227
|
//types
|
2108
2228
|
$.fn.editabletypes = {};
|
2109
|
-
|
2229
|
+
|
2110
2230
|
var AbstractInput = function () { };
|
2111
2231
|
|
2112
2232
|
AbstractInput.prototype = {
|
2113
2233
|
/**
|
2114
2234
|
Initializes input
|
2115
|
-
|
2235
|
+
|
2116
2236
|
@method init()
|
2117
2237
|
**/
|
2118
2238
|
init: function(type, options, defaults) {
|
2119
2239
|
this.type = type;
|
2120
2240
|
this.options = $.extend({}, defaults, options);
|
2121
2241
|
},
|
2122
|
-
|
2242
|
+
|
2123
2243
|
/*
|
2124
2244
|
this method called before render to init $tpl that is inserted in DOM
|
2125
2245
|
*/
|
@@ -2133,107 +2253,107 @@ To create your own input you can inherit from this class.
|
|
2133
2253
|
/**
|
2134
2254
|
Renders input from tpl. Can return jQuery deferred object.
|
2135
2255
|
Can be overwritten in child objects
|
2136
|
-
|
2137
|
-
@method render()
|
2138
|
-
**/
|
2256
|
+
|
2257
|
+
@method render()
|
2258
|
+
**/
|
2139
2259
|
render: function() {
|
2140
2260
|
|
2141
2261
|
},
|
2142
2262
|
|
2143
2263
|
/**
|
2144
2264
|
Sets element's html by value.
|
2145
|
-
|
2146
|
-
@method value2html(value, element)
|
2265
|
+
|
2266
|
+
@method value2html(value, element)
|
2147
2267
|
@param {mixed} value
|
2148
2268
|
@param {DOMElement} element
|
2149
|
-
**/
|
2269
|
+
**/
|
2150
2270
|
value2html: function(value, element) {
|
2151
|
-
$(element).text(value);
|
2271
|
+
$(element).text($.trim(value));
|
2152
2272
|
},
|
2153
|
-
|
2273
|
+
|
2154
2274
|
/**
|
2155
2275
|
Converts element's html to value
|
2156
|
-
|
2157
|
-
@method html2value(html)
|
2276
|
+
|
2277
|
+
@method html2value(html)
|
2158
2278
|
@param {string} html
|
2159
2279
|
@returns {mixed}
|
2160
|
-
**/
|
2280
|
+
**/
|
2161
2281
|
html2value: function(html) {
|
2162
2282
|
return $('<div>').html(html).text();
|
2163
2283
|
},
|
2164
|
-
|
2284
|
+
|
2165
2285
|
/**
|
2166
2286
|
Converts value to string (for internal compare). For submitting to server used value2submit().
|
2167
|
-
|
2287
|
+
|
2168
2288
|
@method value2str(value)
|
2169
2289
|
@param {mixed} value
|
2170
2290
|
@returns {string}
|
2171
|
-
**/
|
2291
|
+
**/
|
2172
2292
|
value2str: function(value) {
|
2173
2293
|
return value;
|
2174
2294
|
},
|
2175
|
-
|
2295
|
+
|
2176
2296
|
/**
|
2177
2297
|
Converts string received from server into value. Usually from `data-value` attribute.
|
2178
|
-
|
2179
|
-
@method str2value(str)
|
2298
|
+
|
2299
|
+
@method str2value(str)
|
2180
2300
|
@param {string} str
|
2181
2301
|
@returns {mixed}
|
2182
|
-
**/
|
2302
|
+
**/
|
2183
2303
|
str2value: function(str) {
|
2184
2304
|
return str;
|
2185
2305
|
},
|
2186
2306
|
|
2187
2307
|
/**
|
2188
2308
|
Converts value for submitting to server. Result can be string or object.
|
2189
|
-
|
2309
|
+
|
2190
2310
|
@method value2submit(value)
|
2191
2311
|
@param {mixed} value
|
2192
2312
|
@returns {mixed}
|
2193
|
-
**/
|
2313
|
+
**/
|
2194
2314
|
value2submit: function(value) {
|
2195
2315
|
return value;
|
2196
|
-
},
|
2197
|
-
|
2316
|
+
},
|
2317
|
+
|
2198
2318
|
/**
|
2199
2319
|
Sets value of input.
|
2200
|
-
|
2320
|
+
|
2201
2321
|
@method value2input(value)
|
2202
2322
|
@param {mixed} value
|
2203
|
-
**/
|
2323
|
+
**/
|
2204
2324
|
value2input: function(value) {
|
2205
2325
|
this.$input.val(value);
|
2206
2326
|
},
|
2207
|
-
|
2327
|
+
|
2208
2328
|
/**
|
2209
2329
|
Returns value of input. Value can be object (e.g. datepicker)
|
2210
|
-
|
2330
|
+
|
2211
2331
|
@method input2value()
|
2212
|
-
**/
|
2332
|
+
**/
|
2213
2333
|
input2value: function() {
|
2214
2334
|
return this.$input.val();
|
2215
2335
|
},
|
2216
2336
|
|
2217
2337
|
/**
|
2218
2338
|
Activates input. For text it sets focus.
|
2219
|
-
|
2339
|
+
|
2220
2340
|
@method activate()
|
2221
|
-
**/
|
2341
|
+
**/
|
2222
2342
|
activate: function() {
|
2223
2343
|
if(this.$input.is(':visible')) {
|
2224
2344
|
this.$input.focus();
|
2225
2345
|
}
|
2226
2346
|
},
|
2227
|
-
|
2347
|
+
|
2228
2348
|
/**
|
2229
2349
|
Creates input.
|
2230
|
-
|
2350
|
+
|
2231
2351
|
@method clear()
|
2232
2352
|
**/
|
2233
2353
|
clear: function() {
|
2234
2354
|
this.$input.val(null);
|
2235
2355
|
},
|
2236
|
-
|
2356
|
+
|
2237
2357
|
/**
|
2238
2358
|
method to escape html.
|
2239
2359
|
**/
|
@@ -2243,18 +2363,24 @@ To create your own input you can inherit from this class.
|
|
2243
2363
|
|
2244
2364
|
/**
|
2245
2365
|
attach handler to automatically submit form when value changed (useful when buttons not shown)
|
2246
|
-
**/
|
2366
|
+
**/
|
2247
2367
|
autosubmit: function() {
|
2248
2368
|
|
2249
2369
|
},
|
2250
2370
|
|
2371
|
+
/**
|
2372
|
+
Additional actions when destroying element
|
2373
|
+
**/
|
2374
|
+
destroy: function() {
|
2375
|
+
},
|
2376
|
+
|
2251
2377
|
// -------- helper functions --------
|
2252
2378
|
setClass: function() {
|
2253
2379
|
if(this.options.inputclass) {
|
2254
2380
|
this.$input.addClass(this.options.inputclass);
|
2255
2381
|
}
|
2256
2382
|
},
|
2257
|
-
|
2383
|
+
|
2258
2384
|
setAttr: function(attr) {
|
2259
2385
|
if (this.options[attr] !== undefined && this.options[attr] !== null) {
|
2260
2386
|
this.$input.attr(attr, this.options[attr]);
|
@@ -2356,30 +2482,33 @@ List - abstract class for inputs that have source option loaded from js array or
|
|
2356
2482
|
// ------------- additional functions ------------
|
2357
2483
|
|
2358
2484
|
onSourceReady: function (success, error) {
|
2485
|
+
//run source if it function
|
2486
|
+
var source;
|
2487
|
+
if ($.isFunction(this.options.source)) {
|
2488
|
+
source = this.options.source.call(this.options.scope);
|
2489
|
+
this.sourceData = null;
|
2490
|
+
//note: if function returns the same source as URL - sourceData will be taken from cahce and no extra request performed
|
2491
|
+
} else {
|
2492
|
+
source = this.options.source;
|
2493
|
+
}
|
2494
|
+
|
2359
2495
|
//if allready loaded just call success
|
2360
|
-
if($.isArray(this.sourceData)) {
|
2496
|
+
if(this.options.sourceCache && $.isArray(this.sourceData)) {
|
2361
2497
|
success.call(this);
|
2362
2498
|
return;
|
2363
2499
|
}
|
2364
2500
|
|
2365
|
-
//
|
2501
|
+
//try parse json in single quotes (for double quotes jquery does automatically)
|
2366
2502
|
try {
|
2367
|
-
|
2503
|
+
source = $.fn.editableutils.tryParseJson(source, false);
|
2368
2504
|
} catch (e) {
|
2369
2505
|
error.call(this);
|
2370
2506
|
return;
|
2371
2507
|
}
|
2372
|
-
|
2373
|
-
var source = this.options.source;
|
2374
|
-
|
2375
|
-
//run source if it function
|
2376
|
-
if ($.isFunction(source)) {
|
2377
|
-
source = source.call(this.options.scope);
|
2378
|
-
}
|
2379
2508
|
|
2380
2509
|
//loading from url
|
2381
2510
|
if (typeof source === 'string') {
|
2382
|
-
//try to get from cache
|
2511
|
+
//try to get sourceData from cache
|
2383
2512
|
if(this.options.sourceCache) {
|
2384
2513
|
var cacheID = source,
|
2385
2514
|
cache;
|
@@ -3299,25 +3428,29 @@ Range (inherit from number)
|
|
3299
3428
|
}(window.jQuery));
|
3300
3429
|
/**
|
3301
3430
|
Select2 input. Based on amazing work of Igor Vaynberg https://github.com/ivaynberg/select2.
|
3302
|
-
Please see [original docs](http://ivaynberg.github.com/select2) for detailed description and options.
|
3303
|
-
|
3431
|
+
Please see [original select2 docs](http://ivaynberg.github.com/select2) for detailed description and options.
|
3432
|
+
Compatible **select2 version is 3.4.1**!
|
3433
|
+
You should manually download and include select2 distributive:
|
3304
3434
|
|
3305
3435
|
<link href="select2/select2.css" rel="stylesheet" type="text/css"></link>
|
3306
3436
|
<script src="select2/select2.js"></script>
|
3307
3437
|
|
3308
|
-
|
3438
|
+
To make it **bootstrap-styled** you can use css from [here](https://github.com/t0m/select2-bootstrap-css):
|
3309
3439
|
|
3310
3440
|
<link href="select2-bootstrap.css" rel="stylesheet" type="text/css"></link>
|
3311
3441
|
|
3312
|
-
**Note:** currently `
|
3313
|
-
|
3442
|
+
**Note:** currently `autotext` feature does not work for select2 with `ajax` remote source.
|
3443
|
+
You need initially put both `data-value` and element's text youself:
|
3444
|
+
|
3445
|
+
<a href="#" data-type="select2" data-value="1">Text1</a>
|
3446
|
+
|
3314
3447
|
|
3315
3448
|
@class select2
|
3316
3449
|
@extends abstractinput
|
3317
3450
|
@since 1.4.1
|
3318
3451
|
@final
|
3319
3452
|
@example
|
3320
|
-
<a href="#" id="country" data-type="select2" data-pk="1" data-value="ru" data-url="/post" data-
|
3453
|
+
<a href="#" id="country" data-type="select2" data-pk="1" data-value="ru" data-url="/post" data-title="Select country"></a>
|
3321
3454
|
<script>
|
3322
3455
|
$(function(){
|
3323
3456
|
$('#country').editable({
|
@@ -3338,56 +3471,47 @@ $(function(){
|
|
3338
3471
|
|
3339
3472
|
var Constructor = function (options) {
|
3340
3473
|
this.init('select2', options, Constructor.defaults);
|
3341
|
-
|
3474
|
+
|
3342
3475
|
options.select2 = options.select2 || {};
|
3476
|
+
|
3477
|
+
this.sourceData = null;
|
3343
3478
|
|
3344
|
-
|
3345
|
-
|
3346
|
-
|
3347
|
-
|
3348
|
-
|
3349
|
-
//detect whether it is multi-valued
|
3350
|
-
this.isMultiple = options.select2.tags || options.select2.multiple;
|
3479
|
+
//placeholder
|
3480
|
+
if(options.placeholder) {
|
3481
|
+
options.select2.placeholder = options.placeholder;
|
3482
|
+
}
|
3351
3483
|
|
3352
|
-
|
3353
|
-
|
3354
|
-
|
3355
|
-
|
3356
|
-
|
3484
|
+
//if not `tags` mode, use source
|
3485
|
+
if(!options.select2.tags && options.source) {
|
3486
|
+
var source = options.source;
|
3487
|
+
//if source is function, call it (once!)
|
3488
|
+
if ($.isFunction(options.source)) {
|
3489
|
+
source = options.source.call(options.scope);
|
3490
|
+
}
|
3357
3491
|
|
3358
|
-
|
3359
|
-
|
3360
|
-
//
|
3361
|
-
|
3362
|
-
|
3363
|
-
console.log('attached');
|
3364
|
-
var original = $(element).data('select2').postprocessResults;
|
3365
|
-
console.log(original);
|
3366
|
-
$(element).data('select2').postprocessResults = function(data, initial) {
|
3367
|
-
console.log('postprocess');
|
3368
|
-
// this.element.triggerHandler('loaded', [data]);
|
3369
|
-
original.apply(this, arguments);
|
3370
|
-
}
|
3371
|
-
|
3372
|
-
// $(element).on('loaded', function(){console.log('loaded');});
|
3373
|
-
$(element).data('select2').updateResults(true);
|
3492
|
+
if (typeof source === 'string') {
|
3493
|
+
options.select2.ajax = options.select2.ajax || {};
|
3494
|
+
//some default ajax params
|
3495
|
+
if(!options.select2.ajax.data) {
|
3496
|
+
options.select2.ajax.data = function(term) {return { query:term };};
|
3374
3497
|
}
|
3375
|
-
|
3376
|
-
|
3377
|
-
var val = that.str2value(element.val()),
|
3378
|
-
data = $.fn.editableutils.itemsByValue(val, mixin.data, 'id');
|
3379
|
-
|
3380
|
-
//for single-valued mode should not use array. Take first element instead.
|
3381
|
-
if($.isArray(data) && data.length && !that.isMultiple) {
|
3382
|
-
data = data[0];
|
3498
|
+
if(!options.select2.ajax.results) {
|
3499
|
+
options.select2.ajax.results = function(data) { return {results:data };};
|
3383
3500
|
}
|
3384
|
-
|
3385
|
-
|
3386
|
-
|
3387
|
-
|
3501
|
+
options.select2.ajax.url = source;
|
3502
|
+
} else {
|
3503
|
+
//check format and convert x-editable format to select2 format (if needed)
|
3504
|
+
this.sourceData = this.convertSource(source);
|
3505
|
+
options.select2.data = this.sourceData;
|
3506
|
+
}
|
3507
|
+
}
|
3388
3508
|
|
3389
3509
|
//overriding objects in config (as by default jQuery extend() is not recursive)
|
3390
|
-
this.options.select2 = $.extend({}, Constructor.defaults.select2,
|
3510
|
+
this.options.select2 = $.extend({}, Constructor.defaults.select2, options.select2);
|
3511
|
+
|
3512
|
+
//detect whether it is multi-valued
|
3513
|
+
this.isMultiple = this.options.select2.tags || this.options.select2.multiple;
|
3514
|
+
this.isRemote = ('ajax' in this.options.select2);
|
3391
3515
|
};
|
3392
3516
|
|
3393
3517
|
$.fn.editableutils.inherit(Constructor, $.fn.editabletypes.abstractinput);
|
@@ -3395,21 +3519,17 @@ $(function(){
|
|
3395
3519
|
$.extend(Constructor.prototype, {
|
3396
3520
|
render: function() {
|
3397
3521
|
this.setClass();
|
3522
|
+
|
3398
3523
|
//apply select2
|
3399
3524
|
this.$input.select2(this.options.select2);
|
3400
3525
|
|
3401
|
-
//when data is loaded via ajax, we need to know when it's done
|
3402
|
-
if(
|
3403
|
-
|
3404
|
-
|
3405
|
-
|
3406
|
-
|
3407
|
-
this.element.triggerHandler('loaded', [data]);
|
3408
|
-
original.apply(this, arguments);
|
3409
|
-
}
|
3410
|
-
*/
|
3526
|
+
//when data is loaded via ajax, we need to know when it's done to populate listData
|
3527
|
+
if(this.isRemote) {
|
3528
|
+
//listen to loaded event to populate data
|
3529
|
+
this.$input.on('select2-loaded', $.proxy(function(e) {
|
3530
|
+
this.sourceData = e.items.results;
|
3531
|
+
}, this));
|
3411
3532
|
}
|
3412
|
-
|
3413
3533
|
|
3414
3534
|
//trigger resize of editableform to re-position container in multi-valued mode
|
3415
3535
|
if(this.isMultiple) {
|
@@ -3421,20 +3541,16 @@ $(function(){
|
|
3421
3541
|
|
3422
3542
|
value2html: function(value, element) {
|
3423
3543
|
var text = '', data;
|
3424
|
-
|
3425
|
-
|
3426
|
-
|
3427
|
-
|
3428
|
-
|
3429
|
-
|
3430
|
-
|
3431
|
-
} else if(this.options.select2.data) {
|
3432
|
-
data = $.fn.editableutils.itemsByValue(value, this.options.select2.data, 'id');
|
3433
|
-
} else {
|
3434
|
-
//if('ajax' in this.options.select2) {
|
3435
|
-
}
|
3544
|
+
|
3545
|
+
if(this.options.select2.tags) { //in tags mode just assign value
|
3546
|
+
data = value;
|
3547
|
+
} else if(this.sourceData) {
|
3548
|
+
data = $.fn.editableutils.itemsByValue(value, this.sourceData, 'id');
|
3549
|
+
} else {
|
3550
|
+
//can not get list of possible values (e.g. autotext for select2 with ajax source)
|
3436
3551
|
}
|
3437
3552
|
|
3553
|
+
//data may be array (when multiple values allowed)
|
3438
3554
|
if($.isArray(data)) {
|
3439
3555
|
//collect selected data and show with separator
|
3440
3556
|
text = [];
|
@@ -3455,7 +3571,26 @@ $(function(){
|
|
3455
3571
|
},
|
3456
3572
|
|
3457
3573
|
value2input: function(value) {
|
3458
|
-
|
3574
|
+
//for remote source .val() is not working, need to look in sourceData
|
3575
|
+
if(this.isRemote) {
|
3576
|
+
//todo: check value for array
|
3577
|
+
var item, items;
|
3578
|
+
//if sourceData loaded, use it to get text for display
|
3579
|
+
if(this.sourceData) {
|
3580
|
+
items = $.fn.editableutils.itemsByValue(value, this.sourceData, 'id');
|
3581
|
+
if(items.length) {
|
3582
|
+
item = items[0];
|
3583
|
+
}
|
3584
|
+
}
|
3585
|
+
//if item not found by sourceData, use element text (e.g. for the first show)
|
3586
|
+
if(!item) {
|
3587
|
+
item = {id: value, text: $(this.options.scope).text()};
|
3588
|
+
}
|
3589
|
+
//select2('data', ...) allows to set both id and text --> usefull for initial show when items are not loaded
|
3590
|
+
this.$input.select2('data', item).trigger('change', true); //second argument needed to separate initial change from user's click (for autosubmit)
|
3591
|
+
} else {
|
3592
|
+
this.$input.val(value).trigger('change', true); //second argument needed to separate initial change from user's click (for autosubmit)
|
3593
|
+
}
|
3459
3594
|
},
|
3460
3595
|
|
3461
3596
|
input2value: function() {
|
@@ -3488,6 +3623,22 @@ $(function(){
|
|
3488
3623
|
$(this).closest('form').submit();
|
3489
3624
|
}
|
3490
3625
|
});
|
3626
|
+
},
|
3627
|
+
|
3628
|
+
/*
|
3629
|
+
Converts source from x-editable format: {value: 1, text: "1"} to
|
3630
|
+
select2 format: {id: 1, text: "1"}
|
3631
|
+
*/
|
3632
|
+
convertSource: function(source) {
|
3633
|
+
if($.isArray(source) && source.length && source[0].value !== undefined) {
|
3634
|
+
for(var i = 0; i<source.length; i++) {
|
3635
|
+
if(source[i].value !== undefined) {
|
3636
|
+
source[i].id = source[i].value;
|
3637
|
+
delete source[i].value;
|
3638
|
+
}
|
3639
|
+
}
|
3640
|
+
}
|
3641
|
+
return source;
|
3491
3642
|
}
|
3492
3643
|
|
3493
3644
|
});
|
@@ -3539,12 +3690,22 @@ $(function(){
|
|
3539
3690
|
}(window.jQuery));
|
3540
3691
|
|
3541
3692
|
/**
|
3542
|
-
* Combodate - 1.0.
|
3693
|
+
* Combodate - 1.0.4
|
3543
3694
|
* Dropdown date and time picker.
|
3544
3695
|
* Converts text input into dropdowns to pick day, month, year, hour, minute and second.
|
3545
3696
|
* Uses momentjs as datetime library http://momentjs.com.
|
3546
3697
|
* For i18n include corresponding file from https://github.com/timrwood/moment/tree/master/lang
|
3547
3698
|
*
|
3699
|
+
* Confusion at noon and midnight - see http://en.wikipedia.org/wiki/12-hour_clock#Confusion_at_noon_and_midnight
|
3700
|
+
* In combodate:
|
3701
|
+
* 12:00 pm --> 12:00 (24-h format, midday)
|
3702
|
+
* 12:00 am --> 00:00 (24-h format, midnight, start of day)
|
3703
|
+
*
|
3704
|
+
* Differs from momentjs parse rules:
|
3705
|
+
* 00:00 pm, 12:00 pm --> 12:00 (24-h format, day not change)
|
3706
|
+
* 00:00 am, 12:00 am --> 00:00 (24-h format, day not change)
|
3707
|
+
*
|
3708
|
+
*
|
3548
3709
|
* Author: Vitaliy Potapov
|
3549
3710
|
* Project page: http://github.com/vitalets/combodate
|
3550
3711
|
* Copyright (c) 2012 Vitaliy Potapov. Released under MIT License.
|
@@ -3694,9 +3855,10 @@ $(function(){
|
|
3694
3855
|
|
3695
3856
|
for(i=0; i<=11; i++) {
|
3696
3857
|
if(longNames) {
|
3697
|
-
|
3858
|
+
//see https://github.com/timrwood/momentjs.com/pull/36
|
3859
|
+
name = moment().date(1).month(i).format('MMMM');
|
3698
3860
|
} else if(shortNames) {
|
3699
|
-
name = moment().month(i).format('MMM');
|
3861
|
+
name = moment().date(1).month(i).format('MMM');
|
3700
3862
|
} else if(twoDigit) {
|
3701
3863
|
name = this.leadZero(i+1);
|
3702
3864
|
} else {
|
@@ -3732,9 +3894,10 @@ $(function(){
|
|
3732
3894
|
h12 = this.options.template.indexOf('h') !== -1,
|
3733
3895
|
h24 = this.options.template.indexOf('H') !== -1,
|
3734
3896
|
twoDigit = this.options.template.toLowerCase().indexOf('hh') !== -1,
|
3897
|
+
min = h12 ? 1 : 0,
|
3735
3898
|
max = h12 ? 12 : 23;
|
3736
3899
|
|
3737
|
-
for(i=
|
3900
|
+
for(i=min; i<=max; i++) {
|
3738
3901
|
name = twoDigit ? this.leadZero(i) : i;
|
3739
3902
|
items.push([i, name]);
|
3740
3903
|
}
|
@@ -3783,7 +3946,7 @@ $(function(){
|
|
3783
3946
|
},
|
3784
3947
|
|
3785
3948
|
/*
|
3786
|
-
Returns current date value.
|
3949
|
+
Returns current date value from combos.
|
3787
3950
|
If format not specified - `options.format` used.
|
3788
3951
|
If format = `null` - Moment object returned.
|
3789
3952
|
*/
|
@@ -3812,12 +3975,14 @@ $(function(){
|
|
3812
3975
|
return '';
|
3813
3976
|
}
|
3814
3977
|
|
3815
|
-
//convert hours
|
3978
|
+
//convert hours 12h --> 24h
|
3816
3979
|
if(this.$ampm) {
|
3817
|
-
|
3818
|
-
|
3819
|
-
|
3820
|
-
|
3980
|
+
//12:00 pm --> 12:00 (24-h format, midday), 12:00 am --> 00:00 (24-h format, midnight, start of day)
|
3981
|
+
if(values.hour === 12) {
|
3982
|
+
values.hour = this.$ampm.val() === 'am' ? 0 : 12;
|
3983
|
+
} else {
|
3984
|
+
values.hour = this.$ampm.val() === 'am' ? values.hour : values.hour+12;
|
3985
|
+
}
|
3821
3986
|
}
|
3822
3987
|
|
3823
3988
|
dt = moment([values.year, values.month, values.day, values.hour, values.minute, values.second]);
|
@@ -3868,11 +4033,17 @@ $(function(){
|
|
3868
4033
|
});
|
3869
4034
|
|
3870
4035
|
if(this.$ampm) {
|
3871
|
-
|
3872
|
-
|
4036
|
+
//12:00 pm --> 12:00 (24-h format, midday), 12:00 am --> 00:00 (24-h format, midnight, start of day)
|
4037
|
+
if(values.hour >= 12) {
|
3873
4038
|
values.ampm = 'pm';
|
4039
|
+
if(values.hour > 12) {
|
4040
|
+
values.hour -= 12;
|
4041
|
+
}
|
3874
4042
|
} else {
|
3875
|
-
values.ampm = 'am';
|
4043
|
+
values.ampm = 'am';
|
4044
|
+
if(values.hour === 0) {
|
4045
|
+
values.hour = 12;
|
4046
|
+
}
|
3876
4047
|
}
|
3877
4048
|
}
|
3878
4049
|
|
@@ -4206,7 +4377,7 @@ $(function(){
|
|
4206
4377
|
this.call('update', $content);
|
4207
4378
|
this.call('show');
|
4208
4379
|
|
4209
|
-
this.tip().addClass(
|
4380
|
+
this.tip().addClass(this.containerClass);
|
4210
4381
|
this.$form.data('editableform').input.activate();
|
4211
4382
|
},
|
4212
4383
|
|