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.
11 // | There are only two ways to violate the license:
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).
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).
21 // | This license applies to this document only, not any other software
22 // | that it may be combined with.
24 // +----------------------------------------------------------------------+
26 // | https://www.anuko.com/time_tracker/credits.htm
27 // +----------------------------------------------------------------------+
29 import('form.TextField');
30 import('DateAndTime');
32 class DateField extends TextField {
33 var $mWeekStartDay = 0;
34 var $mDateFormat = "d/m/Y";
35 var $lToday = "Today";
38 var $cClassName = "DateField";
40 var $lCalendarButtons = array('today'=>'Today', 'close'=>'Close');
42 function DateField($name) {
44 $this->mDateObj = new DateAndTime();
46 if (isset($GLOBALS["I18N"])) {
47 $this->setLocalization($GLOBALS["I18N"]);
51 function setLocalization($i18n) {
54 FormElement::setLocalization($i18n);
55 $this->mDateObj->setFormat($user->date_format);
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');
63 $this->mDateFormat = $user->date_format;
64 $this->mWeekStartDay = $user->week_start;
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); //?
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);
84 function toStringControl() {
85 if (!$this->isRenderable()) return "";
87 if (!$this->isEnable()) {
88 $html = htmlspecialchars($this->getValue()).
89 "<input type=\"hidden\" name=\"$this->mName\" value=\"".htmlspecialchars($this->getValue())."\">\n";
92 if ($this->mId=="") $this->mId = $this->mName;
96 // http://www.nsftools.com/tips/JavaScriptTips.htm#datepicker
100 .dpTable {font-family: Tahoma, Arial, Helvetica, sans-serif; font-size: 12px; text-align: center; color: #505050; background-color: #ece9d8; border: 1px solid #AAAAAA;}
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;}
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;}
118 var datePickerDivID = \"datepicker\";
119 var iFrameDivID = \"datepickeriframe\";
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)."');
128 var defaultDateSeparator = \"".$this->mDateFormat[1]."\";
129 var defaultDateFormat = \"".$this->mDateFormat."\";
130 var dateSeparator = defaultDateSeparator;
131 var dateFormat = defaultDateFormat;
132 var startWeek = ".$this->mWeekStartDay.";
137 function getStartWeekDayNumber(date) {
138 var res = date.getDay() - startWeek;
145 function displayDatePicker(dateFieldName, displayBelowThisObject, dtFormat, dtSep) {
146 var targetDateField = document.getElementsByName(dateFieldName).item(0);
148 if (!displayBelowThisObject) displayBelowThisObject = targetDateField;
150 dateSeparator = dtSep;
152 dateSeparator = defaultDateSeparator;
155 dateFormat = dtFormat;
157 dateFormat = defaultDateFormat;
159 var x = displayBelowThisObject.offsetLeft;
160 var y = displayBelowThisObject.offsetTop + displayBelowThisObject.offsetHeight ;
162 var parent = displayBelowThisObject;
163 while (parent.offsetParent) {
164 parent = parent.offsetParent;
165 x += parent.offsetLeft;
166 y += parent.offsetTop ;
169 drawDatePicker(targetDateField, x, y);
171 function drawDatePicker(targetDateField, x, y) {
172 var dt = getFieldDate(targetDateField.value );
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);
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;
190 refreshDatePicker(targetDateField.name, dt.getFullYear(), dt.getMonth(), dt.getDate());
192 function refreshDatePicker(dateFieldName, year, month, day) {
193 var thisDay = new Date();
195 if ((month >= 0) && (year > 0)) {
196 thisDay = new Date(year, month, 1);
198 day = thisDay.getDate();
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>\";
223 html += TR_title + '<td colspan=7>';
224 html += '<table width=\"250\">'+ TR_title;
225 html += TD_buttons + getButtonCodeYear(dateFieldName, thisDay, -1, \"<<\") + getButtonCode(dateFieldName, thisDay, -1, \"<\") + xTD;
226 html += TD_title + DIV_title + monthArrayLong[ thisDay.getMonth()] + \" \" + thisDay.getFullYear() + xDIV + xTD;
227 html += TD_buttons + getButtonCode(dateFieldName, thisDay, 1, \">\") + getButtonCodeYear(dateFieldName, thisDay, 1, \">>\") + xTD;
228 html += xTR + '</table>' + xTD;
232 for(i = 0; i < dayArrayShort.length; i++)
233 html += TD_days + dayArrayShort[(i + startWeek) % 7] + xTD;
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 + \" \" + xTD;
244 dayNum = thisDay.getDate();
245 TD_onclick = \" onclick=\\\"updateDateField('\" + dateFieldName + \"', '\" + getDateString(thisDay) + \"');\\\">\";
248 html += TD_selected + TD_onclick + DIV_selected + dayNum + xDIV + xTD;
250 html += TD + TD_onclick + dayNum + xTD;
252 var startD = getStartWeekDayNumber(thisDay);
257 thisDay.setDate(thisDay.getDate() + 1);
258 } while (thisDay.getDate() > 1)
260 var startD = getStartWeekDayNumber(thisDay);
262 for (i = 6; i >= startD; i--) {
263 html += TD + \" \" + xTD;
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>\";
277 document.getElementById(datePickerDivID).innerHTML = html;
282 function getButtonCode(dateFieldName, dateVal, adjust, label) {
283 var newMonth = (dateVal.getMonth () + adjust) % 12;
284 var newYear = dateVal.getFullYear() + parseInt((dateVal.getMonth() + adjust) / 12);
290 return \"<button class='dpButton' onClick='refreshDatePicker(\\\"\" + dateFieldName + \"\\\", \" + newYear + \", \" + newMonth + \");'>\" + label + \"</button>\";
293 function getButtonCodeYear(dateFieldName, dateVal, adjust, label) {
294 var newMonth = dateVal.getMonth();
295 var newYear = dateVal.getFullYear() + adjust;
297 return \"<button class='dpButton' onClick='refreshDatePicker(\\\"\" + dateFieldName + \"\\\", \" + newYear + \", \" + newMonth + \");'>\" + label + \"</button>\";
301 function getDateString(dateVal) {\n";
302 if (isset($GLOBALS['i18n'])) {
303 $html .= "dateVal.locale = \"".$GLOBALS['i18n']->lang."\";\n";
305 $html .= "return dateVal.strftime(dateFormat);
308 function getFieldDate(dateString) {
310 var dateVal = strptime(dateString, dateFormat);
312 dateVal = new Date();
314 if (dateVal == null) {
315 dateVal = new Date();
320 function splitDateString(dateString) {
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(\"\\\\\");
336 function updateDateField(dateFieldName, dateString) {
337 var targetDateField = document.getElementsByName(dateFieldName).item(0);
339 targetDateField.value = dateString;
341 var pickerDiv = document.getElementById(datePickerDivID);
342 pickerDiv.style.visibility = \"hidden\";
343 pickerDiv.style.display = \"none\";
346 targetDateField.focus();
348 if ((dateString) && (typeof(datePickerClosed) == \"function\"))
349 datePickerClosed(targetDateField);
352 function updateDateFieldOnly(dateFieldName, dateString) {
353 var targetDateField = document.getElementsByName(dateFieldName).item(0);
355 targetDateField.value = dateString;
358 function adjustiFrame(pickerDiv, iFrameDiv) {
359 var is_opera = (navigator.userAgent.toLowerCase().indexOf(\"opera\") != -1);
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);
374 pickerDiv = document.getElementById(datePickerDivID);
376 iFrameDiv = document.getElementById(iFrameDivID);
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;
393 $html .= "</script>\n";
395 $html .= "\n\t<input type=\"text\"";
396 $html .= " name=\"$this->mName\" id=\"$this->mId\"";
398 if ($this->mSize!="")
399 $html .= " size=\"$this->mSize\"";
401 if ($this->mStyle!="")
402 $html .= " style=\"$this->mStyle\"";
404 $html .= " maxlength=\"50\"";
406 if ($this->mOnChange!="")
407 $html .= " onchange=\"$this->mOnChange\"";
409 if ($this->mOnBlur!="")
410 $html .= " onblur=\"$this->mOnBlur\"";
412 if ($this->mOnClick!="")
413 $html .= " onclick=\"$this->mOnClick\"";
415 if ($this->mOnFocus!="")
416 $html .= " onfocus=\"$this->mOnFocus\"";
418 $html .= " value=\"".htmlspecialchars($this->getValue())."\"";
422 $app_root = '/'.APP_NAME;
424 $html .= " <img src=\"".$app_root."/images/calendar.gif\" width=\"16\" height=\"16\" onclick=\"displayDatePicker('".$this->mName."');\">\n";