diff --git a/etemplate/inc/class.etemplate_widget_date.inc.php b/etemplate/inc/class.etemplate_widget_date.inc.php new file mode 100644 index 0000000000..b45c908bc7 --- /dev/null +++ b/etemplate/inc/class.etemplate_widget_date.inc.php @@ -0,0 +1,25 @@ + array('date-houronly' => 'select-hour') + ); +} +new jscalendar(); +etemplate_widget::registerWidget('etemplate_widget_date', array('date-houronly')); diff --git a/etemplate/js/et2_widget_date.js b/etemplate/js/et2_widget_date.js index 2566dfbc66..4e85561900 100644 --- a/etemplate/js/et2_widget_date.js +++ b/etemplate/js/et2_widget_date.js @@ -71,6 +71,9 @@ var et2_date = et2_inputWidget.extend({ if(this.type == "date" || this.type == "date-time") { + this.getSurroundings().insertDOMNode(this.button[0]); + this.getSurroundings().update(); + window.setTimeout(function() { Calendar.setup({ inputField: this_id, @@ -122,6 +125,202 @@ var et2_date = et2_inputWidget.extend({ et2_register_widget(et2_date, ["date", "date-time", "date-timeonly"]); +var et2_date_duration = et2_date.extend({ + attributes: { + "data_format": { + "name": "Data format", + "default": "m", + "type": "string", + "description": "Units to read/store the data. 'd' = days (float), 'h' = hours (float), 'm' = minutes (int)." + }, + "display_format": { + "name": "Display format", + "default": "dh", + "type": "string", + "description": "Permitted units for displaying the data. 'd' = days, 'h' = hours, 'm' = minutes. Use combinations to give a choice. Default is 'dh' = days or hours with selectbox." + }, + "percent_allowed": { + "name": "Percent allowed", + "default": false, + "type": "boolean", + "description": "Allows to enter a percentage." + }, + "hours_per_day": { + "name": "Hours per day", + "default": 8, + "type": "integer", + "description": "Number of hours in a day, for converting between hours and (working) days." + }, + "empty_not_0": { + "name": "0 or empty", + "default": false, + "type": "boolean", + "description": "Should the widget differ between 0 and empty, which get then returned as NULL" + }, + "short_labels": { + "name": "Short labels", + "default": false, + "type": "boolean", + "description": "use d/h/m instead of day/hour/minute" + } + }, + + legacyOptions: ["data_format","display_format", "hours_per_day", "empty_not_0", "short_labels"], + + init: function() { + this._super.apply(this, arguments); + + this.input = null; + + // Legacy option put percent in with display format + if(this.options.display_format.indexOf("%") != -1) + { + this.options.percent_allowed = true; + this.options.display_format = this.options.display_format.replace("%",""); + } + this.createInputWidget(); + }, + + createInputWidget: function() { + // Create nodes + this.node = $j(document.createElement("span")); + this.duration = $j(document.createElement("input")).attr("size", "5"); + this.node.append(this.duration); + + // Time format labels + var time_formats = { + "d": this.options.short_labels ? egw.lang("m") : egw.lang("Days"), + "h": this.options.short_labels ? egw.lang("h") : egw.lang("Hours"), + "m": this.options.short_labels ? egw.lang("m") : egw.lang("Minutes") + }; + if(this.options.display_format.length > 1) + { + this.format = $j(document.createElement("select")); + this.node.append(this.format); + + for(var i = 0; i < this.options.display_format.length; i++) { + this.format.append(""); + } + } else { + this.node.append(time_formats[this.options.display_format]); + } + }, + attachToDOM: function() { + var node = this.getInputNode(); + if (node) + { + $j(node).bind("change.et2_inputWidget", this, function(e) { + e.data.change(this); + }); + } + et2_DOMWidget.prototype.attachToDOM.apply(this, arguments); + }, + getDOMNode: function() { + return this.node[0]; + }, + getInputNode: function() { + return this.duration[0]; + }, + + /** + * Use id on node, same as DOMWidget + */ + set_id: function(_value) { + this.id = _value; + + var node = this.getDOMNode(this); + if (node) + { + if (_value != "") + { + node.setAttribute("id", _value); + } + else + { + node.removeAttribute("id"); + } + } + }, + set_value: function(_value) { + this.options.value = _value; + if (_value) + { + // Put value into minutes for further processing + switch(this.options.data_format) + { + case 'd': + _value *= this.options.hours_per_day; + // fall-through + case 'h': + _value *= 60; + break; + } + } + + + // Figure out best unit for display + var _unit = this.options.display_format == "d" ? "d" : "h"; + if (this.options.data_format.indexOf('m') > -1 && _value && _value < 60) + { + _unit = 'm'; + } + else if (this.options.data_format.indexOf('d') > -1 && _value >= 60*this.options.hours_per_day) + { + _unit = 'd'; + } + _value = this.options.empty_not_0 && _value === '' || !this.options.empty_not_0 && !_value ? '' : + (_unit == 'm' ? parseInt( _value) : (Math.round((_value / 60.0 / (_unit == 'd' ? this.options.hours_per_day : 1))*100)/100)); + // use decimal separator from user prefs + var sep = '.'; + var format = egw.preference('number_format'); + if (format && (sep = format[0]) && sep != '.') + { + _value = _value.replace('.',sep); + } + + // Set unit as figured above + if(_unit != this.options.display_format && this.format) + { + $j("option[value='"+_unit+"']",this.format).attr('selected','selected'); + } + + // Set display + this.duration.val(_value); + }, + + /** + * Change displayed value into storage value and return + */ + getValue: function() { + value = this.duration.val(); + if(value === '') + { + return this.options.empty_not_0 ? null : ''; + } + // Put value into minutes for further processing + switch(this.format ? this.format.val() : this.options.display_format) + { + case 'd': + value *= this.options.hours_per_day; + // fall-through + case 'h': + value *= 60; + break; + } + switch(this.options.data_format) + { + case 'd': + value /= this.options.hours_per_day; + // fall-through + case 'h': + value /= 60.0; + break; + } + return value; + } +}); +et2_register_widget(et2_date_duration, ["date-duration"]); + /** * et2_date_ro is the dummy readonly implementation of the date widget. */ @@ -148,7 +347,7 @@ var et2_date_ro = et2_valueWidget.extend({ this._super.apply(this, arguments); this.value = ""; - this.span = $j(document.createElement("time")) + this.span = $j(document.createElement(this.type == "date-since" ? "span" : "time")) .addClass("et2_date_ro et2_label"); this.setDOMNode(this.span[0]); @@ -156,7 +355,6 @@ var et2_date_ro = et2_valueWidget.extend({ set_value: function(_value) { this.value = _value; - // JS dates use milliseconds if(isNaN(_value) && _value.indexOf(":") > 0 && this.type == "date-timeonly") { this.span.text(_value); @@ -175,11 +373,44 @@ var et2_date_ro = et2_valueWidget.extend({ case "date-time": display = date(egw.preference('dateformat') + " " + (egw.preference('timeformat') == '24' ? 'H:i' : 'g:i a'), this.date); + break; + case "date-since": + var unit2label = { + 'Y': 'years', + 'm': 'month', + 'd': 'days', + 'H': 'hours', + 'i': 'minutes', + 's': 'seconds', + }; + var unit2s = { + 'Y': 31536000, + 'm': 2628000, + 'd': 86400, + 'H': 3600, + 'i': 60, + 's': 1, + }; + var d = new Date(); + var diff = Math.round(d.valueOf() / 1000) - Math.round(this.date.valueOf()/1000); + display = ''; + + for(var unit in unit2s) + { + var unit_s = unit2s[unit]; + if (diff >= unit_s || unit == 's') + { + display = Math.round(diff/unit_s,1)+' '+egw.lang(unit2label[unit]); + break; + } + } + break } this.span.attr("datetime", date("Y-m-d H:i:s",this.date)).text(display); } }); -et2_register_widget(et2_date_ro, ["date_ro", "date-time_ro"]); +et2_register_widget(et2_date_ro, ["date_ro", "date-time_ro", "date-since"]); + diff --git a/etemplate/js/test/et2_test_date.xet b/etemplate/js/test/et2_test_date.xet index 43a6c8d4ac..6777892fbf 100644 --- a/etemplate/js/test/et2_test_date.xet +++ b/etemplate/js/test/et2_test_date.xet @@ -7,10 +7,11 @@ - + +