';
if (o.showMinute && o.minuteGrid > 0) {
- html += '
' +
- '' +
- '
';
+ html += '
';
- for (var m = o.minuteMin; m < minMax; m += o.minuteGrid) {
+ for (var m = o.minuteMin; m <= minMax; m += parseInt(o.minuteGrid,10)) {
minuteGridSize++;
html += '
';
if (o.showSecond && o.secondGrid > 0) {
- html += '
' +
- '' +
- '
';
+ html += '
';
- for (var s = o.secondMin; s < secMax; s += o.secondGrid) {
+ for (var s = o.secondMin; s <= secMax; s += parseInt(o.secondGrid,10)) {
secondGridSize++;
html += '
' + ((s < 10) ? '0' : '') + s + '
';
}
- html += '
' +
- '';
- } else html += '';
+ html += '
';
+ }
+ html += '
';
+
+ // Milliseconds
+ html += '
' + o.millisecText + '
'+
+ '
';
+
+ if (o.showMillisec && o.millisecGrid > 0) {
+ html += '
';
+
+ for (var l = o.millisecMin; l <= millisecMax; l += parseInt(o.millisecGrid,10)) {
+ millisecGridSize++;
+ html += '
' + ((l < 10) ? '0' : '') + l + '
';
+ }
+
+ html += '
';
+ }
+ html += '
';
+
+ // Timezone
+ html += '
' + o.timezoneText + '
';
+ html += '';
html += '';
$tp = $(html);
@@ -353,6 +472,7 @@ $.extend(Timepicker.prototype, {
}
});
+
// Updated by Peter Medeiros:
// - Pass in Event and UI instance into slide function
this.minute_slider = $tp.find('#ui_tpicker_minute_'+ dp_id).slider({
@@ -362,7 +482,6 @@ $.extend(Timepicker.prototype, {
max: minMax,
step: o.stepMinute,
slide: function(event, ui) {
- // update the global minute slider instance value with the current slider value
tp_inst.minute_slider.slider( "option", "value", ui.value);
tp_inst._onTimeChange();
}
@@ -380,6 +499,31 @@ $.extend(Timepicker.prototype, {
}
});
+ this.millisec_slider = $tp.find('#ui_tpicker_millisec_'+ dp_id).slider({
+ orientation: "horizontal",
+ value: this.millisec,
+ min: o.millisecMin,
+ max: millisecMax,
+ step: o.stepMillisec,
+ slide: function(event, ui) {
+ tp_inst.millisec_slider.slider( "option", "value", ui.value);
+ tp_inst._onTimeChange();
+ }
+ });
+
+ this.timezone_select = $tp.find('#ui_tpicker_timezone_'+ dp_id).append('').find("select");
+ $.fn.append.apply(this.timezone_select,
+ $.map(o.timezoneList, function(val, idx) {
+ return $("")
+ .val(typeof val == "object" ? val.value : val)
+ .text(typeof val == "object" ? val.label : val);
+ })
+ );
+ this.timezone_select.val((typeof this.timezone != "undefined" && this.timezone != null && this.timezone != "") ? this.timezone : o.timezone);
+ this.timezone_select.change(function() {
+ tp_inst._onTimeChange();
+ });
+
// Add grid functionality
if (o.showHour && o.hourGrid > 0) {
size = 100 * hourGridSize * o.hourGrid / (hourMax - o.hourMin);
@@ -393,7 +537,7 @@ $.extend(Timepicker.prototype, {
var h = $(this).html();
if(o.ampm) {
var ap = h.substring(2).toLowerCase(),
- aph = parseInt(h.substring(0,2));
+ aph = parseInt(h.substring(0,2), 10);
if (ap == 'a') {
if (aph == 12) h = 0;
else h = aph;
@@ -402,6 +546,7 @@ $.extend(Timepicker.prototype, {
}
tp_inst.hour_slider.slider("option", "value", h);
tp_inst._onTimeChange();
+ tp_inst._onSelectHandler();
}).css({
cursor: 'pointer',
width: (100 / hourGridSize) + '%',
@@ -421,6 +566,7 @@ $.extend(Timepicker.prototype, {
$(this).click(function() {
tp_inst.minute_slider.slider("option", "value", $(this).html());
tp_inst._onTimeChange();
+ tp_inst._onSelectHandler();
}).css({
cursor: 'pointer',
width: (100 / minuteGridSize) + '%',
@@ -439,6 +585,7 @@ $.extend(Timepicker.prototype, {
$(this).click(function() {
tp_inst.second_slider.slider("option", "value", $(this).html());
tp_inst._onTimeChange();
+ tp_inst._onSelectHandler();
}).css({
cursor: 'pointer',
width: (100 / secondGridSize) + '%',
@@ -448,11 +595,30 @@ $.extend(Timepicker.prototype, {
});
}
+ if (o.showMillisec && o.millisecGrid > 0) {
+ $tp.find(".ui_tpicker_millisec table").css({
+ width: size + "%",
+ marginLeft: (size / (-2 * millisecGridSize)) + "%",
+ borderCollapse: 'collapse'
+ }).find("td").each(function(index) {
+ $(this).click(function() {
+ tp_inst.millisec_slider.slider("option", "value", $(this).html());
+ tp_inst._onTimeChange();
+ tp_inst._onSelectHandler();
+ }).css({
+ cursor: 'pointer',
+ width: (100 / millisecGridSize) + '%',
+ textAlign: 'center',
+ overflow: 'hidden'
+ });
+ });
+ }
+
var $buttonPanel = $dp.find('.ui-datepicker-buttonpane');
if ($buttonPanel.length) $buttonPanel.before($tp);
else $dp.append($tp);
- this.$timeObj = $('#ui_tpicker_time_'+ dp_id);
+ this.$timeObj = $tp.find('#ui_tpicker_time_'+ dp_id);
if (this.inst !== null) {
var timeDefined = this.timeDefined;
@@ -461,85 +627,149 @@ $.extend(Timepicker.prototype, {
}
//Emulate datepicker onSelect behavior. Call on slidestop.
- var onSelect = tp_inst._defaults['onSelect'];
- if (onSelect) {
- var inputEl = tp_inst.$input ? tp_inst.$input[0] : null;
- var onSelectHandler = function() {
- onSelect.apply(inputEl, [tp_inst.formattedDateTime, tp_inst]); // trigger custom callback*/
- }
- this.hour_slider.bind('slidestop',onSelectHandler);
- this.minute_slider.bind('slidestop',onSelectHandler);
- this.second_slider.bind('slidestop',onSelectHandler);
+ var onSelectDelegate = function() {
+ tp_inst._onSelectHandler();
+ };
+ this.hour_slider.bind('slidestop',onSelectDelegate);
+ this.minute_slider.bind('slidestop',onSelectDelegate);
+ this.second_slider.bind('slidestop',onSelectDelegate);
+ this.millisec_slider.bind('slidestop',onSelectDelegate);
+
+ // slideAccess integration: http://trentrichardson.com/2011/11/11/jquery-ui-sliders-and-touch-accessibility/
+ if (this._defaults.addSliderAccess){
+ var sliderAccessArgs = this._defaults.sliderAccessArgs;
+ setTimeout(function(){ // fix for inline mode
+ if($tp.find('.ui-slider-access').length == 0){
+ $tp.find('.ui-slider:visible').sliderAccess(sliderAccessArgs);
+
+ // fix any grids since sliders are shorter
+ var sliderAccessWidth = $tp.find('.ui-slider-access:eq(0)').outerWidth(true);
+ if(sliderAccessWidth){
+ $tp.find('table:visible').each(function(){
+ var $g = $(this),
+ oldWidth = $g.outerWidth(),
+ oldMarginLeft = $g.css('marginLeft').toString().replace('%',''),
+ newWidth = oldWidth - sliderAccessWidth,
+ newMarginLeft = ((oldMarginLeft * newWidth)/oldWidth) + '%';
+
+ $g.css({ width: newWidth, marginLeft: newMarginLeft });
+ });
+ }
+ }
+ },0);
}
+ // end slideAccess integration
+
}
},
//########################################################################
- // This function tries to limit the ability to go outside the
+ // This function tries to limit the ability to go outside the
// min/max date range
//########################################################################
_limitMinMaxDateTime: function(dp_inst, adjustSliders){
var o = this._defaults,
- dp_date = new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay),
- tp_date = new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay, this.hour, this.minute, this.second, 0);
-
- if(this._defaults.minDateTime !== null && dp_date){
- var minDateTime = this._defaults.minDateTime,
+ dp_date = new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay);
+
+ if(!this._defaults.showTimepicker) return; // No time so nothing to check here
+
+ if($.datepicker._get(dp_inst, 'minDateTime') !== null && $.datepicker._get(dp_inst, 'minDateTime') !== undefined && dp_date){
+ var minDateTime = $.datepicker._get(dp_inst, 'minDateTime'),
minDateTimeDate = new Date(minDateTime.getFullYear(), minDateTime.getMonth(), minDateTime.getDate(), 0, 0, 0, 0);
-
- if(this.hourMinOriginal === null || this.minuteMinOriginal === null || this.secondMinOriginal === null){
+
+ if(this.hourMinOriginal === null || this.minuteMinOriginal === null || this.secondMinOriginal === null || this.millisecMinOriginal === null){
this.hourMinOriginal = o.hourMin;
this.minuteMinOriginal = o.minuteMin;
this.secondMinOriginal = o.secondMin;
+ this.millisecMinOriginal = o.millisecMin;
}
-
- if(minDateTimeDate.getTime() == dp_date.getTime()){
- this._defaults.hourMin = minDateTime.getHours();
- this._defaults.minuteMin = minDateTime.getMinutes();
- this._defaults.secondMin = minDateTime.getSeconds();
- if(this.hour < this._defaults.hourMin) this.hour = this._defaults.hourMin;
- if(this.minute < this._defaults.minuteMin) this.minute = this._defaults.minuteMin;
- if(this.second < this._defaults.secondMin) this.second = this._defaults.secondMin;
+ if(dp_inst.settings.timeOnly || minDateTimeDate.getTime() == dp_date.getTime()) {
+ this._defaults.hourMin = minDateTime.getHours();
+ if (this.hour <= this._defaults.hourMin) {
+ this.hour = this._defaults.hourMin;
+ this._defaults.minuteMin = minDateTime.getMinutes();
+ if (this.minute <= this._defaults.minuteMin) {
+ this.minute = this._defaults.minuteMin;
+ this._defaults.secondMin = minDateTime.getSeconds();
+ } else if (this.second <= this._defaults.secondMin){
+ this.second = this._defaults.secondMin;
+ this._defaults.millisecMin = minDateTime.getMilliseconds();
+ } else {
+ if(this.millisec < this._defaults.millisecMin)
+ this.millisec = this._defaults.millisecMin;
+ this._defaults.millisecMin = this.millisecMinOriginal;
+ }
+ } else {
+ this._defaults.minuteMin = this.minuteMinOriginal;
+ this._defaults.secondMin = this.secondMinOriginal;
+ this._defaults.millisecMin = this.millisecMinOriginal;
+ }
}else{
this._defaults.hourMin = this.hourMinOriginal;
this._defaults.minuteMin = this.minuteMinOriginal;
this._defaults.secondMin = this.secondMinOriginal;
+ this._defaults.millisecMin = this.millisecMinOriginal;
}
}
- if(this._defaults.maxDateTime !== null && dp_date){
- var maxDateTime = this._defaults.maxDateTime,
+ if($.datepicker._get(dp_inst, 'maxDateTime') !== null && $.datepicker._get(dp_inst, 'maxDateTime') !== undefined && dp_date){
+ var maxDateTime = $.datepicker._get(dp_inst, 'maxDateTime'),
maxDateTimeDate = new Date(maxDateTime.getFullYear(), maxDateTime.getMonth(), maxDateTime.getDate(), 0, 0, 0, 0);
-
+
if(this.hourMaxOriginal === null || this.minuteMaxOriginal === null || this.secondMaxOriginal === null){
this.hourMaxOriginal = o.hourMax;
this.minuteMaxOriginal = o.minuteMax;
this.secondMaxOriginal = o.secondMax;
+ this.millisecMaxOriginal = o.millisecMax;
}
-
- if(maxDateTimeDate.getTime() == dp_date.getTime()){
+
+ if(dp_inst.settings.timeOnly || maxDateTimeDate.getTime() == dp_date.getTime()){
this._defaults.hourMax = maxDateTime.getHours();
- this._defaults.minuteMax = maxDateTime.getMinutes();
- this._defaults.secondMax = maxDateTime.getSeconds();
-
- if(this.hour > this._defaults.hourMax){ this.hour = this._defaults.hourMax; }
- if(this.minute > this._defaults.minuteMax) this.minute = this._defaults.minuteMax;
- if(this.second > this._defaults.secondMax) this.second = this._defaults.secondMax;
+ if (this.hour >= this._defaults.hourMax) {
+ this.hour = this._defaults.hourMax;
+ this._defaults.minuteMax = maxDateTime.getMinutes();
+ if (this.minute >= this._defaults.minuteMax) {
+ this.minute = this._defaults.minuteMax;
+ this._defaults.secondMax = maxDateTime.getSeconds();
+ } else if (this.second >= this._defaults.secondMax) {
+ this.second = this._defaults.secondMax;
+ this._defaults.millisecMax = maxDateTime.getMilliseconds();
+ } else {
+ if(this.millisec > this._defaults.millisecMax) this.millisec = this._defaults.millisecMax;
+ this._defaults.millisecMax = this.millisecMaxOriginal;
+ }
+ } else {
+ this._defaults.minuteMax = this.minuteMaxOriginal;
+ this._defaults.secondMax = this.secondMaxOriginal;
+ this._defaults.millisecMax = this.millisecMaxOriginal;
+ }
}else{
this._defaults.hourMax = this.hourMaxOriginal;
this._defaults.minuteMax = this.minuteMaxOriginal;
this._defaults.secondMax = this.secondMaxOriginal;
+ this._defaults.millisecMax = this.millisecMaxOriginal;
}
}
-
+
if(adjustSliders !== undefined && adjustSliders === true){
- this.hour_slider.slider("option", { min: this._defaults.hourMin, max: this._defaults.hourMax }).slider('value', this.hour);
- this.minute_slider.slider("option", { min: this._defaults.minuteMin, max: this._defaults.minuteMax }).slider('value', this.minute);
- this.second_slider.slider("option", { min: this._defaults.secondMin, max: this._defaults.secondMax }).slider('value', this.second);
+ var hourMax = parseInt((this._defaults.hourMax - ((this._defaults.hourMax - this._defaults.hourMin) % this._defaults.stepHour)) ,10),
+ minMax = parseInt((this._defaults.minuteMax - ((this._defaults.minuteMax - this._defaults.minuteMin) % this._defaults.stepMinute)) ,10),
+ secMax = parseInt((this._defaults.secondMax - ((this._defaults.secondMax - this._defaults.secondMin) % this._defaults.stepSecond)) ,10),
+ millisecMax = parseInt((this._defaults.millisecMax - ((this._defaults.millisecMax - this._defaults.millisecMin) % this._defaults.stepMillisec)) ,10);
+
+ if(this.hour_slider)
+ this.hour_slider.slider("option", { min: this._defaults.hourMin, max: hourMax }).slider('value', this.hour);
+ if(this.minute_slider)
+ this.minute_slider.slider("option", { min: this._defaults.minuteMin, max: minMax }).slider('value', this.minute);
+ if(this.second_slider)
+ this.second_slider.slider("option", { min: this._defaults.secondMin, max: secMax }).slider('value', this.second);
+ if(this.millisec_slider)
+ this.millisec_slider.slider("option", { min: this._defaults.millisecMin, max: millisecMax }).slider('value', this.millisec);
}
},
+
//########################################################################
// when a slider moves, set the internal time...
@@ -548,65 +778,74 @@ $.extend(Timepicker.prototype, {
_onTimeChange: function() {
var hour = (this.hour_slider) ? this.hour_slider.slider('value') : false,
minute = (this.minute_slider) ? this.minute_slider.slider('value') : false,
- second = (this.second_slider) ? this.second_slider.slider('value') : false;
+ second = (this.second_slider) ? this.second_slider.slider('value') : false,
+ millisec = (this.millisec_slider) ? this.millisec_slider.slider('value') : false,
+ timezone = (this.timezone_select) ? this.timezone_select.val() : false,
+ o = this._defaults;
+
+ if (typeof(hour) == 'object') hour = false;
+ if (typeof(minute) == 'object') minute = false;
+ if (typeof(second) == 'object') second = false;
+ if (typeof(millisec) == 'object') millisec = false;
+ if (typeof(timezone) == 'object') timezone = false;
if (hour !== false) hour = parseInt(hour,10);
if (minute !== false) minute = parseInt(minute,10);
if (second !== false) second = parseInt(second,10);
+ if (millisec !== false) millisec = parseInt(millisec,10);
+
+ var ampm = o[hour < 12 ? 'amNames' : 'pmNames'][0];
- var ampm = (hour < 12) ? 'AM' : 'PM';
-
// If the update was done in the input field, the input field should not be updated.
// If the update was done using the sliders, update the input field.
- var hasChanged = (hour != this.hour || minute != this.minute || second != this.second || (this.ampm.length > 0 && this.ampm != ampm));
+ var hasChanged = (hour != this.hour || minute != this.minute
+ || second != this.second || millisec != this.millisec
+ || (this.ampm.length > 0
+ && (hour < 12) != ($.inArray(this.ampm.toUpperCase(), this.amNames) !== -1))
+ || timezone != this.timezone);
if (hasChanged) {
if (hour !== false)this.hour = hour;
if (minute !== false) this.minute = minute;
if (second !== false) this.second = second;
+ if (millisec !== false) this.millisec = millisec;
+ if (timezone !== false) this.timezone = timezone;
+
+ if (!this.inst) this.inst = $.datepicker._getInst(this.$input[0]);
+
+ this._limitMinMaxDateTime(this.inst, true);
}
- if (this._defaults.ampm) this.ampm = ampm;
+ if (o.ampm) this.ampm = ampm;
- this._formatTime();
- if (this.$timeObj) this.$timeObj.text(this.formattedTime);
+ //this._formatTime();
+ this.formattedTime = $.datepicker.formatTime(this._defaults.timeFormat, this, this._defaults);
+ if (this.$timeObj) this.$timeObj.text(this.formattedTime + o.timeSuffix);
this.timeDefined = true;
if (hasChanged) this._updateDateTime();
},
-
+
//########################################################################
- // format the time all pretty...
+ // call custom onSelect.
+ // bind to sliders slidestop, and grid click.
//########################################################################
- _formatTime: function(time, format, ampm) {
- if (ampm == undefined) ampm = this._defaults.ampm;
- time = time || { hour: this.hour, minute: this.minute, second: this.second, ampm: this.ampm };
- var tmptime = format || this._defaults.timeFormat.toString();
-
- if (ampm) {
- var hour12 = ((time.ampm == 'AM') ? (time.hour) : (time.hour % 12));
- hour12 = (Number(hour12) === 0) ? 12 : hour12;
- tmptime = tmptime.toString()
- .replace(/hh/g, ((hour12 < 10) ? '0' : '') + hour12)
- .replace(/h/g, hour12)
- .replace(/mm/g, ((time.minute < 10) ? '0' : '') + time.minute)
- .replace(/m/g, time.minute)
- .replace(/ss/g, ((time.second < 10) ? '0' : '') + time.second)
- .replace(/s/g, time.second)
- .replace(/TT/g, time.ampm.toUpperCase())
- .replace(/tt/g, time.ampm.toLowerCase())
- .replace(/T/g, time.ampm.charAt(0).toUpperCase())
- .replace(/t/g, time.ampm.charAt(0).toLowerCase());
- } else {
- tmptime = tmptime.toString()
- .replace(/hh/g, ((time.hour < 10) ? '0' : '') + time.hour)
- .replace(/h/g, time.hour)
- .replace(/mm/g, ((time.minute < 10) ? '0' : '') + time.minute)
- .replace(/m/g, time.minute)
- .replace(/ss/g, ((time.second < 10) ? '0' : '') + time.second)
- .replace(/s/g, time.second);
- tmptime = $.trim(tmptime.replace(/t/gi, ''));
+ _onSelectHandler: function() {
+ var onSelect = this._defaults.onSelect;
+ var inputEl = this.$input ? this.$input[0] : null;
+ if (onSelect && inputEl) {
+ onSelect.apply(inputEl, [this.formattedDateTime, this]);
}
+ },
+ //########################################################################
+ // left for any backwards compatibility
+ //########################################################################
+ _formatTime: function(time, format) {
+ time = time || { hour: this.hour, minute: this.minute, second: this.second, millisec: this.millisec, ampm: this.ampm, timezone: this.timezone };
+ var tmptime = (format || this._defaults.timeFormat).toString();
+
+ tmptime = $.datepicker.formatTime(tmptime, time, this._defaults);
+
if (arguments.length) return tmptime;
else this.formattedTime = tmptime;
},
@@ -615,8 +854,8 @@ $.extend(Timepicker.prototype, {
// update our input with the new date time..
//########################################################################
_updateDateTime: function(dp_inst) {
- dp_inst = this.inst || dp_inst,
- dt = new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay),
+ dp_inst = this.inst || dp_inst;
+ var dt = $.datepicker._daylightSavingAdjust(new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay)),
dateFmt = $.datepicker._get(dp_inst, 'dateFormat'),
formatCfg = $.datepicker._getFormatConfig(dp_inst),
timeAvailable = dt !== null && this.timeDefined;
@@ -627,8 +866,8 @@ $.extend(Timepicker.prototype, {
if (this._defaults.timeOnly === true) {
formattedDateTime = this.formattedTime;
- } else if (this._defaults.timeOnly !== true && (this._defaults.alwaysSetTime || timeAvailable)) {
- formattedDateTime += this._defaults.separator + this.formattedTime;
+ } else if (this._defaults.timeOnly !== true && (this._defaults.alwaysSetTime || timeAvailable)) {
+ formattedDateTime += this._defaults.separator + this.formattedTime + this._defaults.timeSuffix;
}
this.formattedDateTime = formattedDateTime;
@@ -671,7 +910,7 @@ $.fn.extend({
datetimepicker: function(o) {
o = o || {};
var $input = this,
- tmp_args = arguments;
+ tmp_args = arguments;
if (typeof(o) == 'string'){
if(o == 'getDate')
@@ -690,6 +929,54 @@ $.fn.extend({
}
});
+//########################################################################
+// format the time all pretty...
+// format = string format of the time
+// time = a {}, not a Date() for timezones
+// options = essentially the regional[].. amNames, pmNames, ampm
+//########################################################################
+$.datepicker.formatTime = function(format, time, options) {
+ options = options || {};
+ options = $.extend($.timepicker._defaults, options);
+ time = $.extend({hour:0, minute:0, second:0, millisec:0, timezone:'+0000'}, time);
+
+ var tmptime = format;
+ var ampmName = options['amNames'][0];
+
+ var hour = parseInt(time.hour, 10);
+ if (options.ampm) {
+ if (hour > 11){
+ ampmName = options['pmNames'][0];
+ if(hour > 12)
+ hour = hour % 12;
+ }
+ if (hour === 0)
+ hour = 12;
+ }
+ tmptime = tmptime.replace(/(?:hh?|mm?|ss?|[tT]{1,2}|[lz])/g, function(match) {
+ switch (match.toLowerCase()) {
+ case 'hh': return ('0' + hour).slice(-2);
+ case 'h': return hour;
+ case 'mm': return ('0' + time.minute).slice(-2);
+ case 'm': return time.minute;
+ case 'ss': return ('0' + time.second).slice(-2);
+ case 's': return time.second;
+ case 'l': return ('00' + time.millisec).slice(-3);
+ case 'z': return time.timezone;
+ case 't': case 'tt':
+ if (options.ampm) {
+ if (match.length == 1)
+ ampmName = ampmName.charAt(0);
+ return match.charAt(0) == 'T' ? ampmName.toUpperCase() : ampmName.toLowerCase();
+ }
+ return '';
+ }
+ });
+
+ tmptime = $.trim(tmptime);
+ return tmptime;
+}
+
//########################################################################
// the bad hack :/ override datepicker so it doesnt close on select
// inspired: http://stackoverflow.com/questions/1252512/jquery-datepicker-prevent-closing-picker-when-clicking-a-date/1762378#1762378
@@ -703,7 +990,7 @@ $.datepicker._selectDate = function (id, dateStr) {
tp_inst._limitMinMaxDateTime(inst, true);
inst.inline = inst.stay_open = true;
//This way the onSelect handler called from calendarpicker get the full dateTime
- this._base_selectDate(id, dateStr + tp_inst._defaults.separator + tp_inst.formattedTime);
+ this._base_selectDate(id, dateStr);
inst.inline = inst.stay_open = false;
this._notifyChange(inst);
this._updateDatepicker(inst);
@@ -717,6 +1004,16 @@ $.datepicker._selectDate = function (id, dateStr) {
//#############################################################################################
$.datepicker._base_updateDatepicker = $.datepicker._updateDatepicker;
$.datepicker._updateDatepicker = function(inst) {
+
+ // don't popup the datepicker if there is another instance already opened
+ var input = inst.input[0];
+ if($.datepicker._curInst &&
+ $.datepicker._curInst != inst &&
+ $.datepicker._datepickerShowing &&
+ $.datepicker._lastInput != input) {
+ return;
+ }
+
if (typeof(inst.stay_open) !== 'boolean' || inst.stay_open === false) {
this._base_updateDatepicker(inst);
@@ -728,7 +1025,7 @@ $.datepicker._updateDatepicker = function(inst) {
};
//#######################################################################################
-// third bad hack :/ override datepicker so it allows spaces and colan in the input field
+// third bad hack :/ override datepicker so it allows spaces and colon in the input field
//#######################################################################################
$.datepicker._base_doKeyPress = $.datepicker._doKeyPress;
$.datepicker._doKeyPress = function(event) {
@@ -738,17 +1035,24 @@ $.datepicker._doKeyPress = function(event) {
if (tp_inst) {
if ($.datepicker._get(inst, 'constrainInput')) {
var ampm = tp_inst._defaults.ampm,
+ dateChars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat')),
datetimeChars = tp_inst._defaults.timeFormat.toString()
.replace(/[hms]/g, '')
.replace(/TT/g, ampm ? 'APM' : '')
+ .replace(/Tt/g, ampm ? 'AaPpMm' : '')
+ .replace(/tT/g, ampm ? 'AaPpMm' : '')
.replace(/T/g, ampm ? 'AP' : '')
.replace(/tt/g, ampm ? 'apm' : '')
.replace(/t/g, ampm ? 'ap' : '') +
" " +
tp_inst._defaults.separator +
- $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat')),
+ tp_inst._defaults.timeSuffix +
+ (tp_inst._defaults.showTimezone ? tp_inst._defaults.timezoneList.join('') : '') +
+ (tp_inst._defaults.amNames.join('')) +
+ (tp_inst._defaults.pmNames.join('')) +
+ dateChars,
chr = String.fromCharCode(event.charCode === undefined ? event.keyCode : event.charCode);
- return event.ctrlKey || (chr < ' ' || !datetimeChars || datetimeChars.indexOf(chr) > -1);
+ return event.ctrlKey || (chr < ' ' || !dateChars || datetimeChars.indexOf(chr) > -1);
}
}
@@ -782,8 +1086,23 @@ $.datepicker._doKeyUp = function (event) {
//#######################################################################################
$.datepicker._base_gotoToday = $.datepicker._gotoToday;
$.datepicker._gotoToday = function(id) {
+ var inst = this._getInst($(id)[0]),
+ $dp = inst.dpDiv;
this._base_gotoToday(id);
- this._setTime(this._getInst($(id)[0]), new Date());
+ var now = new Date();
+ var tp_inst = this._get(inst, 'timepicker');
+ if (tp_inst && tp_inst._defaults.showTimezone && tp_inst.timezone_select) {
+ var tzoffset = now.getTimezoneOffset(); // If +0100, returns -60
+ var tzsign = tzoffset > 0 ? '-' : '+';
+ tzoffset = Math.abs(tzoffset);
+ var tzmin = tzoffset % 60;
+ tzoffset = tzsign + ('0' + (tzoffset - tzmin) / 60).slice(-2) + ('0' + tzmin).slice(-2);
+ if (tp_inst._defaults.timezoneIso8609)
+ tzoffset = tzoffset.substring(0, 3) + ':' + tzoffset.substring(3);
+ tp_inst.timezone_select.val(tzoffset);
+ }
+ this._setTime(inst, now);
+ $( '.ui-datepicker-today', $dp).click();
};
//#######################################################################################
@@ -792,9 +1111,9 @@ $.datepicker._gotoToday = function(id) {
$.datepicker._disableTimepickerDatepicker = function(target, date, withDate) {
var inst = this._getInst(target),
tp_inst = this._get(inst, 'timepicker');
+ $(target).datepicker('getDate'); // Init selected[Year|Month|Day]
if (tp_inst) {
tp_inst._defaults.showTimepicker = false;
- tp_inst._onTimeChange();
tp_inst._updateDateTime(inst);
}
};
@@ -802,9 +1121,10 @@ $.datepicker._disableTimepickerDatepicker = function(target, date, withDate) {
$.datepicker._enableTimepickerDatepicker = function(target, date, withDate) {
var inst = this._getInst(target),
tp_inst = this._get(inst, 'timepicker');
+ $(target).datepicker('getDate'); // Init selected[Year|Month|Day]
if (tp_inst) {
tp_inst._defaults.showTimepicker = true;
- tp_inst._onTimeChange();
+ tp_inst._addTimePicker(inst); // Could be disabled on page load
tp_inst._updateDateTime(inst);
}
};
@@ -819,21 +1139,26 @@ $.datepicker._setTime = function(inst, date) {
// calling _setTime with no date sets time to defaults
hour = date ? date.getHours() : defaults.hour,
minute = date ? date.getMinutes() : defaults.minute,
- second = date ? date.getSeconds() : defaults.second;
+ second = date ? date.getSeconds() : defaults.second,
+ millisec = date ? date.getMilliseconds() : defaults.millisec;
//check if within min/max times..
- if ((hour < defaults.hourMin || hour > defaults.hourMax) || (minute < defaults.minuteMin || minute > defaults.minuteMax) || (second < defaults.secondMin || second > defaults.secondMax)) {
+ if ((hour < defaults.hourMin || hour > defaults.hourMax) || (minute < defaults.minuteMin || minute > defaults.minuteMax) || (second < defaults.secondMin || second > defaults.secondMax) || (millisec < defaults.millisecMin || millisec > defaults.millisecMax)) {
hour = defaults.hourMin;
minute = defaults.minuteMin;
second = defaults.secondMin;
+ millisec = defaults.millisecMin;
}
+ tp_inst.hour = hour;
+ tp_inst.minute = minute;
+ tp_inst.second = second;
+ tp_inst.millisec = millisec;
+
if (tp_inst.hour_slider) tp_inst.hour_slider.slider('value', hour);
- else tp_inst.hour = hour;
if (tp_inst.minute_slider) tp_inst.minute_slider.slider('value', minute);
- else tp_inst.minute = minute;
if (tp_inst.second_slider) tp_inst.second_slider.slider('value', second);
- else tp_inst.second = second;
+ if (tp_inst.millisec_slider) tp_inst.millisec_slider.slider('value', millisec);
tp_inst._onTimeChange();
tp_inst._updateDateTime(inst);
@@ -854,12 +1179,12 @@ $.datepicker._setTimeDatepicker = function(target, date, withDate) {
if (typeof date == "string") {
tp_inst._parseTime(date, withDate);
tp_date = new Date();
- tp_date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second);
+ tp_date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec);
}
else tp_date = new Date(date.getTime());
if (tp_date.toString() == 'Invalid Date') tp_date = undefined;
+ this._setTime(inst, tp_date);
}
- this._setTime(inst, tp_date);
}
};
@@ -888,12 +1213,101 @@ $.datepicker._getDateDatepicker = function(target, noDefault) {
if (tp_inst) {
this._setDateFromField(inst, noDefault);
var date = this._getDate(inst);
- if (date && tp_inst._parseTime($(target).val(), true)) date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second);
+ if (date && tp_inst._parseTime($(target).val(), tp_inst.timeOnly)) date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec);
return date;
}
return this._base_getDateDatepicker(target, noDefault);
};
+//#######################################################################################
+// override parseDate() because UI 1.8.14 throws an error about "Extra characters"
+// An option in datapicker to ignore extra format characters would be nicer.
+//#######################################################################################
+$.datepicker._base_parseDate = $.datepicker.parseDate;
+$.datepicker.parseDate = function(format, value, settings) {
+ var date;
+ try {
+ date = this._base_parseDate(format, value, settings);
+ } catch (err) {
+ if (err.indexOf(":") >= 0) {
+ // Hack! The error message ends with a colon, a space, and
+ // the "extra" characters. We rely on that instead of
+ // attempting to perfectly reproduce the parsing algorithm.
+ date = this._base_parseDate(format, value.substring(0,value.length-(err.length-err.indexOf(':')-2)), settings);
+ } else {
+ // The underlying error was not related to the time
+ throw err;
+ }
+ }
+ return date;
+};
+
+//#######################################################################################
+// override formatDate to set date with time to the input
+//#######################################################################################
+$.datepicker._base_formatDate=$.datepicker._formatDate;
+$.datepicker._formatDate = function(inst, day, month, year){
+ var tp_inst = this._get(inst, 'timepicker');
+ if(tp_inst)
+ {
+ if(day)
+ var b = this._base_formatDate(inst, day, month, year);
+ tp_inst._updateDateTime(inst);
+ return tp_inst.$input.val();
+ }
+ return this._base_formatDate(inst);
+};
+
+//#######################################################################################
+// override options setter to add time to maxDate(Time) and minDate(Time). MaxDate
+//#######################################################################################
+$.datepicker._base_optionDatepicker = $.datepicker._optionDatepicker;
+$.datepicker._optionDatepicker = function(target, name, value) {
+ var inst = this._getInst(target),
+ tp_inst = this._get(inst, 'timepicker');
+ if (tp_inst) {
+ var min,max,onselect;
+ if (typeof name == 'string') { // if min/max was set with the string
+ if (name==='minDate' || name==='minDateTime' )
+ min = value;
+ else if (name==='maxDate' || name==='maxDateTime')
+ max = value;
+ else if (name==='onSelect')
+ onselect=value;
+ } else if (typeof name == 'object') { //if min/max was set with the JSON
+ if(name.minDate)
+ min = name.minDate;
+ else if (name.minDateTime)
+ min = name.minDateTime;
+ else if (name.maxDate)
+ max = name.maxDate;
+ else if (name.maxDateTime)
+ max = name.maxDateTime;
+ }
+ if(min){ //if min was set
+ if(min==0)
+ min=new Date();
+ else
+ min= new Date(min);
+
+ tp_inst._defaults.minDate = min;
+ tp_inst._defaults.minDateTime = min;
+ } else if (max){ //if max was set
+ if(max==0)
+ max=new Date();
+ else
+ max= new Date(max);
+ tp_inst._defaults.maxDate = max;
+ tp_inst._defaults.maxDateTime = max;
+ }
+ else if (onselect)
+ tp_inst._defaults.onSelect=onselect;
+ }
+ if (value === undefined)
+ return this._base_optionDatepicker(target, name);
+ return this._base_optionDatepicker(target, name, value);
+};
+
//#######################################################################################
// jQuery extend now ignores nulls!
//#######################################################################################
@@ -903,9 +1317,10 @@ function extendRemove(target, props) {
if (props[name] === null || props[name] === undefined)
target[name] = props[name];
return target;
-}
+};
$.timepicker = new Timepicker(); // singleton instance
-$.timepicker.version = "0.9.3";
+$.timepicker.version = "0.9.9";
})(jQuery);
+
diff --git a/addons/web/static/lib/qweb/qweb2.js b/addons/web/static/lib/qweb/qweb2.js
index 9845889a0b7..d4f7781e88b 100644
--- a/addons/web/static/lib/qweb/qweb2.js
+++ b/addons/web/static/lib/qweb/qweb2.js
@@ -241,8 +241,8 @@ QWeb2.Engine = (function() {
return true;
},
load_xml : function(s) {
- s = s.replace(/^\s*|\s*$/g, '');
- if (this.tools.trim(s)[0] === '<') {
+ s = this.tools.trim(s);
+ if (s.charAt(0) === '<') {
return this.load_xml_string(s);
} else {
var req = this.get_xhr();
@@ -256,6 +256,9 @@ QWeb2.Engine = (function() {
req.send(null);
var xDoc = req.responseXML;
if (xDoc) {
+ if (!xDoc.documentElement) {
+ throw new Error("QWeb2: This xml document has no root document : " + xDoc.responseText);
+ }
if (xDoc.documentElement.nodeName == "parsererror") {
return this.tools.exception(xDoc.documentElement.childNodes[0].nodeValue);
}
diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css
index ce86eb889ea..2a27e61eb3d 100644
--- a/addons/web/static/src/css/base.css
+++ b/addons/web/static/src/css/base.css
@@ -1,9 +1,12 @@
-body { padding: 0; margin: 0; }
+body.openerp {
+ padding: 0;
+ margin: 0;
+ overflow-y: scroll;
+}
.openerp {
padding: 0;
margin: 0;
height: 100%;
- overflow-y: scroll;
font-size: 80%;
font-family: Ubuntu, Helvetica, sans-serif;
}
@@ -382,6 +385,14 @@ label.error {
height: 100%;
}
+/* IE Hack - for IE < 9
+ * Avoids footer to be placed statically at 100% cutting the middle of the views
+ * */
+.openerp .oe-application-container {
+ height: auto\9;
+ min-height: 100%\9;
+}
+
/* Menu */
.openerp .menu {
height: 34px;
@@ -747,6 +758,7 @@ label.error {
}
.openerp .filter_label.enabled, .openerp .filter_icon.enabled {
background: #aaa;
+ filter: none;
-moz-box-shadow: none;
-webkit-box-shadow: none;
-o-box-shadow: none;
@@ -1172,7 +1184,20 @@ label.error {
/* Form */
-
+.openerp .oe_form_button_save_dirty {
+ display: none;
+}
+.openerp .oe_form_dirty > .oe_form_header > .oe_form_buttons > .oe_form_button_save {
+ color: white;
+ background: #dc5f59;
+ background: -moz-linear-gradient(#dc5f59, #b33630);
+ background: -webkit-gradient(linear, left top, left bottom, from(#dc5f59), to(#b33630));
+ background: -webkit-linear-gradient(#dc5f59, #b33630);
+ -moz-box-shadow: none;
+ -webkit-box-shadow: none;
+ -box-shadow: none;
+ font-weight: bold;
+}
.openerp .oe_form_frame_cell input[type="checkbox"] {
margin-top: 3px;
vertical-align: middle;
@@ -1208,6 +1233,11 @@ label.error {
.openerp td.oe_form_frame_cell {
padding: 2px;
position: relative;
+}
+.openerp td.oe_form_field_translatable,
+.openerp td.oe_form_field_many2one,
+.openerp td.oe_form_field_date,
+.openerp td.oe_form_field_datetime {
white-space: nowrap;
}
.openerp td.oe_form_field_boolean {
@@ -1307,6 +1337,10 @@ label.error {
white-space: normal;
}
+.openerp .oe_forms .oe_form_paragraph.oe_multilines {
+ white-space: pre;
+}
+
.openerp .oe_form_field_one2many .oe-actions h3.oe_view_title,
.openerp .oe_form_field_one2many_list .oe-actions h3.oe_view_title{
display: inline;
@@ -1319,6 +1353,9 @@ label.error {
margin-top: -9px;
}
+.openerp table.oe_frame .oe-listview-content td {
+ color: inherit;
+}
/* Uneditable Form View */
.openerp .oe_form_readonly {
@@ -1421,10 +1458,14 @@ label.error {
.openerp .oe_forms select{
padding-top: 2px;
}
+.openerp .oe_forms input[readonly],
+.openerp .oe_forms select[readonly],
+.openerp .oe_forms textarea[readonly],
.openerp .oe_forms input[disabled],
.openerp .oe_forms select[disabled],
.openerp .oe_forms textarea[disabled]{
- background: #E0E0E0;
+ background: #E5E5E5 !important;
+ color: #666;
}
.openerp .oe_forms textarea {
resize:vertical;
@@ -1446,15 +1487,21 @@ label.error {
min-width: 100%;
width: 100%;
}
-.openerp .oe_forms .button {
- height: 22px;
-}
@-moz-document url-prefix() {
/* Strange firefox behaviour on width: 100% + white-space: nowrap */
.openerp .oe_forms .oe_form_button .oe_button {
width: auto;
}
}
+/* IE Hack - for IE < 9
+ * Avoids buttons overflow
+ * */
+.openerp .oe_forms .oe_form_button .oe_button {
+ min-width: auto\9;
+}
+.openerp .oe_forms .button {
+ height: 22px;
+}
.openerp .oe_forms .oe_button span {
position: relative;
vertical-align: top;
@@ -1888,6 +1935,7 @@ label.error {
width: 100%;
background-color : #FFFFFF;
border-spacing: 0;
+
}
.openerp .oe-treeview-table tr:hover{
color: blue;
@@ -1908,14 +1956,14 @@ label.error {
white-space: nowrap;
display: block;
}
-.treeview-tr:first-of-type {
+.treeview-tr.oe-treeview-first {
background: transparent url(/web/static/src/img/expand.gif) 0 50% no-repeat;
}
-.oe-open .treeview-tr:first-of-type {
+.oe-open .treeview-tr.oe-treeview-first {
background-image: url(/web/static/src/img/collapse.gif);
}
-.treeview-tr:first-of-type span,
-.treeview-td:first-of-type span {
+.treeview-tr.oe-treeview-first span,
+.treeview-td.oe-treeview-first span {
margin-left: 16px;
}
@@ -2031,34 +2079,31 @@ ul.oe-arrow-list li.oe-arrow-list-selected .oe-arrow-list-after {
border-bottom-right-radius: 3px;
}
.openerp .oe_view_editor {
- border-collapse: collapse;
- padding: 0;
- align: left;
+ width:100%;
+ border-collapse : collapse;
+ margin-left: -12px;
+
width: 100%;
+ background-color : white;
+ border-spacing: 0;
}
-.openerp .oe_view_editor_colum{
+.openerp .oe_view_editor td{
+ text-align: center;
+ white-space: nowrap;
+ border: 1px solid #D8D8D8;
+
+ cursor: pointer;
font-size: 90%;
- font-weight: normal;
- padding: 0;
- border-bottom: 1px solid #CFCCCC;
}
-.openerp .oe_view_editor_row:hover {
- background-color: #F3F3F3;
+.openerp .oe_view_editor_field td{
+ border: 0px !important;
}
-.openerp .oe_view_editor_tree_grid{
- text-align: left;
- white-space: nowrap;
- border-collapse: collapse;
- width: 100%;
-}
-.openerp .oe_view_editor_tree_grid a:hover {
- color: blue;
-}
-.openerp .oe_view_editor_tree_grid a {
- display: block;
+.openerp .oe_view_editor tr:hover {
+ background-color: #ecebf2;
}
+
/* Dialog traceback cases */
.openerp .oe_error_detail{
display: block;
diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js
index 9fda4752a36..ba31ec81846 100644
--- a/addons/web/static/src/js/chrome.js
+++ b/addons/web/static/src/js/chrome.js
@@ -20,17 +20,27 @@ openerp.web.Notification = openerp.web.OldWidget.extend(/** @lends openerp.web.
expires: 2500
});
},
- notify: function(title, text) {
+ notify: function(title, text, sticky) {
+ sticky = !!sticky;
+ var opts = {};
+ if (sticky) {
+ opts.expires = false;
+ }
this.$element.notify('create', {
title: title,
text: text
- });
+ }, opts);
},
- warn: function(title, text) {
+ warn: function(title, text, sticky) {
+ sticky = !!sticky;
+ var opts = {};
+ if (sticky) {
+ opts.expires = false;
+ }
this.$element.notify('create', 'oe_notification_alert', {
title: title,
text: text
- });
+ }, opts);
}
});
@@ -606,6 +616,10 @@ openerp.web.Login = openerp.web.OldWidget.extend(/** @lends openerp.web.Login#
}
var $e = this.$element;
var db = $e.find("form [name=db]").val();
+ if (!db) {
+ this.do_warn("Login", "No database selected !");
+ return false;
+ }
var login = $e.find("form input[name=login]").val();
var password = $e.find("form input[name=password]").val();
@@ -945,7 +959,8 @@ openerp.web.Menu = openerp.web.OldWidget.extend(/** @lends openerp.web.Menu# */
do_menu_click: function($clicked_menu, manual) {
var $sub_menu, $main_menu,
active = $clicked_menu.is('.active'),
- sub_menu_visible = false;
+ sub_menu_visible = false,
+ has_submenu_items = false;
if (this.$secondary_menu.has($clicked_menu).length) {
$sub_menu = $clicked_menu.parents('.oe_secondary_menu');
@@ -956,15 +971,18 @@ openerp.web.Menu = openerp.web.OldWidget.extend(/** @lends openerp.web.Menu# */
}
sub_menu_visible = $sub_menu.is(':visible');
+ has_submenu_items = !!$sub_menu.children().length;
this.$secondary_menu.find('.oe_secondary_menu').hide();
$('.active', this.$element.add(this.$secondary_menu)).removeClass('active');
$main_menu.add($clicked_menu).add($sub_menu).addClass('active');
- if (!(this.folded && manual)) {
- this.do_show_secondary($sub_menu, $main_menu);
- } else {
- this.do_show_secondary();
+ if (has_submenu_items) {
+ if (!(this.folded && manual)) {
+ this.do_show_secondary($sub_menu, $main_menu);
+ } else {
+ this.do_show_secondary();
+ }
}
if ($main_menu != $clicked_menu) {
@@ -980,7 +998,7 @@ openerp.web.Menu = openerp.web.OldWidget.extend(/** @lends openerp.web.Menu# */
return true;
}
} else if (this.folded) {
- if (active && sub_menu_visible) {
+ if ((active && sub_menu_visible) || !has_submenu_items) {
$sub_menu.hide();
return true;
}
@@ -1147,12 +1165,14 @@ openerp.web.WebClient = openerp.web.OldWidget.extend(/** @lends openerp.web.WebC
n.warn.apply(n, arguments);
},
on_logout: function() {
- this.session.session_logout();
- $(window).unbind('hashchange', this.on_hashchange);
- this.do_push_state({});
- //would be cool to be able to do this, but I think it will make addons do strange things
- //this.show_login();
- window.location.reload();
+ var self = this;
+ this.session.session_logout().then(function () {
+ $(window).unbind('hashchange', self.on_hashchange);
+ self.do_push_state({});
+ //would be cool to be able to do this, but I think it will make addons do strange things
+ //this.show_login();
+ window.location.reload();
+ });
},
bind_hashchange: function() {
$(window).bind('hashchange', this.on_hashchange);
diff --git a/addons/web/static/src/js/core.js b/addons/web/static/src/js/core.js
index 8ab6c897fb0..086f7f3b56a 100644
--- a/addons/web/static/src/js/core.js
+++ b/addons/web/static/src/js/core.js
@@ -254,6 +254,7 @@ openerp.web.Registry = openerp.web.Class.extend( /** @lends openerp.web.Registry
* @param {Object} mapping a mapping of keys to object-paths
*/
init: function (mapping) {
+ this.parent = null;
this.map = mapping || {};
},
/**
@@ -269,6 +270,9 @@ openerp.web.Registry = openerp.web.Class.extend( /** @lends openerp.web.Registry
get_object: function (key, silent_error) {
var path_string = this.map[key];
if (path_string === undefined) {
+ if (this.parent) {
+ return this.parent.get_object(key, silent_error);
+ }
if (silent_error) { return void 'nooo'; }
throw new openerp.web.KeyNotFound(key);
}
@@ -286,6 +290,21 @@ openerp.web.Registry = openerp.web.Class.extend( /** @lends openerp.web.Registry
}
return object_match;
},
+ /**
+ * Checks if the registry contains an object mapping for this key.
+ *
+ * @param {String} key key to look for
+ */
+ contains: function (key) {
+ if (key === undefined) { return false; }
+ if (key in this.map) {
+ return true
+ }
+ if (this.parent) {
+ return this.parent.contains(key);
+ }
+ return false;
+ },
/**
* Tries a number of keys, and returns the first object matching one of
* the keys.
@@ -299,7 +318,7 @@ openerp.web.Registry = openerp.web.Class.extend( /** @lends openerp.web.Registry
get_any: function (keys) {
for (var i=0; i\n\t ", val[1]);
+ var vals = {'model': self.model, 'name': view_name, 'priority': priority.priority + 1, 'type': "form", 'arch': arch,'inherit_id':self.main_view_id};
+ this.dataset.create(vals, function(suc) {
+ var arch_to_obj = self.parse_xml(arch,suc.result);
+ obj.child_id.push(arch_to_obj[0]);
+ self.one_object['parent_child_id'] = self.parent_child_list(self.one_object['main_object'],[]);
+ self.one_object['arch'].push({'view_id':suc.result,"arch":arch,'priority': priority.priority + 1});
+ self.increase_level(arch_to_obj[0],obj.level+1);
+ self.render_inherited_view(selected_row,arch_to_obj[0]);
+ });
+ },
+ render_inherited_view: function(selected_row,obj){
+ var self = this,row_id = parseInt((selected_row.attr('id')).split('-')[1]);
+ var clone = this.create_clone(selected_row.clone(),obj);
+ if (selected_row.find("img[id^='parentimg-']").length == 0) {
+ ($(selected_row.find('a').parent()).siblings('td'))
+ .append($('').attr('src', '/web/static/src/img/collapse.gif').
+ attr('id','parentimg-'+ row_id).click(function(){
+ self.do_parent_img_hide_show(this);
+ }));
+ }
+ self.edit_xml_dialog.$element.
+ find("tr[id='viewedit-"+row_id+"']").after(clone.removeClass('ui-selected'));
+ _.each(obj.child_id,function(obj){self.render_inherited_view(clone,obj);});
+ },
on_select_img: function(element_img) {
var self = this;
var side = $(element_img).closest("tr[id^='viewedit-']");
@@ -449,7 +515,7 @@ openerp.web.ViewEditor = openerp.web.OldWidget.extend({
},
do_node_add: function(side){
var self = this;
- var tr = $(side).find('a').text();
+ var tr = self.get_object_by_id(this.one_object.clicked_tr_id, this.one_object['main_object'], [])[0].att_list[0];
var parent_tr = ($(side).prevAll("tr[level=" + String(this.one_object.clicked_tr_level - 1) + "]"))[0];
var field_dataset = new openerp.web.DataSetSearch(this, this.model, null, null);
parent_tr = $(parent_tr).find('a').text();
@@ -562,13 +628,13 @@ openerp.web.ViewEditor = openerp.web.OldWidget.extend({
arch.arch = _.detect(children, function(xml_child) {
var temp_obj = self.create_View_Node(xml_child),
insert = _.intersection(_.flatten(temp_obj.att_list),_.uniq(check_list));
- if (insert.length == check_list.length ) {return xml_child;}
+ if (insert.length == _.uniq(check_list).length ) {return xml_child;}
});
}
arch_to_pass = _.filter($(arch.arch), function (child) {
return child.nodeType == 1;
});
- return self.do_save_xml(arch_to_pass[0], obj[0].child_id[0],[], move_direct, update_values,arch);
+ return self.do_save_xml(arch_to_pass[0], obj[0].child_id[0],obj[0].child_id, move_direct, update_values,arch);
},
get_object_by_id: function(id, one_object, result) {
var self = this;
@@ -583,7 +649,7 @@ openerp.web.ViewEditor = openerp.web.OldWidget.extend({
}
return result;
},
- create_clone: function(clone, new_node_obj, position){
+ create_clone: function(clone, new_node_obj){
var self = this;
clone.find('a').text(new_node_obj.name);
($(clone.find('a').parent()).siblings('td')).css( "padding-left", 20 * new_node_obj.level);
@@ -599,7 +665,8 @@ openerp.web.ViewEditor = openerp.web.OldWidget.extend({
return clone;
},
do_save_xml: function(arch1, obj, child_list, move_direct, update_values, arch){
- var self = this, children_list = $(arch1).children(), list_obj_xml = _.zip(children_list, obj.child_id);
+ var self = this, children_list = $(arch1).children(),list_obj_xml;
+ try{list_obj_xml = _.zip(children_list, obj.child_id);}catch(err){return;}
if (this.one_object.clicked_tr_id) {
if (obj.id == this.one_object.clicked_tr_id) {
var parent = false, index = _.indexOf(child_list, obj);
@@ -823,6 +890,7 @@ openerp.web.ViewEditor = openerp.web.OldWidget.extend({
var value = _.detect(arch_val[0]['att_list'],function(res) {
return res instanceof Array? _.include(res, widget.name): false;
});
+
value = value instanceof Array ? value[1] : value;
self.edit_node_dialog.$element.find('table[id=rec_table]').append('
', record.name))
.appendTo($logs_list)
- .delegate('a', 'click', function (e) {
+ .delegate('a', 'click', function () {
self.do_action({
type: 'ir.actions.act_window',
res_model: record.res_model,
res_id: record.res_id,
// TODO: need to have an evaluated context here somehow
- //context: record.context,
- views: [[false, 'form']]
+ context: context,
+ views: [[context.view_id || false, 'form']]
});
return false;
});
@@ -821,10 +816,6 @@ session.web.Sidebar = session.web.OldWidget.extend({
}, {
label: _t("Export"),
callback: view.on_sidebar_export
- }, {
- label: _t("View Log"),
- callback: view.on_sidebar_view_log,
- classname: 'oe_hide oe_sidebar_view_log'
}
]);
},
@@ -863,18 +854,32 @@ session.web.Sidebar = session.web.OldWidget.extend({
}
return $section;
},
-
+ /**
+ * For each item added to the section:
+ *
+ * ``label``
+ * will be used as the item's name in the sidebar
+ *
+ * ``action``
+ * descriptor for the action which will be executed, ``action`` and
+ * ``callback`` should be exclusive
+ *
+ * ``callback``
+ * function to call when the item is clicked in the sidebar, called
+ * with the item descriptor as its first argument (so information
+ * can be stored as additional keys on the object passed to
+ * ``add_items``)
+ *
+ * ``classname`` (optional)
+ * ``@class`` set on the sidebar serialization of the item
+ *
+ * ``title`` (optional)
+ * will be set as the item's ``@title`` (tooltip)
+ *
+ * @param {String} section_code
+ * @param {Array<{label, action | callback[, classname][, title]}>} items
+ */
add_items: function(section_code, items) {
- // An item is a dictonary : {
- // label: label to be displayed for the link,
- // action: action to be launch when the link is clicked,
- // callback: a function to be executed when the link is clicked,
- // classname: optional dom class name for the line,
- // title: optional title for the link
- // }
- // Note: The item should have one action or/and a callback
- //
-
var self = this,
$section = this.add_section(_.str.titleize(section_code.replace('_', ' ')), section_code),
section_id = $section.attr('id');
@@ -1038,7 +1043,8 @@ session.web.TranslateDialog = session.web.Dialog.extend({
},
on_button_Save: function() {
var trads = {},
- self = this;
+ self = this,
+ trads_mutex = new $.Mutex();
self.$fields_form.find('.oe_trad_field.touched').each(function() {
var field = $(this).attr('name').split('-');
if (!trads[field[0]]) {
@@ -1051,9 +1057,10 @@ session.web.TranslateDialog = session.web.Dialog.extend({
_.each(data, function(value, field) {
self.view.fields[field].set_value(value);
});
- } else {
- self.view.dataset.write(self.view.datarecord.id, data, { 'lang': code });
}
+ trads_mutex.exec(function() {
+ return self.view.dataset.write(self.view.datarecord.id, data, { context : { 'lang': code } });
+ });
});
this.close();
},
@@ -1222,8 +1229,6 @@ session.web.View = session.web.Widget.extend(/** @lends session.web.View# */{
view_mode : "list"
});
},
- on_sidebar_view_log: function() {
- },
sidebar_context: function () {
return $.when();
},
diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml
index 6b068679310..2d867c25390 100644
--- a/addons/web/static/src/xml/base.xml
+++ b/addons/web/static/src/xml/base.xml
@@ -484,7 +484,6 @@
-
@@ -529,11 +528,11 @@
-