Initial implementation of a mobile timer page
[timetracker.git] / WEB-INF / lib / form / DateField.class.php
1 <?php
2 // +----------------------------------------------------------------------+
3 // | Anuko Time Tracker
4 // +----------------------------------------------------------------------+
5 // | Copyright (c) Anuko International Ltd. (https://www.anuko.com)
6 // +----------------------------------------------------------------------+
7 // | LIBERAL FREEWARE LICENSE: This source code document may be used
8 // | by anyone for any purpose, and freely redistributed alone or in
9 // | combination with other software, provided that the license is obeyed.
10 // |
11 // | There are only two ways to violate the license:
12 // |
13 // | 1. To redistribute this code in source form, with the copyright
14 // |    notice or license removed or altered. (Distributing in compiled
15 // |    forms without embedded copyright notices is permitted).
16 // |
17 // | 2. To redistribute modified versions of this code in *any* form
18 // |    that bears insufficient indications that the modifications are
19 // |    not the work of the original author(s).
20 // |
21 // | This license applies to this document only, not any other software
22 // | that it may be combined with.
23 // |
24 // +----------------------------------------------------------------------+
25 // | Contributors:
26 // | https://www.anuko.com/time_tracker/credits.htm
27 // +----------------------------------------------------------------------+
28
29 import('form.TextField');
30 import('DateAndTime');
31
32 class DateField extends TextField {
33   var $mWeekStartDay = 0;
34   var $mDateFormat  = "d/m/Y";
35   var $lToday      = "Today";
36
37   var $mDateObj;
38   var $cClassName  = "DateField";
39
40   var $lCalendarButtons = array('today'=>'Today', 'close'=>'Close');
41
42   function DateField($name) {
43     $this->mName  = $name;
44     $this->mDateObj  = new DateAndTime();
45
46     if (isset($GLOBALS["I18N"])) {
47       $this->setLocalization($GLOBALS["I18N"]);
48     }
49   }
50
51   function setLocalization($i18n)  {
52         global $user;
53         
54     FormElement::setLocalization($i18n);
55     $this->mDateObj->setFormat($user->date_format);
56
57     $this->mMonthNames = $i18n->monthNames;
58     $this->mWeekDayShortNames = $i18n->weekdayShortNames;
59     $this->lToday = $i18n->getKey('label.today');
60     $this->lCalendarButtons['today'] = $i18n->getKey('label.today');
61     $this->lCalendarButtons['close'] = $i18n->getKey('button.close');
62
63     $this->mDateFormat = $user->date_format;
64     $this->mWeekStartDay = $user->week_start;
65   }
66
67   // set current value taken from session or database
68   function setValueSafe($value)  {
69     if (isset($value) && (strlen($value) > 0)) {
70       $this->mDateObj->parseVal($value, DB_DATEFORMAT);
71       $this->mValue = $this->mDateObj->toString($this->mDateFormat); //?
72     }
73   }
74   // get value for storing in session or database
75   function getValueSafe() {
76     if (strlen($this->mValue)>0) {
77       $this->mDateObj->parseVal($this->mValue, $this->mDateFormat);  //?
78       return $this->mDateObj->toString(DB_DATEFORMAT);
79     } else {
80       return null;
81     }
82   }
83
84   function toStringControl()  {
85     if (!$this->isRenderable()) return "";
86
87     if (!$this->isEnable()) {
88       $html = htmlspecialchars($this->getValue()).
89         "<input type=\"hidden\" name=\"$this->mName\" value=\"".htmlspecialchars($this->getValue())."\">\n";
90     } else {
91
92         if ($this->mId=="") $this->mId = $this->mName;
93
94       $html = "";
95
96       // http://www.nsftools.com/tips/JavaScriptTips.htm#datepicker
97
98       $html .= "<style>
99             .dpDiv {}
100             .dpTable {font-family: Tahoma, Arial, Helvetica, sans-serif; font-size: 12px; text-align: center; color: #505050; background-color: #ece9d8; border: 1px solid #AAAAAA;}
101             .dpTR {}
102             .dpTitleTR {}
103             .dpDayTR {}
104             .dpTodayButtonTR {}
105             .dpTD {border: 1px solid #ece9d8;}
106             .dpDayHighlightTD {background-color: #CCCCCC;border: 1px solid #AAAAAA;}
107             .dpTDHover {background-color: #aca998;border: 1px solid #888888;cursor: pointer;color: red;}
108             .dpTitleTD {}
109             .dpButtonTD {}
110             .dpTodayButtonTD {}
111             .dpDayTD {background-color: #CCCCCC;border: 1px solid #AAAAAA;color: white;}
112             .dpTitleText {font-size: 12px;color: gray;font-weight: bold;}
113             .dpDayHighlight {color: 4060ff;font-weight: bold;}
114             .dpButton {font-family: Verdana, Tahoma, Arial, Helvetica, sans-serif;font-size: 10px;color: gray;background: #d8e8ff;font-weight: bold;padding: 0px;}
115             .dpTodayButton {font-family: Verdana, Tahoma, Arial, Helvetica, sans-serif;font-size: 10px;color: gray;  background: #d8e8ff;font-weight: bold;}
116             </style>\n";
117       $html .= "<script>
118             var datePickerDivID = \"datepicker\";
119             var iFrameDivID = \"datepickeriframe\";
120
121             var dayArrayShort = new Array('".join("','",$this->mWeekDayShortNames)."');
122             var dayArrayMed = new Array('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat');
123             var dayArrayLong = new Array('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday');
124             var monthArrayShort = new Array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec');
125             var monthArrayMed = new Array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'June', 'July', 'Aug', 'Sept', 'Oct', 'Nov', 'Dec');
126             var monthArrayLong = new Array('".join("','",$this->mMonthNames)."');
127
128             var defaultDateSeparator = \"".$this->mDateFormat[1]."\";
129             var defaultDateFormat = \"".$this->mDateFormat."\";
130             var dateSeparator = defaultDateSeparator;
131             var dateFormat = defaultDateFormat;
132             var startWeek = ".$this->mWeekStartDay.";
133
134           ";
135       $html .= "
136
137             function getStartWeekDayNumber(date) {
138               var res = date.getDay() - startWeek;
139               if (res < 0) {
140                 res += 7;
141               }
142               return res;
143             }
144
145             function displayDatePicker(dateFieldName, displayBelowThisObject, dtFormat, dtSep) {
146               var targetDateField = document.getElementsByName(dateFieldName).item(0);
147
148               if (!displayBelowThisObject) displayBelowThisObject = targetDateField;
149               if (dtSep)
150                 dateSeparator = dtSep;
151               else
152                 dateSeparator = defaultDateSeparator;
153
154               if (dtFormat)
155                 dateFormat = dtFormat;
156               else
157                 dateFormat = defaultDateFormat;
158
159               var x = displayBelowThisObject.offsetLeft;
160               var y = displayBelowThisObject.offsetTop + displayBelowThisObject.offsetHeight ;
161
162               var parent = displayBelowThisObject;
163               while (parent.offsetParent) {
164                 parent = parent.offsetParent;
165                 x += parent.offsetLeft;
166                 y += parent.offsetTop ;
167               }
168
169               drawDatePicker(targetDateField, x, y);
170             }
171             function drawDatePicker(targetDateField, x, y) {
172               var dt = getFieldDate(targetDateField.value );
173
174               if (!document.getElementById(datePickerDivID)) {
175                 var newNode = document.createElement(\"div\");
176                 newNode.setAttribute(\"id\", datePickerDivID);
177                 newNode.setAttribute(\"class\", \"dpDiv\");
178                 newNode.setAttribute(\"style\", \"visibility: hidden;\");
179                 document.body.appendChild(newNode);
180               }
181
182               var pickerDiv = document.getElementById(datePickerDivID);
183               pickerDiv.style.position = \"absolute\";
184               pickerDiv.style.left = x + \"px\";
185               pickerDiv.style.top = (y + 3) + \"px\";
186               pickerDiv.style.visibility = (pickerDiv.style.visibility == \"visible\" ? \"hidden\" : \"visible\");
187               pickerDiv.style.display = (pickerDiv.style.display == \"block\" ? \"none\" : \"block\");
188               pickerDiv.style.zIndex = 10000;
189
190               refreshDatePicker(targetDateField.name, dt.getFullYear(), dt.getMonth(), dt.getDate());
191             }
192             function refreshDatePicker(dateFieldName, year, month, day) {
193               var thisDay = new Date();
194
195               if ((month >= 0) && (year > 0)) {
196                 thisDay = new Date(year, month, 1);
197               } else {
198                 day = thisDay.getDate();
199                 thisDay.setDate(1);
200               }
201
202               var crlf = \"\\r\\n\";
203               var TABLE = \"<table cols=7 class='dpTable'>\" + crlf;
204               var xTABLE = \"</table>\" + crlf;
205               var TR = \"<tr class='dpTR'>\";
206               var TR_title = \"<tr class='dpTitleTR' width='150' align='center'>\";
207               var TR_days = \"<tr class='dpDayTR'>\";
208               var TR_todaybutton = \"<tr class='dpTodayButtonTR'>\";
209               var xTR = \"</tr>\" + crlf;
210               var TD = \"<td class='dpTD' onMouseOut='this.className=\\\"dpTD\\\";' onMouseOver=' this.className=\\\"dpTDHover\\\";' \";
211               var TD_title = \"<td colspan=5 class='dpTitleTD'>\";
212               var TD_buttons = \"<td class='dpButtonTD' width='50'>\";
213               var TD_todaybutton = \"<td colspan=7 class='dpTodayButtonTD'>\";
214               var TD_days = \"<td class='dpDayTD'>\";
215               var TD_selected = \"<td class='dpDayHighlightTD' onMouseOut='this.className=\\\"dpDayHighlightTD\\\";' onMouseOver='this.className=\\\"dpTDHover\\\";' \";
216               var xTD = \"</td>\" + crlf;
217               var DIV_title = \"<div class='dpTitleText'>\";
218               var DIV_selected = \"<div class='dpDayHighlight'>\";
219               var xDIV = \"</div>\";
220
221               var html = TABLE;
222
223               html += TR_title + '<td colspan=7>';
224               html += '<table width=\"250\">'+ TR_title;
225               html += TD_buttons + getButtonCodeYear(dateFieldName, thisDay, -1, \"&lt;&lt;\") + getButtonCode(dateFieldName, thisDay, -1, \"&lt;\") + xTD;
226               html += TD_title + DIV_title + monthArrayLong[ thisDay.getMonth()] + \" \" + thisDay.getFullYear() + xDIV + xTD;
227               html += TD_buttons + getButtonCode(dateFieldName, thisDay, 1, \"&gt;\") + getButtonCodeYear(dateFieldName, thisDay, 1, \"&gt;&gt;\") + xTD;
228               html += xTR + '</table>' + xTD;
229               html += xTR;
230
231               html += TR_days;
232               for(i = 0; i < dayArrayShort.length; i++)
233                 html += TD_days + dayArrayShort[(i + startWeek) % 7] + xTD;
234               html += xTR;
235
236               html += TR;
237
238               //var startD = (thisDay.getDay()-startWeek<0?6:thisDay.getDay()-startWeek);
239               var startD = getStartWeekDayNumber(thisDay);
240               for (i = 0; i < startD; i++)
241                 html += TD + \"&nbsp;\" + xTD;
242
243               do {
244                 dayNum = thisDay.getDate();
245                 TD_onclick = \" onclick=\\\"updateDateField('\" + dateFieldName + \"', '\" + getDateString(thisDay) + \"');\\\">\";
246
247                 if (dayNum == day)
248                   html += TD_selected + TD_onclick + DIV_selected + dayNum + xDIV + xTD;
249                 else
250                   html += TD + TD_onclick + dayNum + xTD;
251
252                 var startD = getStartWeekDayNumber(thisDay);
253
254                 if (startD == 6)
255                   html += xTR + TR;
256
257                 thisDay.setDate(thisDay.getDate() + 1);
258               } while (thisDay.getDate() > 1)
259
260               var startD = getStartWeekDayNumber(thisDay);
261               if (startD > 0) {
262                 for (i = 6; i >= startD; i--) {
263                   html += TD + \"&nbsp;\" + xTD;
264                 }
265               }              
266               html += xTR;
267
268               var today = new Date();
269               var todayString = \"Today is \" + dayArrayMed[today.getDay()] + \", \" + monthArrayMed[ today.getMonth()] + \" \" + today.getDate();
270               html += TR_todaybutton + TD_todaybutton;
271               html += \"<button class='dpTodayButton' onClick=\\\"refreshDatePicker('\" + dateFieldName + \"'); updateDateFieldOnly('\" + dateFieldName + \"', '\" + getDateString(new Date()) + \"');\\\">".$this->lCalendarButtons['today']."</button> \";
272               html += \"<button class='dpTodayButton' onClick='updateDateField(\\\"\" + dateFieldName + \"\\\");'>".$this->lCalendarButtons['close']."</button>\";
273               html += xTD + xTR;
274
275               html += xTABLE;
276
277               document.getElementById(datePickerDivID).innerHTML = html;
278               adjustiFrame();
279             }
280
281
282             function getButtonCode(dateFieldName, dateVal, adjust, label) {
283               var newMonth = (dateVal.getMonth () + adjust) % 12;
284               var newYear = dateVal.getFullYear() + parseInt((dateVal.getMonth() + adjust) / 12);
285               if (newMonth < 0) {
286                 newMonth += 12;
287                 newYear += -1;
288               }
289
290               return \"<button class='dpButton' onClick='refreshDatePicker(\\\"\" + dateFieldName + \"\\\", \" + newYear + \", \" + newMonth + \");'>\" + label + \"</button>\";
291             }
292
293             function getButtonCodeYear(dateFieldName, dateVal, adjust, label) {
294               var newMonth = dateVal.getMonth();
295               var newYear = dateVal.getFullYear() + adjust;
296
297               return \"<button class='dpButton' onClick='refreshDatePicker(\\\"\" + dateFieldName + \"\\\", \" + newYear + \", \" + newMonth + \");'>\" + label + \"</button>\";
298             }
299
300
301             function getDateString(dateVal) {\n";
302             if (isset($GLOBALS['i18n'])) {
303               $html .= "dateVal.locale = \"".$GLOBALS['i18n']->lang."\";\n";
304             }
305             $html .=  "return dateVal.strftime(dateFormat);
306             }
307
308             function getFieldDate(dateString) {
309               try {
310                 var dateVal = strptime(dateString, dateFormat);
311               } catch(e) {
312                 dateVal = new Date();
313               }
314               if (dateVal == null) {
315                 dateVal = new Date();
316               }
317               return dateVal;
318             }
319
320             function splitDateString(dateString) {
321               var dArray;
322               if (dateString.indexOf(\"/\") >= 0)
323                 dArray = dateString.split(\"/\");
324               else if (dateString.indexOf(\".\") >= 0)
325                 dArray = dateString.split(\".\");
326               else if (dateString.indexOf(\"-\") >= 0)
327                 dArray = dateString.split(\"-\");
328               else if (dateString.indexOf(\"\\\\\") >= 0)
329                 dArray = dateString.split(\"\\\\\");
330               else
331                 dArray = false;
332
333               return dArray;
334             }
335
336             function updateDateField(dateFieldName, dateString)  {
337               var targetDateField = document.getElementsByName(dateFieldName).item(0);
338               if (dateString)
339                 targetDateField.value = dateString;
340
341               var pickerDiv = document.getElementById(datePickerDivID);
342               pickerDiv.style.visibility = \"hidden\";
343               pickerDiv.style.display = \"none\";
344
345               adjustiFrame();
346               targetDateField.focus();
347
348               if ((dateString) && (typeof(datePickerClosed) == \"function\"))
349                 datePickerClosed(targetDateField);
350             }
351
352             function updateDateFieldOnly(dateFieldName, dateString)  {
353               var targetDateField = document.getElementsByName(dateFieldName).item(0);
354               if (dateString)
355                 targetDateField.value = dateString;
356             }
357
358             function adjustiFrame(pickerDiv, iFrameDiv) {
359               var is_opera = (navigator.userAgent.toLowerCase().indexOf(\"opera\") != -1);
360               if (is_opera)
361                 return;
362
363               try {
364                 if (!document.getElementById(iFrameDivID)) {
365                   var newNode = document.createElement(\"iFrame\");
366                   newNode.setAttribute(\"id\", iFrameDivID);
367                   newNode.setAttribute(\"src\", \"javascript:false;\");
368                   newNode.setAttribute(\"scrolling\", \"no\");
369                   newNode.setAttribute (\"frameborder\", \"0\");
370                   document.body.appendChild(newNode);
371                 }
372
373                 if (!pickerDiv)
374                   pickerDiv = document.getElementById(datePickerDivID);
375                 if (!iFrameDiv)
376                   iFrameDiv = document.getElementById(iFrameDivID);
377
378                 try {
379                   iFrameDiv.style.position = \"absolute\";
380                   iFrameDiv.style.width = pickerDiv.offsetWidth;
381                   iFrameDiv.style.height = pickerDiv.offsetHeight ;
382                   iFrameDiv.style.top = pickerDiv.style.top;
383                   iFrameDiv.style.left = pickerDiv.style.left;
384                   iFrameDiv.style.zIndex = pickerDiv.style.zIndex - 1;
385                   iFrameDiv.style.visibility = pickerDiv.style.visibility ;
386                   iFrameDiv.style.display = pickerDiv.style.display;
387                 } catch(e) {
388                 }
389
390               } catch (ee) {
391               }
392             }\n";
393       $html .= "</script>\n";
394
395       $html .= "\n\t<input type=\"text\"";
396       $html .= " name=\"$this->mName\" id=\"$this->mId\"";
397
398       if ($this->mSize!="")
399         $html .= " size=\"$this->mSize\"";
400
401       if ($this->mStyle!="")
402          $html .= " style=\"$this->mStyle\"";
403
404         $html .= " maxlength=\"50\"";
405
406       if ($this->mOnChange!="")
407          $html .= " onchange=\"$this->mOnChange\"";
408
409       if ($this->mOnBlur!="")
410          $html .= " onblur=\"$this->mOnBlur\"";
411
412       if ($this->mOnClick!="")
413          $html .= " onclick=\"$this->mOnClick\"";
414
415       if ($this->mOnFocus!="")
416          $html .= " onfocus=\"$this->mOnFocus\"";
417
418       $html .= " value=\"".htmlspecialchars($this->getValue())."\"";
419       $html .= ">";
420       
421       if (APP_NAME)
422         $app_root = '/'.APP_NAME;
423
424       $html .= "&nbsp;<img src=\"".$app_root."/images/calendar.gif\" width=\"16\" height=\"16\" onclick=\"displayDatePicker('".$this->mName."');\">\n";
425     }
426
427     return $html;
428   }
429 }