vendor/assets/javascripts/bootstrap-editable.js in bootstrap-editable-rails-0.0.4 vs vendor/assets/javascripts/bootstrap-editable.js in bootstrap-editable-rails-0.0.5
- old
+ new
@@ -1,6 +1,6 @@
-/*! X-editable - v1.4.1
+/*! X-editable - v1.4.3
* In-place editing with Twitter Bootstrap, jQuery UI or pure jQuery
* http://github.com/vitalets/x-editable
* Copyright (c) 2013 Vitaliy Potapov; Licensed MIT */
/**
@@ -492,11 +492,11 @@
if(!response.success) return response.msg;
}
**/
success: null,
/**
- Additional options for ajax request.
+ Additional options for submit ajax request.
List of values: http://api.jquery.com/jQuery.ajax
@property ajaxOptions
@type object
@default null
@@ -709,11 +709,11 @@
result = [],
that = this;
$.each(sourceData, function(i, o) {
if(o.children) {
- result = result.concat(that.itemsByValue(value, o.children));
+ result = result.concat(that.itemsByValue(value, o.children, valueProp));
} else {
/*jslint eqeq: true*/
if(isValArray) {
if($.grep(value, function(v){ return v == (o && typeof o === 'object' ? o[valueProp] : o); }).length) {
result.push(o);
@@ -829,11 +829,12 @@
$('.editable-open').editableContainer('hide');
//todo: return focus on element
}
});
- //close containers when click outside
+ //close containers when click outside
+ //(mousedown could be better than click, it closes everything also on drag drop)
$(document).on('click.editable', function(e) {
var $target = $(e.target), i,
exclude_classes = ['.editable-container',
'.ui-datepicker-header',
'.modal-backdrop',
@@ -878,11 +879,11 @@
return this.container() ? this.container().$tip : null;
},
/* returns container object */
container: function() {
- return this.$element.data(this.containerName);
+ return this.$element.data(this.containerDataName || this.containerName);
},
call: function() {
this.$element[this.containerName].apply(this.$element, arguments);
},
@@ -907,12 +908,12 @@
@event shown
@param {Object} event event object
@example
$('#username').on('shown', function() {
- var $tip = $(this).data('editableContainer').tip();
- $tip.find('input').val('overwriting value of input..');
+ var editable = $(this).data('editable');
+ editable.input.$input.val('overwriting value of input..');
});
**/
this.$element.triggerHandler('shown');
}, this)
})
@@ -1209,13 +1210,13 @@
/**
Animation speed (inline mode)
@property anim
@type string
- @default 'fast'
+ @default false
**/
- anim: 'fast',
+ anim: false,
/**
Mode of editable, can be `popup` or `inline`
@property mode
@@ -1318,11 +1319,13 @@
doAutotext, finalize;
//name
this.options.name = this.options.name || this.$element.attr('id');
- //create input of specified type. Input will be used for converting value, not in form
+ //create input of specified type. Input needed already here to convert value for initial display (e.g. show text by id for select)
+ //also we set scope option to have access to element inside input specific callbacks (e. g. source as function)
+ this.options.scope = this.$element[0];
this.input = $.fn.editableutils.createInput(this.options);
if(!this.input) {
return;
}
@@ -1369,13 +1372,23 @@
} else {
this.$element.attr('tabindex', -1); //do not stop focus on element when toggled manually
}
//check conditions for autotext:
- //if value was generated by text or value is empty, no sense to run autotext
- doAutotext = !isValueByText && this.value !== null && this.value !== undefined;
- doAutotext &= (this.options.autotext === 'always') || (this.options.autotext === 'auto' && !this.$element.text().length);
+ switch(this.options.autotext) {
+ case 'always':
+ doAutotext = true;
+ break;
+ case 'auto':
+ //if element text is empty and value is defined and value not generated by text --> run autotext
+ doAutotext = !$.trim(this.$element.text()).length && this.value !== null && this.value !== undefined && !isValueByText;
+ break;
+ default:
+ doAutotext = false;
+ }
+
+ //depending on autotext run render() or just finilize init
$.when(doAutotext ? this.render() : true).then($.proxy(function() {
if(this.options.disabled) {
this.disable();
} else {
this.enable();
@@ -1407,10 +1420,15 @@
this.options.autotext = 'never';
//listen toggle events
this.$element.on(this.options.toggle + '.editable', selector, $.proxy(function(e){
var $target = $(e.target);
if(!$target.data('editable')) {
+ //if delegated element initially empty, we need to clear it's text (that was manually set to `empty` by user)
+ //see https://github.com/vitalets/x-editable/issues/137
+ if($target.hasClass(this.options.emptyclass)) {
+ $target.empty();
+ }
$target.editable(this.options).trigger(e);
}
}, this));
},
@@ -1528,11 +1546,11 @@
handleEmpty: function (isEmpty) {
//do not handle empty if we do not display anything
if(this.options.display === false) {
return;
}
-
+
this.isEmpty = isEmpty !== undefined ? isEmpty : $.trim(this.$element.text()) === '';
//emptytext shown only for enabled
if(!this.options.disabled) {
if (this.isEmpty) {
@@ -1749,15 +1767,18 @@
}
});
return result;
/**
- Returns current values of editable elements. If value is <code>null</code> or <code>undefined</code> it will not be returned
+ Returns current values of editable elements.
+ Note that it returns an **object** with name-value pairs, not a value itself. It allows to get data from several elements.
+ If value of some editable is `null` or `undefined` it is excluded from result object.
+
@method getValue()
@returns {Object} object of element names and values
@example
- $('#username, #fullname').editable('validate');
+ $('#username, #fullname').editable('getValue');
// possible result:
{
username: "superuser",
fullname: "John"
}
@@ -1890,28 +1911,40 @@
@type string
@default 'auto'
**/
autotext: 'auto',
/**
- Initial value of input. If not set, taken from element's text.
-
+ Initial value of input. If not set, taken from element's text.
+ Note, that if element's text is empty - text is automatically generated from value and can be customized (see `autotext` option).
+ For example, to display currency sign:
+ @example
+ <a id="price" data-type="text" data-value="100"></a>
+ <script>
+ $('#price').editable({
+ ...
+ display: function(value) {
+ $(this).text(value + '$');
+ }
+ })
+ </script>
+
@property value
@type mixed
@default element's text
**/
value: null,
/**
Callback to perform custom displaying of value in element's text.
If `null`, default input's display used.
If `false`, no displaying methods will be called, element's text will never change.
Runs under element's scope.
- _Parameters:_
+ _**Parameters:**_
* `value` current value to be displayed
* `response` server response (if display called after ajax submit), since 1.4.0
- For **inputs with source** (select, checklist) parameters are different:
+ For _inputs with source_ (select, checklist) parameters are different:
* `value` current value to be displayed
* `sourceData` array of items for current input (e.g. dropdown items)
* `response` server response (if display called after ajax submit), since 1.4.0
@@ -1954,23 +1987,27 @@
@since 1.4.1
@default editable-unsaved
**/
unsavedclass: 'editable-unsaved',
/**
- If a css selector is provided, editable will be delegated to the specified targets.
+ If selector is provided, editable will be delegated to the specified targets.
Usefull for dynamically generated DOM elements.
- **Please note**, that delegated targets can't use `emptytext` and `autotext` options,
- as they are initialized after first click.
+ **Please note**, that delegated targets can't be initialized with `emptytext` and `autotext` options,
+ as they actually become editable only after first click.
+ You should manually set class `editable-click` to these elements.
+ Also, if element originally empty you should add class `editable-empty`, set `data-value=""` and write emptytext into element:
@property selector
@type string
@since 1.4.1
@default null
@example
<div id="user">
- <a href="#" data-name="username" data-type="text" title="Username">awesome</a>
- <a href="#" data-name="group" data-type="select" data-source="/groups" data-value="1" title="Group">Operator</a>
+ <!-- empty -->
+ <a href="#" data-name="username" data-type="text" class="editable-click editable-empty" data-value="" title="Username">Empty</a>
+ <!-- non-empty -->
+ <a href="#" data-name="group" data-type="select" data-source="/groups" data-value="1" class="editable-click" title="Group">Operator</a>
</div>
<script>
$('#user').editable({
selector: 'a',
@@ -2143,11 +2180,11 @@
this.$input.addClass(this.options.inputclass);
}
},
setAttr: function(attr) {
- if (this.options[attr]) {
+ if (this.options[attr] !== undefined && this.options[attr] !== null) {
this.$input.attr(attr, this.options[attr]);
}
},
option: function(key, value) {
@@ -2170,11 +2207,14 @@
@property inputclass
@type string
@default input-medium
**/
- inputclass: 'input-medium'
+ inputclass: 'input-medium',
+ //scope for external methods (e.g. source defined as function)
+ //for internal use only
+ scope: null
};
$.extend($.fn.editabletypes, {abstractinput: AbstractInput});
}(window.jQuery));
@@ -2249,16 +2289,23 @@
this.options.source = $.fn.editableutils.tryParseJson(this.options.source, false);
} catch (e) {
error.call(this);
return;
}
+
+ var source = this.options.source;
+
+ //run source if it function
+ if ($.isFunction(source)) {
+ source = source.call(this.options.scope);
+ }
//loading from url
- if (typeof this.options.source === 'string') {
+ if (typeof source === 'string') {
//try to get from cache
if(this.options.sourceCache) {
- var cacheID = this.options.source,
+ var cacheID = source,
cache;
if (!$(document).data(cacheID)) {
$(document).data(cacheID, {});
}
@@ -2287,11 +2334,11 @@
}
}
//loading sourceData from server
$.ajax({
- url: this.options.source,
+ url: source,
type: 'get',
cache: false,
dataType: 'json',
success: $.proxy(function (data) {
if(cache) {
@@ -2322,16 +2369,12 @@
//run error callbacks for other fields
$.each(cache.err_callbacks, function () { this.call(); });
}
}, this)
});
- } else { //options as json/array/function
- if ($.isFunction(this.options.source)) {
- this.sourceData = this.makeArray(this.options.source());
- } else {
- this.sourceData = this.makeArray(this.options.source);
- }
+ } else { //options as json/array
+ this.sourceData = this.makeArray(source);
if($.isArray(this.sourceData)) {
this.doPrepend();
success.call(this);
} else {
@@ -2344,20 +2387,24 @@
if(this.options.prepend === null || this.options.prepend === undefined) {
return;
}
if(!$.isArray(this.prependData)) {
+ //run prepend if it is function (once)
+ if ($.isFunction(this.options.prepend)) {
+ this.options.prepend = this.options.prepend.call(this.options.scope);
+ }
+
//try parse json in single quotes
this.options.prepend = $.fn.editableutils.tryParseJson(this.options.prepend, true);
+
+ //convert prepend from string to object
if (typeof this.options.prepend === 'string') {
this.options.prepend = {'': this.options.prepend};
- }
- if (typeof this.options.prepend === 'function') {
- this.prependData = this.makeArray(this.options.prepend());
- } else {
- this.prependData = this.makeArray(this.options.prepend);
}
+
+ this.prependData = this.makeArray(this.options.prepend);
}
if($.isArray(this.prependData) && $.isArray(this.sourceData)) {
this.sourceData = this.prependData.concat(this.sourceData);
}
@@ -2534,12 +2581,24 @@
//render clear button
renderClear: function() {
if (this.options.clear) {
this.$clear = $('<span class="editable-clear-x"></span>');
this.$input.after(this.$clear)
- .css('padding-right', 20)
- .keyup($.proxy(this.toggleClear, this))
+ .css('padding-right', 24)
+ .keyup($.proxy(function(e) {
+ //arrows, enter, tab, etc
+ if(~$.inArray(e.keyCode, [40,38,9,13,27])) {
+ return;
+ }
+
+ clearTimeout(this.t);
+ var that = this;
+ this.t = setTimeout(function() {
+ that.toggleClear(e);
+ }, 100);
+
+ }, this))
.parent().css('position', 'relative');
this.$clear.click($.proxy(this.clear, this));
}
},
@@ -2553,23 +2612,28 @@
//workaround for plain-popup
if(delta < 3) {
delta = 3;
}
- this.$clear.css({top: delta, right: delta});
+ this.$clear.css({bottom: delta, right: delta});
}
},
//show / hide clear button
- toggleClear: function() {
+ toggleClear: function(e) {
if(!this.$clear) {
return;
}
- if(this.$input.val().length) {
+ var len = this.$input.val().length,
+ visible = this.$clear.is(':visible');
+
+ if(len && !visible) {
this.$clear.show();
- } else {
+ }
+
+ if(!len && visible) {
this.$clear.hide();
}
},
clear: function() {
@@ -2731,11 +2795,10 @@
source: [
{value: 1, text: 'Active'},
{value: 2, text: 'Blocked'},
{value: 3, text: 'Deleted'}
]
- }
});
});
</script>
**/
(function ($) {
@@ -2801,11 +2864,12 @@
tpl:'<select></select>'
});
$.fn.editabletypes.select = Select;
-}(window.jQuery));
+}(window.jQuery));
+
/**
List of checkboxes.
Internally value stored as javascript array of values.
@class checklist
@@ -2820,11 +2884,10 @@
source: [
{value: 1, text: 'option1'},
{value: 2, text: 'option2'},
{value: 3, text: 'option3'}
]
- }
});
});
</script>
**/
(function ($) {
@@ -3130,10 +3193,13 @@
You should manually include select2 distributive:
<link href="select2/select2.css" rel="stylesheet" type="text/css"></link>
<script src="select2/select2.js"></script>
+**Note:** currently `ajax` source for select2 is not supported, as it's not possible to load it in closed select2 state.
+The solution is to load source manually and assign statically.
+
@class select2
@extends abstractinput
@since 1.4.1
@final
@example
@@ -3159,25 +3225,42 @@
this.init('select2', options, Constructor.defaults);
options.select2 = options.select2 || {};
var that = this,
- mixin = {
+ mixin = { //mixin to select2 options
placeholder: options.placeholder
};
//detect whether it is multi-valued
this.isMultiple = options.select2.tags || options.select2.multiple;
- //if not `tags` mode, we need define init set data from source
+ //if not `tags` mode, we need define initSelection to set data from source
if(!options.select2.tags) {
if(options.source) {
mixin.data = options.source;
}
//this function can be defaulted in seletc2. See https://github.com/ivaynberg/select2/issues/710
mixin.initSelection = function (element, callback) {
+ //temp: try update results
+ /*
+ if(options.select2 && options.select2.ajax) {
+ console.log('attached');
+ var original = $(element).data('select2').postprocessResults;
+ console.log(original);
+ $(element).data('select2').postprocessResults = function(data, initial) {
+ console.log('postprocess');
+ // this.element.triggerHandler('loaded', [data]);
+ original.apply(this, arguments);
+ }
+
+ // $(element).on('loaded', function(){console.log('loaded');});
+ $(element).data('select2').updateResults(true);
+ }
+ */
+
var val = that.str2value(element.val()),
data = $.fn.editableutils.itemsByValue(val, mixin.data, 'id');
//for single-valued mode should not use array. Take first element instead.
if($.isArray(data) && data.length && !that.isMultiple) {
@@ -3198,30 +3281,44 @@
render: function() {
this.setClass();
//apply select2
this.$input.select2(this.options.select2);
+ //when data is loaded via ajax, we need to know when it's done
+ if('ajax' in this.options.select2) {
+ /*
+ console.log('attached');
+ var original = this.$input.data('select2').postprocessResults;
+ this.$input.data('select2').postprocessResults = function(data, initial) {
+ this.element.triggerHandler('loaded', [data]);
+ original.apply(this, arguments);
+ }
+ */
+ }
+
+
//trigger resize of editableform to re-position container in multi-valued mode
if(this.isMultiple) {
this.$input.on('change', function() {
$(this).closest('form').parent().triggerHandler('resize');
});
- }
-
- },
+ }
+ },
value2html: function(value, element) {
var text = '', data;
- if(this.$input) { //when submitting form
+ if(this.$input) { //called when submitting form and select2 already exists
data = this.$input.select2('data');
} else { //on init (autotext)
//here select2 instance not created yet and data may be even not loaded.
//we can check data/tags property of select config and if exist lookup text
if(this.options.select2.tags) {
data = value;
} else if(this.options.select2.data) {
data = $.fn.editableutils.itemsByValue(value, this.options.select2.data, 'id');
+ } else {
+ //if('ajax' in this.options.select2) {
}
}
if($.isArray(data)) {
//collect selected data and show with separator
@@ -3241,11 +3338,11 @@
html2value: function(html) {
return this.options.select2.tags ? this.str2value(html, this.options.viewseparator) : null;
},
value2input: function(value) {
- this.$input.val(value).trigger('change');
+ this.$input.val(value).trigger('change', true); //second argument needed to separate initial change from user's click (for autosubmit)
},
input2value: function() {
return this.$input.select2('val');
},
@@ -3266,11 +3363,19 @@
for (i = 0, l = val.length; i < l; i = i + 1) {
val[i] = $.trim(val[i]);
}
return val;
- }
+ },
+
+ autosubmit: function() {
+ this.$input.on('change', function(e, isInitial){
+ if(!isInitial) {
+ $(this).closest('form').submit();
+ }
+ });
+ }
});
Constructor.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, {
/**
@@ -3316,11 +3421,11 @@
$.fn.editabletypes.select2 = Constructor;
}(window.jQuery));
/**
-* Combodate - 1.0.1
+* Combodate - 1.0.2
* Dropdown date and time picker.
* Converts text input into dropdowns to pick day, month, year, hour, minute and second.
* Uses momentjs as datetime library http://momentjs.com.
* For i18n include corresponding file from https://github.com/timrwood/moment/tree/master/lang
*
@@ -3419,13 +3524,17 @@
/*
Initialize items of combos. Handles `firstItem` option
*/
initItems: function(key) {
- var values = [];
+ var values = [],
+ relTime;
+
if(this.options.firstItem === 'name') {
- var header = typeof moment.relativeTime[key] === 'function' ? moment.relativeTime[key](1, true, key, false) : moment.relativeTime[key];
+ //need both to suuport moment ver < 2 and >= 2
+ relTime = moment.relativeTime || moment.langData()._relativeTime;
+ var header = typeof relTime[key] === 'function' ? relTime[key](1, true, key, false) : relTime[key];
//take last entry (see momentjs lang files structure)
header = header.split(' ').reverse()[0];
values.push(['', header]);
} else if(this.options.firstItem === 'empty') {
values.push(['', '']);
@@ -3467,13 +3576,13 @@
shortNames = this.options.template.indexOf('MMM') !== -1,
twoDigit = this.options.template.indexOf('MM') !== -1;
for(i=0; i<=11; i++) {
if(longNames) {
- name = moment.months[i];
+ name = moment().month(i).format('MMMM');
} else if(shortNames) {
- name = moment.monthsShort[i];
+ name = moment().month(i).format('MMM');
} else if(twoDigit) {
name = this.leadZero(i+1);
} else {
name = i+1;
}
@@ -3715,11 +3824,11 @@
};
}(window.jQuery));
/**
Combodate input - dropdown date and time picker.
-Based on [combodate](http://vitalets.github.com/combodate) plugin. To use it you should manually include [momentjs](http://momentjs.com).
+Based on [combodate](http://vitalets.github.com/combodate) plugin (included). To use it you should manually include [momentjs](http://momentjs.com).
<script src="js/moment.min.js"></script>
Allows to input:
@@ -3763,10 +3872,13 @@
//by default viewformat equals to format
if(!this.options.viewformat) {
this.options.viewformat = this.options.format;
}
+ //try parse combodate config defined as json string in data-combodate
+ options.combodate = $.fn.editableutils.tryParseJson(options.combodate, true);
+
//overriding combodate config (as by default jQuery extend() is not recursive)
this.options.combodate = $.extend({}, Constructor.defaults.combodate, options.combodate, {
format: this.options.format,
template: this.options.template
});
@@ -4147,16 +4259,28 @@
this.$input.data('datepicker').date = null;
this.$input.find('.active').removeClass('active');
},
autosubmit: function() {
+ this.$input.on('mouseup', '.day', function(e){
+ if($(e.currentTarget).is('.old') || $(e.currentTarget).is('.new')) {
+ return;
+ }
+ var $form = $(this).closest('form');
+ setTimeout(function() {
+ $form.submit();
+ }, 200);
+ });
+ //changedate is not suitable as it triggered when showing datepicker. see #149
+ /*
this.$input.on('changeDate', function(e){
var $form = $(this).closest('form');
setTimeout(function() {
$form.submit();
}, 200);
});
+ */
}
});
Date.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, {
@@ -4195,16 +4319,18 @@
@property datepicker
@type object
@default {
weekStart: 0,
startView: 0,
+ minViewMode: 0,
autoclose: false
}
**/
datepicker:{
weekStart: 0,
startView: 0,
+ minViewMode: 0,
autoclose: false
},
/**
Text shown as clear date button.
If <code>false</code> clear button will not be rendered.
@@ -4289,10 +4415,11 @@
/* datepicker config */
datepicker: {
weekStart: 0,
startView: 0,
+ minViewMode: 0,
autoclose: true
}
});
$.fn.editabletypes.datefield = DateField;
@@ -4333,13 +4460,14 @@
var Datepicker = function(element, options) {
var that = this;
this.element = $(element);
this.language = options.language||this.element.data('date-language')||"en";
+ this.language = this.language in dates ? this.language : this.language.split('-')[0]; //Check if "de-DE" style date is available, if not language should fallback to 2 letter code eg "de"
this.language = this.language in dates ? this.language : "en";
this.isRTL = dates[this.language].rtl||false;
- this.format = DPGlobal.parseFormat(options.format||this.element.data('date-format')||'mm/dd/yyyy');
+ this.format = DPGlobal.parseFormat(options.format||this.element.data('date-format')||dates[this.language].format||'mm/dd/yyyy');
this.isInline = false;
this.isInput = this.element.is('input');
this.component = this.element.is('.date') ? this.element.find('.add-on') : false;
this.hasInput = this.component && this.element.find('input').length;
if(this.component && this.component.length === 0)
@@ -4351,12 +4479,12 @@
if ('forceParse' in options) {
this.forceParse = options.forceParse;
} else if ('dateForceParse' in this.element.data()) {
this.forceParse = this.element.data('date-force-parse');
}
-
+
this.picker = $(DPGlobal.template)
.appendTo(this.isInline ? this.element : 'body')
.on({
click: $.proxy(this.click, this),
mousedown: $.proxy(this.mousedown, this)
@@ -4372,11 +4500,11 @@
this.picker.find('.prev i, .next i')
.toggleClass('icon-arrow-left icon-arrow-right');
}
$(document).on('mousedown', function (e) {
// Clicked outside the datepicker, hide it
- if ($(e.target).closest('.datepicker').length === 0) {
+ if ($(e.target).closest('.datepicker.datepicker-inline, .datepicker.datepicker-dropdown').length === 0) {
that.hide();
}
});
this.autoclose = false;
@@ -4403,13 +4531,42 @@
case 'year':
this.viewMode = this.startViewMode = 1;
break;
}
+ this.minViewMode = options.minViewMode||this.element.data('date-min-view-mode')||0;
+ if (typeof this.minViewMode === 'string') {
+ switch (this.minViewMode) {
+ case 'months':
+ this.minViewMode = 1;
+ break;
+ case 'years':
+ this.minViewMode = 2;
+ break;
+ default:
+ this.minViewMode = 0;
+ break;
+ }
+ }
+
+ this.viewMode = this.startViewMode = Math.max(this.startViewMode, this.minViewMode);
+
this.todayBtn = (options.todayBtn||this.element.data('date-today-btn')||false);
this.todayHighlight = (options.todayHighlight||this.element.data('date-today-highlight')||false);
+ this.calendarWeeks = false;
+ if ('calendarWeeks' in options) {
+ this.calendarWeeks = options.calendarWeeks;
+ } else if ('dateCalendarWeeks' in this.element.data()) {
+ this.calendarWeeks = this.element.data('date-calendar-weeks');
+ }
+ if (this.calendarWeeks)
+ this.picker.find('tfoot th.today')
+ .attr('colspan', function(i, val){
+ return parseInt(val) + 1;
+ });
+
this.weekStart = ((options.weekStart||this.element.data('date-weekstart')||dates[this.language].weekStart||0) % 7);
this.weekEnd = ((this.weekStart + 6) % 7);
this.startDate = -Infinity;
this.endDate = Infinity;
this.daysOfWeekDisabled = [];
@@ -4495,10 +4652,11 @@
});
},
hide: function(e){
if(this.isInline) return;
+ if (!this.picker.is(':visible')) return;
this.picker.hide();
$(window).off('resize', this.place);
this.viewMode = this.startViewMode;
this.showMode();
if (!this.isInput) {
@@ -4616,31 +4774,28 @@
this.date = DPGlobal.parseDate(date, this.format, this.language);
if(fromArgs) this.setValue();
- var oldViewDate = this.viewDate;
if (this.date < this.startDate) {
this.viewDate = new Date(this.startDate);
} else if (this.date > this.endDate) {
this.viewDate = new Date(this.endDate);
} else {
this.viewDate = new Date(this.date);
}
-
- if (oldViewDate && oldViewDate.getTime() != this.viewDate.getTime()){
- this.element.trigger({
- type: 'changeDate',
- date: this.viewDate
- });
- }
this.fill();
},
fillDow: function(){
var dowCnt = this.weekStart,
html = '<tr>';
+ if(this.calendarWeeks){
+ var cell = '<th class="cw"> </th>';
+ html += cell;
+ this.picker.find('.datepicker-days thead tr:first-child').prepend(cell);
+ }
while (dowCnt < this.weekStart + 7) {
html += '<th class="dow">'+dates[this.language].daysMin[(dowCnt++)%7]+'</th>';
}
html += '</tr>';
this.picker.find('.datepicker-days thead').append(html);
@@ -4663,11 +4818,11 @@
startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
currentDate = this.date && this.date.valueOf(),
today = new Date();
- this.picker.find('.datepicker-days thead th:eq(1)')
+ this.picker.find('.datepicker-days thead th.switch')
.text(dates[this.language].months[month]+' '+year);
this.picker.find('tfoot th.today')
.text(dates[this.language].today)
.toggle(this.todayBtn !== false);
this.updateNavArrows();
@@ -4682,10 +4837,25 @@
var html = [];
var clsName;
while(prevMonth.valueOf() < nextMonth) {
if (prevMonth.getUTCDay() == this.weekStart) {
html.push('<tr>');
+ if(this.calendarWeeks){
+ // ISO 8601: First week contains first thursday.
+ // ISO also states week starts on Monday, but we can be more abstract here.
+ var
+ // Start of current week: based on weekstart/current date
+ ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
+ // Thursday of this week
+ th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
+ // First Thursday of year, year from thursday
+ yth = new Date(+(yth = UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
+ // Calendar week: ms between thursdays, div ms per day, div 7 days
+ calWeek = (th - yth) / 864e5 / 7 + 1;
+ html.push('<td class="cw">'+ calWeek +'</td>');
+
+ }
}
clsName = '';
if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
clsName += ' old';
} else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
@@ -4817,23 +4987,33 @@
break;
case 'span':
if (!target.is('.disabled')) {
this.viewDate.setUTCDate(1);
if (target.is('.month')) {
+ var day = 1;
var month = target.parent().find('span').index(target);
+ var year = this.viewDate.getUTCFullYear();
this.viewDate.setUTCMonth(month);
this.element.trigger({
type: 'changeMonth',
date: this.viewDate
});
+ if ( this.minViewMode == 1 ) {
+ this._setDate(UTCDate(year, month, day,0,0,0,0));
+ }
} else {
var year = parseInt(target.text(), 10)||0;
+ var day = 1;
+ var month = 0;
this.viewDate.setUTCFullYear(year);
this.element.trigger({
type: 'changeYear',
date: this.viewDate
});
+ if ( this.minViewMode == 2 ) {
+ this._setDate(UTCDate(year, month, day,0,0,0,0));
+ }
}
this.showMode(-1);
this.fill();
}
break;
@@ -5026,11 +5206,11 @@
}
},
showMode: function(dir) {
if (dir) {
- this.viewMode = Math.max(0, Math.min(2, this.viewMode + dir));
+ this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
}
/*
vitalets: fixing bug of very special conditions:
jquery 1.7.1 + webkit + show inline datepicker in bootstrap popover.
Method show() does not set display css correctly and datepicker is not shown.
@@ -5286,11 +5466,10 @@
source: [
{value: 'gb', text: 'Great Britain'},
{value: 'us', text: 'United States'},
{value: 'ru', text: 'Russia'}
]
- }
});
});
</script>
**/
(function ($) {
@@ -5318,12 +5497,15 @@
this.options.typeahead.source = this.sourceData;
//apply typeahead
this.$input.typeahead(this.options.typeahead);
- //attach own render method
- this.$input.data('typeahead').render = $.proxy(this.typeaheadRender, this.$input.data('typeahead'));
+ //patch some methods in typeahead
+ var ta = this.$input.data('typeahead');
+ ta.render = $.proxy(this.typeaheadRender, ta);
+ ta.select = $.proxy(this.typeaheadSelect, ta);
+ ta.move = $.proxy(this.typeaheadMove, ta);
this.renderClear();
this.setClass();
this.setAttr('placeholder');
},
@@ -5398,11 +5580,11 @@
/*
Typeahead option methods used as defaults
*/
- /*jshint eqeqeq:false, curly: false, laxcomma: true*/
+ /*jshint eqeqeq:false, curly: false, laxcomma: true, asi: true*/
matcher: function (item) {
return $.fn.typeahead.Constructor.prototype.matcher.call(this, item.text);
},
sorter: function (items) {
var beginswith = []
@@ -5422,22 +5604,21 @@
},
highlighter: function (item) {
return $.fn.typeahead.Constructor.prototype.highlighter.call(this, item.text);
},
updater: function (item) {
- item = this.$menu.find('.active').data('item');
this.$element.data('value', item.value);
return item.text;
},
/*
Overwrite typeahead's render method to store objects.
There are a lot of disscussion in bootstrap repo on this point and still no result.
See https://github.com/twitter/bootstrap/issues/5967
- This function just store item in via jQuery data() method instead of attr('data-value')
+ This function just store item via jQuery data() method instead of attr('data-value')
*/
typeaheadRender: function (items) {
var that = this;
items = $(items).map(function (i, item) {
@@ -5445,14 +5626,60 @@
i = $(that.options.item).data('item', item);
i.find('a').html(that.highlighter(item));
return i[0];
});
- items.first().addClass('active');
+ //add option to disable autoselect of first line
+ //see https://github.com/twitter/bootstrap/pull/4164
+ if (this.options.autoSelect) {
+ items.first().addClass('active');
+ }
this.$menu.html(items);
return this;
+ },
+
+ //add option to disable autoselect of first line
+ //see https://github.com/twitter/bootstrap/pull/4164
+ typeaheadSelect: function () {
+ var val = this.$menu.find('.active').data('item')
+ if(this.options.autoSelect || val){
+ this.$element
+ .val(this.updater(val))
+ .change()
+ }
+ return this.hide()
+ },
+
+ /*
+ if autoSelect = false and nothing matched we need extra press onEnter that is not convinient.
+ This patch fixes it.
+ */
+ typeaheadMove: function (e) {
+ if (!this.shown) return
+
+ switch(e.keyCode) {
+ case 9: // tab
+ case 13: // enter
+ case 27: // escape
+ if (!this.$menu.find('.active').length) return
+ e.preventDefault()
+ break
+
+ case 38: // up arrow
+ e.preventDefault()
+ this.prev()
+ break
+
+ case 40: // down arrow
+ e.preventDefault()
+ this.next()
+ break
+ }
+
+ e.stopPropagation()
}
- /*jshint eqeqeq: true, curly: true, laxcomma: false*/
+
+ /*jshint eqeqeq: true, curly: true, laxcomma: false, asi: false*/
});
Constructor.defaults = $.extend({}, $.fn.editabletypes.list.defaults, {
/**
\ No newline at end of file