x-editable-rails 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
|