2011-08-22 20:18:29 +02:00
/ * *
* eGroupWare eTemplate2 - JS Date object
*
* @ license http : //opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @ package etemplate
* @ subpackage api
* @ link http : //www.egroupware.org
* @ author Nathan Gray
* @ copyright Nathan Gray 2011
* @ version $Id$
* /
"use strict" ;
/ * e g w : u s e s
jquery . jquery ;
2011-08-29 23:15:53 +02:00
jscalendar . calendar - setup ;
jscalendar . calendar ;
/ p h p g w a p i / j s / j s c a l e n d a r / l a n g / c a l e n d a r - e n . j s ;
lib / date ;
2011-08-24 12:18:07 +02:00
et2 _core _inputWidget ;
et2 _core _valueWidget ;
2011-08-22 20:18:29 +02:00
* /
/ * *
* Class which implements the "date" XET - Tag
* /
var et2 _date = et2 _inputWidget . extend ( {
attributes : {
"value" : {
"type" : "any"
} ,
"type" : {
"ignore" : false
}
} ,
/ * *
* Internal container for working easily with dates
* /
date : new Date ( ) ,
2011-08-24 12:05:52 +02:00
init : function ( ) {
2011-08-22 20:18:29 +02:00
this . _super . apply ( this , arguments ) ;
this . input = null ;
this . createInputWidget ( ) ;
} ,
createInputWidget : function ( ) {
2011-08-29 23:15:53 +02:00
2011-08-31 21:58:38 +02:00
this . input _date = $j ( document . createElement ( "input" ) ) ;
2011-08-22 20:18:29 +02:00
2011-08-31 21:58:38 +02:00
var type = ( this . type == "date-timeonly" ? "time" : "text" ) ;
this . input _date . addClass ( "et2_date" ) . attr ( "type" , type ) . attr ( "size" , 5 ) ;
2011-08-22 20:18:29 +02:00
2011-08-31 21:58:38 +02:00
var node = this . input _date ;
2011-08-29 23:15:53 +02:00
2011-08-31 02:08:59 +02:00
// Add a button
2011-08-29 23:15:53 +02:00
if ( this . type == "date" || this . type == "date-time" ) {
2011-08-31 02:08:59 +02:00
this . span = $j ( document . createElement ( "span" ) ) ;
2011-08-31 21:58:38 +02:00
this . button = $j ( document . createElement ( "span" ) ) ;
this . button . attr ( "id" , this . options . id + "-trigger" ) ;
this . span . append ( this . input _date ) . append ( this . button ) ;
// Icon could be done in CSS file
var button _image = egw . image ( 'datepopup' , 'phpgwapi' ) ;
if ( button _image )
{
this . button . css ( "background-image" , "url(" + button _image + ")" ) ;
}
2011-08-31 02:08:59 +02:00
node = this . span ;
node . addClass ( "et2_date" ) ;
2011-08-31 21:58:38 +02:00
var _this = this ;
2011-09-01 01:37:30 +02:00
var dateformat = egw . preference ( "dateformat" ) ;
if ( ! dateformat ) dateformat = "Y-m-d" ;
dateformat = dateformat . replace ( "Y" , "%Y" ) . replace ( "d" , "%d" ) . replace ( "m" , "%m" ) . replace ( "M" , "%b" ) ;
2011-08-31 21:58:38 +02:00
var setup = {
inputField : this . options . id ,
button : this . button . attr ( "id" ) ,
showsTime : false ,
2011-09-01 01:37:30 +02:00
onUpdate : function ( _value ) { _this . set _value ( _value ) } ,
daFormat : dateformat ,
firstDay : egw . preference ( "weekdaystarts" , "calendar" )
2011-08-31 21:58:38 +02:00
} ;
2011-08-29 23:15:53 +02:00
window . setTimeout ( function ( ) {
2011-08-31 21:58:38 +02:00
Calendar . setup ( setup ) ;
2011-08-29 23:15:53 +02:00
} , 500 ) ;
}
2011-08-31 21:58:38 +02:00
// If date also has a time, or browser doesn't support HTML5 time type
if ( this . type == "date-time" || this . type == "date-timeonly" && this . input _date . attr ( "type" ) == 'text' )
{
if ( ! this . span )
{
this . span = $j ( document . createElement ( "span" ) ) ;
node = this . span ;
}
switch ( this . type )
{
case "date-time" :
var input _time = $j ( document . createElement ( "input" ) ) . attr ( "type" , "time" ) ;
if ( input _time . attr ( "type" ) == "time" )
{
this . input _time = input _time ;
this . input _time . appendTo ( this . span ) . attr ( "size" , 5 ) ;
break ;
}
// Fall through
default :
this . _make _time _selects ( this . span ) ;
break ;
}
}
else if ( this . type == "date-timeonly" )
{
// Update internal value if control changes
this . input _date . change ( this , function ( e ) { e . data . set _value ( $j ( e . target ) . val ( ) ) ; } ) ;
}
2011-08-31 02:08:59 +02:00
this . setDOMNode ( node [ 0 ] ) ;
2011-08-22 20:18:29 +02:00
} ,
2011-08-31 21:58:38 +02:00
_make _time _selects : function ( node ) {
var timeformat = egw . preference ( "timeformat" ) ;
this . input _hours = $j ( document . createElement ( "select" ) ) ;
for ( var i = 0 ; i < 24 ; i ++ )
{
var time = i ;
if ( timeformat == 12 )
{
2011-08-31 22:32:24 +02:00
switch ( i )
{
case 0 :
time = "12 am" ;
break ;
case 12 : time = "12 pm" ;
break ;
default :
time = i % 12 + " " + ( i < 12 ? "am" : "pm" ) ;
}
2011-08-31 21:58:38 +02:00
}
else if ( time < 10 )
{
time = "0" + time ;
}
var option = $j ( document . createElement ( "option" ) ) . attr ( "value" , i ) . text ( time ) ;
option . appendTo ( this . input _hours ) ;
}
this . input _hours . appendTo ( node ) . change ( this , function ( e ) {
if ( e . data . type == "date-timeonly" )
{
e . data . set _value ( e . target . options [ e . target . selectedIndex ] . value + ":" + $j ( 'option:selected' , e . data . input _minutes ) . text ( ) ) ;
}
else
{
e . data . date . setHours ( e . target . options [ e . target . selectedIndex ] . value ) ;
e . data . set _value ( e . data . date . valueOf ( ) ) ;
}
} ) ;
node . append ( ":" ) ;
this . input _minutes = $j ( document . createElement ( "select" ) ) ;
for ( var i = 0 ; i < 60 ; i += 5 )
{
2011-08-31 22:32:24 +02:00
var time = i ;
if ( time < 10 )
{
time = "0" + time ;
}
var option = $j ( document . createElement ( "option" ) ) . attr ( "value" , time ) . text ( time ) ;
2011-08-31 21:58:38 +02:00
option . appendTo ( this . input _minutes ) ;
}
this . input _minutes . appendTo ( node ) . change ( this , function ( e ) {
if ( e . data . type == "date-timeonly" )
{
e . data . set _value ( $j ( 'option:selected' , e . data . input _hours ) . val ( ) + ":" + e . target . options [ e . target . selectedIndex ] . text ) ;
}
else
{
e . data . date . setMinutes ( e . target . options [ e . target . selectedIndex ] . value ) ;
e . data . set _value ( e . data . date . valueOf ( ) ) ;
}
} ) ;
} ,
2011-08-22 20:18:29 +02:00
set _type : function ( _type ) {
this . type = _type ;
this . createInputWidget ( ) ;
} ,
set _value : function ( _value ) {
2011-08-31 21:58:38 +02:00
// Handle just time as a string in the form H:i
2011-08-22 20:18:29 +02:00
if ( typeof _value == 'string' && isNaN ( _value ) ) {
2011-08-29 23:15:53 +02:00
if ( _value . indexOf ( ":" ) > 0 && this . type == "date-timeonly" ) {
2011-08-31 21:58:38 +02:00
this . value = _value ;
// HTML5
if ( ! this . input _hours )
{
return this . _super . apply ( this , [ _value ] ) ;
}
else
{
var parts = _value . split ( ":" ) ;
$j ( "option[value='" + parts [ 0 ] + "']" , this . input _hours ) . attr ( "selected" , "selected" ) ;
if ( $j ( "option[value='" + parseInt ( parts [ 1 ] ) + "']" , this . input _minutes ) . length == 0 )
{
// Selected an option that isn't in the list
2011-08-31 22:32:24 +02:00
var i = parseInt ( parts [ 1 ] ) ;
2011-08-31 21:58:38 +02:00
var option = $j ( document . createElement ( "option" ) ) . attr ( "value" , i ) . text ( i < 10 ? "0" + i : i ) . attr ( "selected" , "selected" ) ;
option . appendTo ( this . input _minutes ) ;
}
else
{
$j ( "option[value='" + parts [ 1 ] + "']" , this . input _minutes ) . attr ( "selected" , "selected" ) ;
}
return ;
}
2011-08-29 23:15:53 +02:00
} else {
_value = Date . parse ( _value ) ;
// JS dates use milliseconds
this . date . setTime ( parseInt ( _value ) * 1000 ) ;
}
2011-08-31 21:58:38 +02:00
} else if ( typeof _value == 'integer' ) {
2011-08-29 23:15:53 +02:00
// JS dates use milliseconds
this . date . setTime ( parseInt ( _value ) * 1000 ) ;
2011-08-31 21:58:38 +02:00
} else if ( typeof _value == 'object' && _value . date ) {
this . date = _value . date ;
_value = this . date . valueOf ( ) ;
2011-08-22 20:18:29 +02:00
}
this . value = _value ;
2011-08-31 21:58:38 +02:00
if ( this . input _date )
{
this . input _date . val ( date ( egw . preference ( 'dateformat' ) , this . date ) ) ;
}
if ( this . input _time )
{
this . input _time . val ( date ( "H:i" , this . date ) ) ;
}
if ( this . input _hours )
{
$j ( "option[value='" + date ( "H" , this . date ) + "']" , this . input _hours ) . attr ( "selected" , "selected" ) ;
}
if ( this . input _minutes )
{
if ( $j ( "option[value='" + parseInt ( date ( "i" , this . date ) ) + "']" , this . input _minutes ) . length == 0 )
{
// Selected an option that isn't in the list
var i = date ( "i" , this . date ) ;
2011-08-31 22:32:24 +02:00
var option = $j ( document . createElement ( "option" ) ) . attr ( "value" , i ) . text ( i ) . attr ( "selected" , "selected" ) ;
2011-08-31 21:58:38 +02:00
option . appendTo ( this . input _minutes ) ;
} else {
$j ( "option[value='" + date ( "i" , this . date ) + "']" , this . input _minutes ) . attr ( "selected" , "selected" ) ;
}
2011-08-22 20:18:29 +02:00
}
2011-08-31 02:08:59 +02:00
} ,
getValue : function ( ) {
return this . value ;
2011-08-22 20:18:29 +02:00
}
} ) ;
et2 _register _widget ( et2 _date , [ "date" , "date-time" , "date-timeonly" ] ) ;
2011-08-30 22:50:55 +02:00
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" ] ,
2011-09-08 19:11:49 +02:00
time _formats : { "d" : "d" , "h" : "h" , "m" : "m" } ,
2011-08-30 22:50:55 +02:00
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 ( "%" , "" ) ;
}
2011-09-08 19:11:49 +02:00
// Get translations
this . 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" )
} ,
2011-08-30 22:50:55 +02:00
this . createInputWidget ( ) ;
} ,
createInputWidget : function ( ) {
// Create nodes
this . node = $j ( document . createElement ( "span" ) ) ;
2011-08-31 21:58:38 +02:00
this . duration = $j ( document . createElement ( "input" ) ) . attr ( "size" , "2" ) ;
2011-08-30 22:50:55 +02:00
this . node . append ( this . duration ) ;
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 ++ ) {
2011-09-08 19:11:49 +02:00
this . format . append ( "<option value='" + this . options . display _format [ i ] + "'>" + this . time _formats [ this . options . display _format [ i ] ] + "</option>" ) ;
2011-08-30 22:50:55 +02:00
}
} else {
2011-09-08 19:11:49 +02:00
this . format = $j ( document . createElement ( "<span>" + this . time _formats [ this . options . display _format ] ) + "</span>" ) . appendTo ( this . node ) ;
2011-08-30 22:50:55 +02:00
}
} ,
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 ;
2011-09-08 19:11:49 +02:00
var display = this . _convert _to _display ( _value ) ;
// Set display
if ( this . duration [ 0 ] . nodeName == "INPUT" )
{
this . duration . val ( display . value ) ;
}
else
{
this . duration . text ( display . value + " " ) ;
}
// Set unit as figured for display
if ( display . unit != this . options . display _format )
{
if ( this . format . children ( ) . length > 1 ) {
$j ( "option[value='" + display . unit + "']" , this . format ) . attr ( 'selected' , 'selected' ) ;
}
else
{
this . format . text ( this . time _formats [ display . unit ] ) ;
}
}
} ,
/ * *
* Converts the value in data format into value in display format .
*
* @ param _value int / float Data in data format
*
* @ return Object { value : Value in display format , unit : unit for display }
* /
_convert _to _display : function ( _value ) {
2011-08-30 22:50:55 +02:00
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 ) ;
}
2011-09-08 19:11:49 +02:00
return { value : _value , unit : _unit } ;
2011-08-30 22:50:55 +02:00
} ,
/ * *
* Change displayed value into storage value and return
* /
getValue : function ( ) {
2011-08-31 02:08:59 +02:00
var value = this . duration . val ( ) ;
2011-08-30 22:50:55 +02:00
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" ] ) ;
2011-09-08 19:11:49 +02:00
var et2 _date _duration _ro = et2 _date _duration . extend ( {
createInputWidget : function ( ) {
this . node = $j ( document . createElement ( "span" ) ) ;
var display = this . _convert _to _display ( this . options . value ) ;
this . duration = $j ( document . createElement ( "span" ) ) . appendTo ( this . node ) ;
this . format = $j ( document . createElement ( "span" ) ) . appendTo ( this . node ) ;
} ,
/ * *
* Code for implementing et2 _IDetachedDOM
* Fast - clonable read - only widget that only deals with DOM nodes , not the widget tree
* /
/ * *
* Build a list of attributes which can be set when working in the
* "detached" mode in the _attrs array which is provided
* by the calling code .
* /
getDetachedAttributes : function ( _attrs ) {
_attrs . push ( "value" ) ;
} ,
/ * *
* Returns an array of DOM nodes . The ( relativly ) same DOM - Nodes have to be
* passed to the "setDetachedAttributes" function in the same order .
* /
getDetachedNodes : function ( ) {
return [ this . duration [ 0 ] , this . format [ 0 ] ] ;
} ,
/ * *
* Sets the given associative attribute - > value array and applies the
* attributes to the given DOM - Node .
*
* @ param _nodes is an array of nodes which has to be in the same order as
* the nodes returned by "getDetachedNodes"
* @ param _values is an associative array which contains a subset of attributes
* returned by the "getDetachedAttributes" function and sets them to the
* given values .
* /
setDetachedAttributes : function ( _nodes , _values ) {
for ( var i = 0 ; i < _nodes . length ; i ++ ) {
// Clear the node
for ( var i = _node . childNodes . length - 1 ; i >= 0 ; i -- )
{
_node . removeChild ( _node . childNodes [ i ] ) ;
}
}
var display = this . _convert _to _display ( _values . value ) ;
_nodes [ 0 ] . appendChild ( document . createTextNode ( display . value ) ) ;
_nodes [ 1 ] . appendChild ( document . createTextNode ( display . unit ) ) ;
}
} ) ;
et2 _register _widget ( et2 _date _duration _ro , [ "date-duration_ro" ] ) ;
2011-08-22 20:18:29 +02:00
/ * *
2011-08-31 22:32:24 +02:00
* et2 _date _ro is the readonly implementation of some date widget .
2011-08-22 20:18:29 +02:00
* /
var et2 _date _ro = et2 _valueWidget . extend ( {
/ * *
* Ignore all more advanced attributes .
* /
attributes : {
"value" : {
"type" : "integer"
} ,
"type" : {
"ignore" : false
}
} ,
/ * *
* Internal container for working easily with dates
* /
date : new Date ( ) ,
init : function ( ) {
this . _super . apply ( this , arguments ) ;
this . value = "" ;
2011-08-30 22:50:55 +02:00
this . span = $j ( document . createElement ( this . type == "date-since" ? "span" : "time" ) )
2011-08-29 23:15:53 +02:00
. addClass ( "et2_date_ro et2_label" ) ;
2011-08-22 20:18:29 +02:00
this . setDOMNode ( this . span [ 0 ] ) ;
} ,
set _value : function ( _value ) {
this . value = _value ;
// JS dates use milliseconds
this . date . setTime ( parseInt ( _value ) * 1000 ) ;
var display = this . date . toString ( ) ;
// TODO: Use user's preference, not browser's locale
switch ( this . type ) {
case "date" :
2011-08-29 23:15:53 +02:00
display = date ( egw . preference ( 'dateformat' ) , this . date ) ;
2011-08-22 20:18:29 +02:00
break ;
2011-08-29 23:15:53 +02:00
case "date-timeonly" :
display = date ( egw . preference ( 'timeformat' ) == '24' ? 'H:i' : 'g:i a' , this . date ) ;
2011-08-22 20:18:29 +02:00
break ;
case "date-time" :
2011-08-29 23:15:53 +02:00
display = date ( egw . preference ( 'dateformat' ) + " " +
( egw . preference ( 'timeformat' ) == '24' ? 'H:i' : 'g:i a' ) , this . date ) ;
2011-08-30 22:50:55 +02:00
break ;
case "date-since" :
var unit2label = {
'Y' : 'years' ,
'm' : 'month' ,
'd' : 'days' ,
'H' : 'hours' ,
'i' : 'minutes' ,
2011-09-02 18:23:26 +02:00
's' : 'seconds'
2011-08-30 22:50:55 +02:00
} ;
var unit2s = {
'Y' : 31536000 ,
'm' : 2628000 ,
'd' : 86400 ,
'H' : 3600 ,
'i' : 60 ,
2011-09-02 18:23:26 +02:00
's' : 1
2011-08-30 22:50:55 +02:00
} ;
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
2011-08-22 20:18:29 +02:00
}
2011-08-29 23:15:53 +02:00
this . span . attr ( "datetime" , date ( "Y-m-d H:i:s" , this . date ) ) . text ( display ) ;
2011-08-22 20:18:29 +02:00
}
} ) ;
2011-08-30 22:50:55 +02:00
et2 _register _widget ( et2 _date _ro , [ "date_ro" , "date-time_ro" , "date-since" ] ) ;
2011-08-22 20:18:29 +02:00
2011-08-31 22:32:24 +02:00
var et2 _date _timeonly _ro = et2 _date _ro . extend ( {
attributes : {
"value" : {
"type" : "string"
}
} ,
set _value : function ( _value ) {
if ( egw . preference ( "timeformat" ) == "12" && _value . indexOf ( ":" ) > 0 ) {
var parts = _value . split ( ":" ) ;
if ( parts [ 0 ] >= 12 ) {
this . span . text ( ( parts [ 0 ] == "12" ? "12" : parseInt ( parts [ 0 ] ) - 12 ) + ":" + parts [ 1 ] + " pm" ) ;
}
else
{
this . span . text ( _value + " am" ) ;
}
}
else
{
this . span . text ( _value ) ;
}
}
} ) ;
et2 _register _widget ( et2 _date _timeonly _ro , [ "date-timeonly_ro" ] ) ;