diff --git a/administrator/components/com_admin/script.php b/administrator/components/com_admin/script.php index 5c4fc2a73a68d..30931a3292157 100644 --- a/administrator/components/com_admin/script.php +++ b/administrator/components/com_admin/script.php @@ -1655,7 +1655,7 @@ public function deleteUnexistingFiles() '/libraries/simplepie', // Joomla! 3.6.3 '/media/editors/codemirror/mode/jade', - // Joomla __DEPLOY_VERSION__ + // Joomla! __DEPLOY_VERSION__ '/libraries/joomla/data', ); diff --git a/administrator/components/com_content/models/forms/article.xml b/administrator/components/com_content/models/forms/article.xml index fb46c6da6378d..c963551888a17 100644 --- a/administrator/components/com_content/models/forms/article.xml +++ b/administrator/components/com_content/models/forms/article.xml @@ -68,6 +68,7 @@ @@ -98,11 +99,11 @@ - section in form XML. + * @var boolean $hidden Is this field hidden in the form? + * @var string $hint Placeholder for the field. + * @var string $id DOM id of the field. + * @var string $label Label of the field. + * @var string $labelclass Classes to apply to the label. + * @var boolean $multiple Does this field support multiple values? + * @var string $name Name of the input field. + * @var string $onchange Onchange attribute for the field. + * @var string $onclick Onclick attribute for the field. + * @var string $pattern Pattern (Reg Ex) of value of the form field. + * @var boolean $readonly Is this field read only? + * @var boolean $repeat Allows extensions to duplicate elements. + * @var boolean $required Is this field required? + * @var integer $size Size attribute of the input. + * @var boolean $spellcheck Spellcheck state for the form field. + * @var string $validate Validation rules to apply. + * @var string $value Value attribute of the field. + * @var array $checkedOptions Options that will be set as checked. + * @var boolean $hasValue Has this field a value assigned? + * @var array $options Options available for this field. + * + * Calendar Specific + * @var string $localesPath The relative path for the locale file + * @var string $helperPath The relative path for the helper file + * @var string $minYear The minimum year, that will be subtracted/added to current year + * @var string $maxYear The maximum year, that will be subtracted/added to current year + * @var integer $todaybutton The today button + * @var integer $weeknumbers The week numbers display + * @var integer $showtime The time selector display + * @var integer $filltable The previous/next month filling + * @var integer $timeformat The time format + * @var integer $singleheader Display different header row for month/year + * @var integer $direction The document direction + */ + +$inputvalue = ''; + +// Build the attributes array. +$attributes = array(); + +empty($size) ? null : $attributes['size'] = $size; +empty($maxlength) ? null : $attributes['maxlength'] = ' maxlength="' . $maxLength . '"'; +empty($class) ? null : $attributes['class'] = $class; +!$readonly ? null : $attributes['readonly'] = 'readonly'; +!$disabled ? null : $attributes['disabled'] = 'disabled'; +empty($onchange) ? null : $attributes['onchange'] = $onchange; + +if ($required) +{ + $attributes['required'] = ''; + $attributes['aria-required'] = 'true'; +} + +// Handle the special case for "now". +if (strtoupper($value) == 'NOW') +{ + $value = JFactory::getDate()->format('Y-m-d H:i:s'); +} + +$readonly = isset($attributes['readonly']) && $attributes['readonly'] == 'readonly'; +$disabled = isset($attributes['disabled']) && $attributes['disabled'] == 'disabled'; + +if (is_array($attributes)) +{ + $attributes = ArrayHelper::toString($attributes); +} + +$cssFileExt = ($direction === 'rtl') ? '-rtl.css' : '.css'; + +// Load polyfills for older IE +JHtml::_('behavior.polyfill', array('event', 'classlist', 'map'), 'lte IE 11'); + +// The static assets for the calendar +JHtml::_('script', $localesPath, false, true, false, false, true); +JHtml::_('script', $helperPath, false, true, false, false, true); +JHtml::_('script', 'system/fields/calendar-vanilla.min.js', false, true, false, false, true); +JHtml::_('stylesheet', 'system/fields/calendar-vanilla' . $cssFileExt, array(), true); +?> +
+ +
+ + " + data-alt-value="" autocomplete="off"/> + + +
+ +
diff --git a/libraries/cms/html/behavior.php b/libraries/cms/html/behavior.php index 9a203decdbbcf..c9fc27d6e3fc8 100644 --- a/libraries/cms/html/behavior.php +++ b/libraries/cms/html/behavior.php @@ -561,31 +561,12 @@ public static function tree($id, $params = array(), $root = array()) * @return void * * @since 1.5 + * + * @deprecated 4.0 */ public static function calendar() { - // Only load once - if (isset(static::$loaded[__METHOD__])) - { - return; - } - - $document = JFactory::getDocument(); - $tag = JFactory::getLanguage()->getTag(); - $attribs = array('title' => JText::_('JLIB_HTML_BEHAVIOR_GREEN'), 'media' => 'all'); - - JHtml::_('stylesheet', 'system/calendar-jos.css', array('version' => 'auto', 'relative' => true), $attribs); - JHtml::_('script', $tag . '/calendar.js', array('version' => 'auto', 'relative' => true)); - JHtml::_('script', $tag . '/calendar-setup.js', array('version' => 'auto', 'relative' => true)); - - $translation = static::calendartranslation(); - - if ($translation) - { - $document->addScriptDeclaration($translation); - } - - static::$loaded[__METHOD__] = true; + JLog::add('JHtmlBehavior::calendar is deprecated as the static assets are being loaded in the relative layout.', JLog::WARNING, 'deprecated'); } /** @@ -851,95 +832,6 @@ protected static function _getJSObject($array = array()) return JHtml::getJSObject($array); } - /** - * Internal method to translate the JavaScript Calendar - * - * @return string JavaScript that translates the object - * - * @since 1.5 - */ - protected static function calendartranslation() - { - static $jsscript = 0; - - // Guard clause, avoids unnecessary nesting - if ($jsscript) - { - return false; - } - - $jsscript = 1; - - // To keep the code simple here, run strings through JText::_() using array_map() - $callback = array('JText', '_'); - $weekdays_full = array_map( - $callback, array( - 'SUNDAY', 'MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY', 'FRIDAY', 'SATURDAY', 'SUNDAY', - ) - ); - $weekdays_short = array_map( - $callback, - array( - 'SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT', 'SUN', - ) - ); - $months_long = array_map( - $callback, array( - 'JANUARY', 'FEBRUARY', 'MARCH', 'APRIL', 'MAY', 'JUNE', - 'JULY', 'AUGUST', 'SEPTEMBER', 'OCTOBER', 'NOVEMBER', 'DECEMBER', - ) - ); - $months_short = array_map( - $callback, array( - 'JANUARY_SHORT', 'FEBRUARY_SHORT', 'MARCH_SHORT', 'APRIL_SHORT', 'MAY_SHORT', 'JUNE_SHORT', - 'JULY_SHORT', 'AUGUST_SHORT', 'SEPTEMBER_SHORT', 'OCTOBER_SHORT', 'NOVEMBER_SHORT', 'DECEMBER_SHORT', - ) - ); - - // This will become an object in Javascript but define it first in PHP for readability - $today = " " . JText::_('JLIB_HTML_BEHAVIOR_TODAY') . " "; - $text = array( - 'INFO' => JText::_('JLIB_HTML_BEHAVIOR_ABOUT_THE_CALENDAR'), - 'ABOUT' => "DHTML Date/Time Selector\n" - . "(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" - . "For latest version visit: http://www.dynarch.com/projects/calendar/\n" - . "Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." - . "\n\n" - . JText::_('JLIB_HTML_BEHAVIOR_DATE_SELECTION') - . JText::_('JLIB_HTML_BEHAVIOR_YEAR_SELECT') - . JText::_('JLIB_HTML_BEHAVIOR_MONTH_SELECT') - . JText::_('JLIB_HTML_BEHAVIOR_HOLD_MOUSE'), - 'ABOUT_TIME' => "\n\n" - . "Time selection:\n" - . "- Click on any of the time parts to increase it\n" - . "- or Shift-click to decrease it\n" - . "- or click and drag for faster selection.", - 'PREV_YEAR' => JText::_('JLIB_HTML_BEHAVIOR_PREV_YEAR_HOLD_FOR_MENU'), - 'PREV_MONTH' => JText::_('JLIB_HTML_BEHAVIOR_PREV_MONTH_HOLD_FOR_MENU'), - 'GO_TODAY' => JText::_('JLIB_HTML_BEHAVIOR_GO_TODAY'), - 'NEXT_MONTH' => JText::_('JLIB_HTML_BEHAVIOR_NEXT_MONTH_HOLD_FOR_MENU'), - 'SEL_DATE' => JText::_('JLIB_HTML_BEHAVIOR_SELECT_DATE'), - 'DRAG_TO_MOVE' => JText::_('JLIB_HTML_BEHAVIOR_DRAG_TO_MOVE'), - 'PART_TODAY' => $today, - 'DAY_FIRST' => JText::_('JLIB_HTML_BEHAVIOR_DISPLAY_S_FIRST'), - 'WEEKEND' => JFactory::getLanguage()->getWeekEnd(), - 'CLOSE' => JText::_('JLIB_HTML_BEHAVIOR_CLOSE'), - 'TODAY' => JText::_('JLIB_HTML_BEHAVIOR_TODAY'), - 'TIME_PART' => JText::_('JLIB_HTML_BEHAVIOR_SHIFT_CLICK_OR_DRAG_TO_CHANGE_VALUE'), - 'DEF_DATE_FORMAT' => "%Y-%m-%d", - 'TT_DATE_FORMAT' => JText::_('JLIB_HTML_BEHAVIOR_TT_DATE_FORMAT'), - 'WK' => JText::_('JLIB_HTML_BEHAVIOR_WK'), - 'TIME' => JText::_('JLIB_HTML_BEHAVIOR_TIME'), - ); - - return 'Calendar._DN = ' . json_encode($weekdays_full) . ';' - . ' Calendar._SDN = ' . json_encode($weekdays_short) . ';' - . ' Calendar._FD = 0;' - . ' Calendar._MN = ' . json_encode($months_long) . ';' - . ' Calendar._SMN = ' . json_encode($months_short) . ';' - . ' Calendar._TT = ' . json_encode($text) . ';'; - } - /** * Add unobtrusive JavaScript support to keep a tab state. * diff --git a/libraries/cms/html/html.php b/libraries/cms/html/html.php index 12b8c8c1e1d2d..d5c52c7810507 100644 --- a/libraries/cms/html/html.php +++ b/libraries/cms/html/html.php @@ -777,7 +777,7 @@ public static function date($input = 'now', $format = null, $tz = true, $gregori { // Get some system objects. $config = JFactory::getConfig(); - $user = JFactory::getUser(); + $user = JFactory::getUser(); // UTC date converted to user time zone. if ($tz === true) @@ -974,32 +974,58 @@ public static function tooltipText($title = '', $content = '', $translate = true * @param string $id The id of the text field * @param string $format The date format * @param mixed $attribs Additional HTML attributes + * The array can have the following keys: + * readonly Sets the readonly parameter for the input tag + * disabled Sets the disabled parameter for the input tag + * autofocus Sets the autofocus parameter for the input tag + * autocomplete Sets the autocomplete parameter for the input tag + * filter Sets the filter for the input tag * * @return string HTML markup for a calendar field * * @since 1.5 + * */ - public static function calendar($value, $name, $id, $format = '%Y-%m-%d', $attribs = null) + public static function calendar($value, $name, $id, $format = '%Y-%m-%d', $attribs = array()) { - static $done; + $tag = JFactory::getLanguage()->getTag(); + $calendar = JFactory::getLanguage()->getCalendar(); + $direction = strtolower(JFactory::getDocument()->getDirection()); + + // Get the appropriate file for the current language date helper + $helperPath = 'system/fields/calendar-locales/date/gregorian/date-helper.min.js'; - if ($done === null) + if (!empty($calendar) && is_dir(JPATH_ROOT . '/media/system/js/fields/calendar-locales/date/' . strtolower($calendar))) { - $done = array(); + $helperPath = 'system/fields/calendar-locales/date/' . strtolower($calendar) . '/date-helper.min.js'; } - $readonly = isset($attribs['readonly']) && $attribs['readonly'] == 'readonly'; - $disabled = isset($attribs['disabled']) && $attribs['disabled'] == 'disabled'; + // Get the appropriate locale file for the current language + $localesPath = 'system/fields/calendar-locales/en.js'; - if (is_array($attribs)) + if (is_file(JPATH_ROOT . '/media/system/js/fields/calendar-locales/' . strtolower($tag) . '.js')) { - $attribs['class'] = isset($attribs['class']) ? $attribs['class'] : 'input-medium'; - $attribs['class'] = trim($attribs['class'] . ' hasTooltip'); - - $attribs = ArrayHelper::toString($attribs); + $localesPath = 'system/fields/calendar-locales/' . strtolower($tag) . '.js'; + } + elseif (is_file(JPATH_ROOT . '/media/system/js/fields/calendar-locales/' . strtolower(substr($tag, 0, -3)) . '.js')) + { + $localesPath = 'system/fields/calendar-locales/' . strtolower(substr($tag, 0, -3)) . '.js'; } - static::_('bootstrap.tooltip'); + $readonly = isset($attribs['readonly']) && $attribs['readonly'] == 'readonly'; + $disabled = isset($attribs['disabled']) && $attribs['disabled'] == 'disabled'; + $autocomplete = isset($attribs['autocomplete']) && $attribs['autocomplete'] == ''; + $autofocus = isset($attribs['autofocus']) && $attribs['autofocus'] == ''; + $required = isset($attribs['required']) && $attribs['required'] == ''; + $filter = isset($attribs['filter']) && $attribs['filter'] == ''; + $todayBtn = isset($attribs['todayBtn']) ? $attribs['todayBtn'] : true; + $weekNumbers = isset($attribs['weekNumbers']) ? $attribs['weekNumbers'] : false; + $showTime = isset($attribs['showTime']) ? $attribs['showTime'] : true; + $fillTable = isset($attribs['fillTable']) ? $attribs['fillTable'] : true; + $timeFormat = isset($attribs['timeFormat']) ? $attribs['timeFormat'] : 24; + $singleHeader = isset($attribs['singleHeader']) ? $attribs['singleHeader'] : false; + $hint = isset($attribs['placeholder']) ? $attribs['placeholder'] : ''; + $class = isset($attribs['class']) ? $attribs['class'] : ''; // Format value when not nulldate ('0000-00-00 00:00:00'), otherwise blank it as it would result in 1970-01-01. if ($value && $value != JFactory::getDbo()->getNullDate() && strtotime($value) !== false) @@ -1014,38 +1040,32 @@ public static function calendar($value, $name, $id, $format = '%Y-%m-%d', $attri $inputvalue = ''; } - // Load the calendar behavior - static::_('behavior.calendar'); - - // Only display the triggers once for each control. - if (!in_array($id, $done)) - { - JFactory::getDocument()->addScriptDeclaration( - 'jQuery(document).ready(function($) {Calendar.setup({ - // Id of the input field - inputField: "' . $id . '", - // Format of the input field - ifFormat: "' . $format . '", - // Trigger for the calendar (button ID) - button: "' . $id . '_img", - // Alignment (defaults to "Bl") - align: "Tl", - singleClick: true, - firstDay: ' . JFactory::getLanguage()->getFirstDay() . ' - });});' + $data = array( + 'id' => $id, + 'name' => $name, + 'class' => $class, + 'value' => $inputvalue, + 'format' => $format, + 'filter' => $filter, + 'required' => $required, + 'readonly' => $readonly, + 'disabled' => $disabled, + 'hint' => $hint, + 'autofocus' => $autofocus, + 'autocomplete' => $autocomplete, + 'todaybutton' => $todayBtn, + 'weeknumbers' => $weekNumbers, + 'showtime' => $showTime, + 'filltable' => $fillTable, + 'timeformat' => $timeFormat, + 'singleheader' => $singleHeader, + 'tag' => $tag, + 'helperPath' => $helperPath, + 'localesPath' => $localesPath, + 'direction' => $direction, ); - $done[] = $id; - } - - // Hide button using inline styles for readonly/disabled fields - $btn_style = ($readonly || $disabled) ? ' style="display:none;"' : ''; - $div_class = (!$readonly && !$disabled) ? ' class="input-append"' : ''; - return '' - . '' - . '' - . ''; + return JLayoutHelper::render('joomla.form.field.calendar', $data, null, null); } /** diff --git a/libraries/joomla/form/fields/calendar.php b/libraries/joomla/form/fields/calendar.php index 610ca29cc6044..31b8d37a3b6e7 100644 --- a/libraries/joomla/form/fields/calendar.php +++ b/libraries/joomla/form/fields/calendar.php @@ -51,6 +51,30 @@ class JFormFieldCalendar extends JFormField implements JFormDomfieldinterface */ protected $filter; + /** + * The minimum year number to subtract/add from the current year + * + * @var integer + * @since __DEPLOY_VERSION__ + */ + protected $minyear; + + /** + * The maximum year number to subtract/add from the current year + * + * @var integer + * @since __DEPLOY_VERSION__ + */ + protected $maxyear; + + /** + * Name of the layout being used to render the field + * + * @var string + * @since __DEPLOY_VERSION__ + */ + protected $layout = 'joomla.form.field.calendar'; + /** * Method to get certain otherwise inaccessible properties from the form field object. * @@ -67,6 +91,14 @@ public function __get($name) case 'maxlength': case 'format': case 'filter': + case 'timeformat': + case 'todaybutton': + case 'singleheader': + case 'weeknumbers': + case 'showtime': + case 'filltable': + case 'minyear': + case 'maxyear': return $this->$name; } @@ -88,9 +120,18 @@ public function __set($name, $value) switch ($name) { case 'maxlength': - $value = (int) $value; + case 'timeformat': + $this->$name = (int) $value; + break; + case 'todaybutton': + case 'singleheader': + case 'weeknumbers': + case 'showtime': + case 'filltable': case 'format': case 'filter': + case 'minyear': + case 'maxyear': $this->$name = (string) $value; break; @@ -119,9 +160,17 @@ public function setup(SimpleXMLElement $element, $value, $group = null) if ($return) { - $this->maxlength = (int) $this->element['maxlength'] ? (int) $this->element['maxlength'] : 45; - $this->format = (string) $this->element['format'] ? (string) $this->element['format'] : '%Y-%m-%d'; - $this->filter = (string) $this->element['filter'] ? (string) $this->element['filter'] : 'USER_UTC'; + $this->maxlength = (int) $this->element['maxlength'] ? (int) $this->element['maxlength'] : 45; + $this->format = (string) $this->element['format'] ? (string) $this->element['format'] : '%Y-%m-%d'; + $this->filter = (string) $this->element['filter'] ? (string) $this->element['filter'] : 'USER_UTC'; + $this->todaybutton = (string) $this->element['todaybutton'] ? (string) $this->element['todaybutton'] : "true"; + $this->weeknumbers = (string) $this->element['weeknumbers'] ? (string) $this->element['weeknumbers'] : "false"; + $this->showtime = (string) $this->element['showtime'] ? (string) $this->element['showtime'] : "true"; + $this->filltable = (string) $this->element['filltable'] ? (string) $this->element['filltable'] : "true"; + $this->timeformat = (int) $this->element['timeformat'] ? (int) $this->element['timeformat'] : 24; + $this->singleheader = (string) $this->element['singleheader'] ? (string) $this->element['singleheader'] : "false"; + $this->minyear = (string) $this->element['minyear'] ? (string) $this->element['minyear'] : null; + $this->maxyear = (string) $this->element['maxyear'] ? (string) $this->element['maxyear'] : null; } return $return; @@ -136,59 +185,45 @@ public function setup(SimpleXMLElement $element, $value, $group = null) */ protected function getInput() { - // Translate placeholder text - $hint = $this->translateHint ? JText::_($this->hint) : $this->hint; + return $this->getRenderer($this->layout)->render($this->getLayoutData()); + } - // Initialize some field attributes. - $translateFormat = (string) $this->element['translateformat']; + /** + * Method to get the data to be passed to the layout for rendering. + * + * @return array + * + * @since __DEPLOY_VERSION__ + */ + protected function getLayoutData() + { + $data = parent::getLayoutData(); + $tag = JFactory::getLanguage()->getTag(); + $calendar = JFactory::getLanguage()->getCalendar(); + $config = JFactory::getConfig(); + $user = JFactory::getUser(); + $direction = strtolower(JFactory::getDocument()->getDirection()); - if ($translateFormat && $translateFormat != 'false') - { - $showTime = (string) $this->element['showtime']; - - if ($showTime && $showTime != 'false') - { - $format = JText::_('DATE_FORMAT_CALENDAR_DATETIME'); - } - else - { - $format = JText::_('DATE_FORMAT_CALENDAR_DATE'); - } - } - else + // Get the appropriate file for the current language date helper + $helperPath = 'system/fields/calendar-locales/date/gregorian/date-helper.min.js'; + + if (!empty($calendar) && is_dir(JPATH_ROOT . '/media/system/js/fields/calendar-locales/date/' . strtolower($calendar))) { - $format = $this->format; + $helperPath = 'system/fields/calendar-locales/date/' . strtolower($calendar) . '/date-helper.min.js'; } - // Build the attributes array. - $attributes = array(); - - empty($this->size) ? null : $attributes['size'] = $this->size; - empty($this->maxlength) ? null : $attributes['maxlength'] = $this->maxlength; - empty($this->class) ? null : $attributes['class'] = $this->class; - !$this->readonly ? null : $attributes['readonly'] = 'readonly'; - !$this->disabled ? null : $attributes['disabled'] = 'disabled'; - empty($this->onchange) ? null : $attributes['onchange'] = $this->onchange; - !strlen($hint) ? null : $attributes['placeholder'] = $hint; - $this->autocomplete ? null : $attributes['autocomplete'] = 'off'; - !$this->autofocus ? null : $attributes['autofocus'] = ''; + // Get the appropriate locale file for the current language + $localesPath = 'system/fields/calendar-locales/en.js'; - if ($this->required) + if (is_file(JPATH_ROOT . '/media/system/js/fields/calendar-locales/' . strtolower($tag) . '.js')) { - $attributes['required'] = ''; - $attributes['aria-required'] = 'true'; + $localesPath = 'system/fields/calendar-locales/' . strtolower($tag) . '.js'; } - - // Handle the special case for "now". - if (strtoupper($this->value) == 'NOW') + elseif (is_file(JPATH_ROOT . '/media/system/js/fields/calendar-locales/' . strtolower(substr($tag, 0, -3)) . '.js')) { - $this->value = JFactory::getDate()->format('Y-m-d H:i:s'); + $localesPath = 'system/fields/calendar-locales/' . strtolower(substr($tag, 0, -3)) . '.js'; } - // Get some system objects. - $config = JFactory::getConfig(); - $user = JFactory::getUser(); - // If a known filter is given use it. switch (strtoupper($this->filter)) { @@ -203,29 +238,39 @@ protected function getInput() // Transform the date string. $this->value = $date->format('Y-m-d H:i:s', true, false); } - break; - case 'USER_UTC': // Convert a date to UTC based on the user timezone. if ($this->value && $this->value != JFactory::getDbo()->getNullDate()) { // Get a date object based on the correct timezone. $date = JFactory::getDate($this->value, 'UTC'); - $date->setTimezone(new DateTimeZone($user->getParam('timezone', $config->get('offset')))); // Transform the date string. $this->value = $date->format('Y-m-d H:i:s', true, false); } - break; } - // Including fallback code for HTML5 non supported browsers. - JHtml::_('jquery.framework'); - JHtml::_('script', 'system/html5fallback.js', array('version' => 'auto', 'relative' => true)); + $extraData = array( + 'value' => $this->value, + 'maxLength' => $this->maxlength, + 'format' => $this->format, + 'filter' => $this->filter, + 'todaybutton' => ($this->todaybutton === "true") ? 1 : 0, + 'weeknumbers' => ($this->weeknumbers === "true") ? 1 : 0, + 'showtime' => ($this->showtime === "true") ? 1 : 0, + 'filltable' => ($this->filltable === "true") ? 1 : 0, + 'timeformat' => $this->timeformat, + 'singleheader' => ($this->singleheader === "true") ? 1 : 0, + 'helperPath' => $helperPath, + 'localesPath' => $localesPath, + 'minYear' => $this->minyear, + 'maxYear' => $this->maxyear, + 'direction' => $direction, + ); - return JHtml::_('calendar', $this->value, $this->name, $this->id, $format, $attributes); + return array_merge($data, $extraData); } } diff --git a/libraries/joomla/language/language.php b/libraries/joomla/language/language.php index 948594a2ff6dc..4d15f3a8004a0 100644 --- a/libraries/joomla/language/language.php +++ b/libraries/joomla/language/language.php @@ -1085,6 +1085,25 @@ public function getTag() return $this->metadata['tag']; } + /** + * Getter for the calendar type + * + * @return string The calendar type. + * + * @since __DEPLOY_VERSION__ + */ + public function getCalendar() + { + if (isset($this->metadata['calendar'])) + { + return $this->metadata['calendar']; + } + else + { + return 'gregorian'; + } + } + /** * Get the RTL property. * diff --git a/media/system/css/fields/calendar-vanilla-rtl.css b/media/system/css/fields/calendar-vanilla-rtl.css new file mode 100644 index 0000000000000..c3f8991d420a1 --- /dev/null +++ b/media/system/css/fields/calendar-vanilla-rtl.css @@ -0,0 +1,129 @@ +/** + * @copyright Copyright (C) 2005 - 2016 Open Source Matters, Inc. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ +.calendar-container { + float: left; + min-width: 160px; + padding: 5px 0; + list-style: none; + border: 1px solid #ccc; + border-radius: 8px; + background-color: #ffffff !important; + z-index: 1100 !important; +} +.calendar-container table { + background-color: #ffffff !important; + z-index: 1100 !important; +} +/* The main calendar widget. DIV containing a table. */ +div.calendar-container table th, .calendar-container table td { + padding: 7px; + line-height: 1.8em; + background-color: #fff; +} + +div.calendar-container table td { + line-height: 2em; +} + +div.calendar-container table td.title { /* This holds the current "month, year" */ + vertical-align: middle; + font-weight: bold; + text-align: center; + font-size: 1.1em; + background: #fff; + color: #000; + padding: 2px; +} + +.calendar-container table thead td.headrow { /* Row containing navigation buttons */ + background: #fff; + color: #000; +} + +.calendar-container table thead td.name { /* Cells containing the day names */ + border-bottom: 1px solid #fff; + padding: 2px; + text-align: center; + color: #000; +} + +.calendar-container table thead td.weekend { /* How a weekend day name shows in header */ + color: #999; +} + +.calendar-container table thead .daynames { /* Row containing the day names */ + background: #fff; +} + +/* The body part -- contains all the days in month. */ + +.calendar-container table tbody td.day { /* Cells containing month days dates */ + text-align: right; + padding: 2px 4px 2px 2px; +} + +.calendar-container table tbody td.wn { + padding: 2px 3px 2px 2px; + background: #fff; +} + +.calendar-container table tbody td.active { /* Active (pressed) cells */ + background: #ffffff; + color: #000000; +} + +.calendar-container table tbody td.weekend { /* Cells showing weekend days */ + color: #999; +} + +.calendar-container table tbody td.hilite { /* Hovered cells */ + background: #999999; + color: #ffffff; +} + +.calendar-container table tbody td.day-name { + width: 14.28%; +} + +.calendar-container table tbody td.day { + border: none; +} + +.calendar-container table tbody td.selected { /* Cell showing today date */ + font-weight: bold; + background: #3071a9; + color: #fff; +} + +.calendar-container table tbody td.today:before { + font-weight: bold; + content: " "; + position: relative; + top: .25em; + right: -1em; + width: 0; + height: 0; + border-top: 0.8em solid lime; + border-left: .8em solid transparent; +} + +.calendar-container table tbody td.day:hover { + cursor: pointer; + background: #3d8fd7; + color: #fff; +} + +.calendar-container table tbody .disabled { + color: #999; +} + +.calendar-container table tbody .emptycell { /* Empty cells (the best is to hide them) */ + visibility: hidden; +} + +.calendar-container table tbody .emptyrow { /* Empty row (some months need less than 6 rows) */ + display: none; +} + diff --git a/media/system/css/fields/calendar-vanilla.css b/media/system/css/fields/calendar-vanilla.css new file mode 100644 index 0000000000000..1a6880a040b3a --- /dev/null +++ b/media/system/css/fields/calendar-vanilla.css @@ -0,0 +1,148 @@ +/** + * @copyright Copyright (C) 2005 - 2016 Open Source Matters, Inc. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ +.calendar-container { + float: left; + min-width: 160px; + padding: 5px 0; + list-style: none; + border: 1px solid #ccc; + border-radius: 8px; + background-color: #ffffff !important; + z-index: 1100 !important; +} +.calendar-container table { + background-color: #ffffff !important; + z-index: 1100 !important; +} +/* The main calendar widget. DIV containing a table. */ +div.calendar-container table th, .calendar-container table td { + padding: 7px; + line-height: 1.8em; + background-color: #fff; +} + +div.calendar-container table td { + line-height: 2em; +} + +div.calendar-container table td.title { /* This holds the current "month, year" */ + vertical-align: middle; + font-weight: bold; + text-align: center; + font-size: 1.1em; + background: #fff; + color: #000; + padding: 2px; +} + +.calendar-container table thead td.headrow { /* Row containing navigation buttons */ + background: #fff; + color: #000; +} + +.calendar-container table thead td.name { /* Cells containing the day names */ + border-bottom: 1px solid #fff; + padding: 2px; + text-align: center; + color: #000; +} + +.calendar-container table thead td.weekend { /* How a weekend day name shows in header */ + color: #999; +} + +.calendar-container table thead .daynames { /* Row containing the day names */ + background: #fff; +} + +/* The body part -- contains all the days in month. */ + +.calendar-container table tbody td.day { /* Cells containing month days dates */ + text-align: right; + padding: 2px 4px 2px 2px; +} + +.calendar-container table tbody td.wn { + padding: 2px 3px 2px 2px; + background: #fff; +} + +.calendar-container table tbody td.active { /* Active (pressed) cells */ + background: #ffffff; + color: #000000; +} + +.calendar-container table tbody td.weekend { /* Cells showing weekend days */ + color: #999; +} + +.calendar-container table tbody td.hilite { /* Hovered cells */ + background: #999999; + color: #ffffff; +} + +.calendar-container table tbody td.day-name { + width: 14.28%; +} + +.calendar-container table tbody td.day-name.day-name-week { + width: 12.5%; +} + +.calendar-container table thead td.day-name.wn { + text-align: center; + background-color: #f4f4f4; +} + +.calendar-container table tbody td.day { + border: none; + cursor : pointer; +} + +.calendar-container table tbody td.day.wn { + text-align: center; + background-color: #f4f4f4; +} + +.calendar-container table tbody td.selected { /* Cell showing today date */ + font-weight: bold; + background: #3071a9; + color: #fff; +} + +.calendar-container table tbody td.today:before { + font-weight: bold; + content: " "; + position: relative; + top: .25em; + right: -1.6em; + width: 0; + height: 0; + border-top: 0.8em solid lime; + border-left: .8em solid transparent; +} + +.calendar-container table tbody td.day:hover { + cursor: pointer; + background: #3d8fd7; + color: #fff; +} + +.calendar-container table tbody .disabled { + color: #999; +} + +.calendar-container table tbody .emptycell { /* Empty cells (the best is to hide them) */ + visibility: hidden; +} + +.calendar-container table tbody .emptyrow { /* Empty row (some months need less than 6 rows) */ + display: none; +} + +a.js-btn.btn.btn-danger.btn-exit, a.js-btn.btn.btn-primary.btn-today, a.js-btn.btn.btn-clear { + cursor : pointer; + text-decoration: none; +} \ No newline at end of file diff --git a/media/system/js/core-uncompressed.js b/media/system/js/core-uncompressed.js index 856abdf5dcfb5..2fbe3ba04e298 100644 --- a/media/system/js/core-uncompressed.js +++ b/media/system/js/core-uncompressed.js @@ -30,7 +30,7 @@ Joomla.editors.instances = Joomla.editors.instances || {}; // Toggle HTML5 validation form.noValidate = !validate; - form.setAttribute('novalidate', !validate); + form.setAttribute('novalidate', !validate) // Submit the form. // Create the input type="submit" diff --git a/media/system/js/fields/calendar-locales/date/gregorian/date-helper.js b/media/system/js/fields/calendar-locales/date/gregorian/date-helper.js new file mode 100644 index 0000000000000..bda6be163b7d3 --- /dev/null +++ b/media/system/js/fields/calendar-locales/date/gregorian/date-helper.js @@ -0,0 +1,380 @@ +!(function(Date){ + 'use strict'; + + /****************** Gregorian dates ********************/ + /** Constants used for time computations */ + Date.SECOND = 1000 /* milliseconds */; + Date.MINUTE = 60 * Date.SECOND; + Date.HOUR = 60 * Date.MINUTE; + Date.DAY = 24 * Date.HOUR; + Date.WEEK = 7 * Date.DAY; + + /** MODIFY ONLY THE MARKED PARTS OF THE METHODS **/ + /************ START *************/ + /** INTERFACE METHODS FOR THE CALENDAR PICKER **/ + + /********************** *************************/ + /**************** SETTERS ***********************/ + /********************** *************************/ + + /** Sets the date for the current date without h/m/s. */ + Date.prototype.setLocalDateOnly = function (dateType, date) { + if (dateType != 'gregorian') { + /** Modify to match the current calendar when overriding **/ + return ''; + } else { + var tmp = new Date(date); + this.setDate(1); + this.setFullYear(tmp.getFullYear()); + this.setMonth(tmp.getMonth()); + this.setDate(tmp.getDate()); + } + }; + + /** Sets the full date for the current date. */ + Date.prototype.setLocalDate = function (dateType, d) { + if (dateType != 'gregorian') { + /** Modify to match the current calendar when overriding **/ + return ''; + } else { + return this.setDate(d); + } + }; + + /** Sets the month for the current date. */ + Date.prototype.setLocalMonth = function (dateType, m, d) { + if (dateType != 'gregorian') { + /** Modify to match the current calendar when overriding **/ + return ''; + } else { + if (d == undefined) this.getDate(); + return this.setMonth(m); + } + }; + + /** Sets the year for the current date. */ + Date.prototype.setOtherFullYear = function(dateType, y) { + if (dateType != 'gregorian') { + /** Modify to match the current calendar when overriding **/ + return ''; + } else { + var date = new Date(this); + date.setFullYear(y); + if (date.getMonth() != this.getMonth()) this.setDate(28); + return this.setUTCFullYear(y); + } + }; + + /** Sets the year for the current date. */ + Date.prototype.setLocalFullYear = function (dateType, y) { + if (dateType != 'gregorian') { + /** Modify to match the current calendar when overriding **/ + return ''; + } else { + var date = new Date(this); + date.setFullYear(y); + if (date.getMonth() != this.getMonth()) this.setDate(28); + return this.setFullYear(y); + } + }; + + /********************** *************************/ + /**************** GETTERS ***********************/ + /********************** *************************/ + + /** The number of days per week **/ + Date.prototype.getLocalWeekDays = function (dateType, y) { + if (dateType != 'gregorian') { + /** Modify to match the current calendar when overriding **/ + return 6; + } else { + return 6; // 7 days per week + } + }; + + /** Returns the year for the current date. */ + Date.prototype.getOtherFullYear = function (dateType) { + if (dateType != 'gregorian') { + /** Modify to match the current calendar when overriding **/ + return ''; + } else { + return this.getFullYear(); + } + }; + + /** Returns the year for the current date. */ + Date.prototype.getLocalFullYear = function (dateType) { + if (dateType != 'gregorian') { + /** Modify to match the current calendar when overriding **/ + return ''; + } else { + return this.getFullYear(); + } + }; + + /** Returns the month the date. */ + Date.prototype.getLocalMonth = function (dateType) { + if (dateType != 'gregorian') { + /** Modify to match the current calendar when overriding **/ + return ''; + } else { + return this.getMonth(); + } + }; + + /** Returns the date. */ + Date.prototype.getLocalDate = function (dateType) { + if (dateType != 'gregorian') { + /** Modify to match the current calendar when overriding **/ + return ''; + } else { + return this.getDate(); + } + }; + + /** Returns the number of day in the year. */ + Date.prototype.getLocalDay = function(dateType) { + if (dateType != 'gregorian') { + return ''; + } else { + return this.getDay(); + } + }; + + /** Returns the number of days in the current month */ + Date.prototype.getLocalMonthDays = function(dateType, month) { + if (dateType != 'gregorian') { + /** Modify to match the current calendar when overriding **/ + return ''; + } else { + var year = this.getFullYear(); + if (typeof month == "undefined") { + month = this.getMonth(); + } + if (((0 == (year%4)) && ( (0 != (year%100)) || (0 == (year%400)))) && month == 1) { + return 29; + } else { + return [31,28,31,30,31,30,31,31,30,31,30,31][month]; + } + } + }; + + /** Returns the week number for the current date. */ + Date.prototype.getLocalWeekNumber = function(dateType) { + if (dateType != 'gregorian') { + /** Modify to match the current calendar when overriding **/ + return ''; + } else { + var d = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0); + var DoW = d.getDay(); + d.setDate(d.getDate() - (DoW + 6) % 7 + 3); // Nearest Thu + var ms = d.valueOf(); // GMT + d.setMonth(0); + d.setDate(4); // Thu in Week 1 + return Math.round((ms - d.valueOf()) / (7 * 864e5)) + 1; + } + }; + + /** Returns the number of day in the year. */ + Date.prototype.getLocalDayOfYear = function(dateType) { + if (dateType != 'gregorian') { + return ''; + } else { + var now = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0); + var then = new Date(this.getFullYear(), 0, 0, 0, 0, 0); + var time = now - then; + return Math.floor(time / Date.DAY); + } + }; + + /** Checks date and time equality */ + Date.prototype.equalsTo = function(date) { + return ((this.getFullYear() == date.getFullYear()) && + (this.getMonth() == date.getMonth()) && + (this.getDate() == date.getDate()) && + (this.getHours() == date.getHours()) && + (this.getMinutes() == date.getMinutes())); + }; + + /** Converts foreign date to gregorian date. */ + Date.localCalToGregorian = function(y, m, d) { + /** Modify to match the current calendar when overriding **/ + return''; + }; + + /** Converts gregorian date to foreign date. */ + Date.gregorianToLocalCal = function(y, m, d) { + /** Modify to match the current calendar when overriding **/ + return ''; + }; + + /** INTERFACE METHODS FOR THE CALENDAR PICKER **/ + /************* END **************/ + + /** Method to parse a string and return a date. **/ + Date.parseFieldDate = function(str, fmt, dateType) { + if (dateType != 'gregorian') + str = Date.toEnglish(str); + + var today = new Date(); + var y = 0; + var m = -1; + var d = 0; + var a = str.split(/\W+/); + var b = fmt.match(/%./g); + var i = 0, j = 0; + var hr = 0; + var min = 0; + var sec = 0; + for (i = 0; i < a.length; ++i) { + if (!a[i]) + continue; + switch (b[i]) { + case "%d": + case "%e": + d = parseInt(a[i], 10); + break; + + case "%m": + m = parseInt(a[i], 10) - 1; + break; + + case "%Y": + case "%y": + y = parseInt(a[i], 10); + (y < 100) && (y += (y > 29) ? 1900 : 2000); + break; + + case "%b": + case "%B": + for (j = 0; j < 12; ++j) { + if (JoomlaCalLocale.months[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) { m = j; break; } + } + break; + + case "%H": + case "%I": + case "%k": + case "%l": + hr = parseInt(a[i], 10); + break; + + case "%P": + case "%p": + if (/pm/i.test(a[i]) && hr < 12) + hr += 12; + else if (/am/i.test(a[i]) && hr >= 12) + hr -= 12; + break; + + case "%M": + min = parseInt(a[i], 10); + break; + } + } + if (isNaN(y)) y = today.getFullYear(); + if (isNaN(m)) m = today.getMonth(); + if (isNaN(d)) d = today.getDate(); + if (isNaN(hr)) hr = today.getHours(); + if (isNaN(min)) min = today.getMinutes(); + if (isNaN(sec)) sec = today.getSeconds(); + if (y != 0 && m != -1 && d != 0) + return new Date(y, m, d, hr, min, sec); + y = 0; m = -1; d = 0; + for (i = 0; i < a.length; ++i) { + if (a[i].search(/[a-zA-Z]+/) != -1) { + var t = -1; + for (j = 0; j < 12; ++j) { + if (JoomlaCalLocale.months[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) { t = j; break; } + } + if (t != -1) { + if (m != -1) { + d = m+1; + } + m = t; + } + } else if (parseInt(a[i], 10) <= 12 && m == -1) { + m = a[i]-1; + } else if (parseInt(a[i], 10) > 31 && y == 0) { + y = parseInt(a[i], 10); + (y < 100) && (y += (y > 29) ? 1900 : 2000); + } else if (d == 0) { + d = a[i]; + } + } + if (y == 0) + y = today.getFullYear(); + if (m != -1 && d != 0) + return new Date(y, m, d, hr, min, sec); + return today; + }; + + /** Prints the date in a string according to the given format. */ + Date.prototype.print = function (str, dateType, translate) { + /** Handle calendar type **/ + if (typeof dateType !== 'string') str = ''; + if (!dateType) dateType = 'gregorian'; + + /** Handle wrong format **/ + if (typeof str !== 'string') str = ''; + if (!str) return ''; + + if (this.getLocalDate(dateType) == 'NaN' || !this.getLocalDate(dateType)) return ''; + var m = this.getLocalMonth(dateType); + var d = this.getLocalDate(dateType); + var y = this.getLocalFullYear(dateType); + var wn = this.getLocalWeekNumber(dateType); + var w = this.getDay(); + var s = {}; + var hr = this.getHours(); + var pm = (hr >= 12); + var ir = (pm) ? (hr - 12) : hr; + var dy = this.getLocalDayOfYear(dateType); + if (ir == 0) + ir = 12; + var min = this.getMinutes(); + var sec = this.getSeconds(); + s["%a"] = JoomlaCalLocale.shortDays[w]; // abbreviated weekday name + s["%A"] = JoomlaCalLocale.days[w]; // full weekday name + s["%b"] = JoomlaCalLocale.shortMonths[m]; // abbreviated month name + s["%B"] = JoomlaCalLocale.months[m]; // full month name + // FIXME: %c : preferred date and time representation for the current locale + s["%C"] = 1 + Math.floor(y / 100); // the century number + s["%d"] = (d < 10) ? ("0" + d) : d; // the day of the month (range 01 to 31) + s["%e"] = d; // the day of the month (range 1 to 31) + // FIXME: %D : american date style: %m/%d/%y + // FIXME: %E, %F, %G, %g, %h (man strftime) + s["%H"] = (hr < 10) ? ("0" + hr) : hr; // hour, range 00 to 23 (24h format) + s["%I"] = (ir < 10) ? ("0" + ir) : ir; // hour, range 01 to 12 (12h format) + s["%j"] = (dy < 100) ? ((dy < 10) ? ("00" + dy) : ("0" + dy)) : dy; // day of the year (range 001 to 366) + s["%k"] = hr; // hour, range 0 to 23 (24h format) + s["%l"] = ir; // hour, range 1 to 12 (12h format) + s["%m"] = (m < 9) ? ("0" + (1+m)) : (1+m); // month, range 01 to 12 + s["%M"] = (min < 10) ? ("0" + min) : min; // minute, range 00 to 59 + s["%n"] = "\n"; // a newline character + s["%p"] = pm ? JoomlaCalLocale.PM : JoomlaCalLocale.AM; + s["%P"] = pm ? JoomlaCalLocale.pm : JoomlaCalLocale.am; + // FIXME: %r : the time in am/pm notation %I:%M:%S %p + // FIXME: %R : the time in 24-hour notation %H:%M + s["%s"] = Math.floor(this.getTime() / 1000); + s["%S"] = (sec < 10) ? ("0" + sec) : sec; // seconds, range 00 to 59 + s["%t"] = "\t"; // a tab character + // FIXME: %T : the time in 24-hour notation (%H:%M:%S) + s["%U"] = s["%W"] = s["%V"] = (wn < 10) ? ("0" + wn) : wn; + s["%u"] = w + 1; // the day of the week (range 1 to 7, 1 = MON) + s["%w"] = w; // the day of the week (range 0 to 6, 0 = SUN) + // FIXME: %x : preferred date representation for the current locale without the time + // FIXME: %X : preferred time representation for the current locale without the date + s["%y"] = ('' + y).substr(2, 2); // year without the century (range 00 to 99) + s["%Y"] = y; // year with the century + s["%%"] = "%"; // a literal '%' character + + var re = /%./g; + + var tmpDate = str.replace(re, function (par) { return s[par] || par; }); + if (Object.prototype.toString.call(JoomlaCalLocale.localLangNumbers) === '[object Array]' && dateType != 'gregorian' && translate) + tmpDate = Date.convertNumbers(tmpDate); + + return tmpDate; + }; +})(Date); \ No newline at end of file diff --git a/media/system/js/fields/calendar-locales/date/gregorian/date-helper.min.js b/media/system/js/fields/calendar-locales/date/gregorian/date-helper.min.js new file mode 100644 index 0000000000000..09de8ca993328 --- /dev/null +++ b/media/system/js/fields/calendar-locales/date/gregorian/date-helper.min.js @@ -0,0 +1 @@ +!function(a){"use strict";a.SECOND=1e3,a.MINUTE=60*a.SECOND,a.HOUR=60*a.MINUTE,a.DAY=24*a.HOUR,a.WEEK=7*a.DAY,a.prototype.setLocalDateOnly=function(b,c){if("gregorian"!=b)return"";var d=new a(c);this.setDate(1),this.setFullYear(d.getFullYear()),this.setMonth(d.getMonth()),this.setDate(d.getDate())},a.prototype.setLocalDate=function(a,b){return"gregorian"!=a?"":this.setDate(b)},a.prototype.setLocalMonth=function(a,b,c){return"gregorian"!=a?"":(void 0==c&&this.getDate(),this.setMonth(b))},a.prototype.setOtherFullYear=function(b,c){if("gregorian"!=b)return"";var d=new a(this);return d.setFullYear(c),d.getMonth()!=this.getMonth()&&this.setDate(28),this.setUTCFullYear(c)},a.prototype.setLocalFullYear=function(b,c){if("gregorian"!=b)return"";var d=new a(this);return d.setFullYear(c),d.getMonth()!=this.getMonth()&&this.setDate(28),this.setFullYear(c)},a.prototype.getLocalWeekDays=function(a,b){return 6},a.prototype.getOtherFullYear=function(a){return"gregorian"!=a?"":this.getFullYear()},a.prototype.getLocalFullYear=function(a){return"gregorian"!=a?"":this.getFullYear()},a.prototype.getLocalMonth=function(a){return"gregorian"!=a?"":this.getMonth()},a.prototype.getLocalDate=function(a){return"gregorian"!=a?"":this.getDate()},a.prototype.getLocalDay=function(a){return"gregorian"!=a?"":this.getDay()},a.prototype.getLocalMonthDays=function(a,b){if("gregorian"!=a)return"";var c=this.getFullYear();return"undefined"==typeof b&&(b=this.getMonth()),0!=c%4||0==c%100&&0!=c%400||1!=b?[31,28,31,30,31,30,31,31,30,31,30,31][b]:29},a.prototype.getLocalWeekNumber=function(b){if("gregorian"!=b)return"";var c=new a(this.getFullYear(),this.getMonth(),this.getDate(),0,0,0),d=c.getDay();c.setDate(c.getDate()-(d+6)%7+3);var e=c.valueOf();return c.setMonth(0),c.setDate(4),Math.round((e-c.valueOf())/6048e5)+1},a.prototype.getLocalDayOfYear=function(b){if("gregorian"!=b)return"";var c=new a(this.getFullYear(),this.getMonth(),this.getDate(),0,0,0),d=new a(this.getFullYear(),0,0,0,0,0),e=c-d;return Math.floor(e/a.DAY)},a.prototype.equalsTo=function(a){return this.getFullYear()==a.getFullYear()&&this.getMonth()==a.getMonth()&&this.getDate()==a.getDate()&&this.getHours()==a.getHours()&&this.getMinutes()==a.getMinutes()},a.localCalToGregorian=function(a,b,c){return""},a.gregorianToLocalCal=function(a,b,c){return""},a.parseFieldDate=function(b,c,d){"gregorian"!=d&&(b=a.toEnglish(b));var e=new a,f=0,g=-1,h=0,i=b.split(/\W+/),j=c.match(/%./g),k=0,l=0,m=0,n=0,o=0;for(k=0;k29?1900:2e3);break;case"%b":case"%B":for(l=0;l<12;++l)if(JoomlaCalLocale.months[l].substr(0,i[k].length).toLowerCase()==i[k].toLowerCase()){g=l;break}break;case"%H":case"%I":case"%k":case"%l":m=parseInt(i[k],10);break;case"%P":case"%p":/pm/i.test(i[k])&&m<12?m+=12:/am/i.test(i[k])&&m>=12&&(m-=12);break;case"%M":n=parseInt(i[k],10)}if(isNaN(f)&&(f=e.getFullYear()),isNaN(g)&&(g=e.getMonth()),isNaN(h)&&(h=e.getDate()),isNaN(m)&&(m=e.getHours()),isNaN(n)&&(n=e.getMinutes()),isNaN(o)&&(o=e.getSeconds()),0!=f&&g!=-1&&0!=h)return new a(f,g,h,m,n,o);for(f=0,g=-1,h=0,k=0;k31&&0==f?(f=parseInt(i[k],10),f<100&&(f+=f>29?1900:2e3)):0==h&&(h=i[k]);return 0==f&&(f=e.getFullYear()),g!=-1&&0!=h?new a(f,g,h,m,n,o):e},a.prototype.print=function(b,c,d){if("string"!=typeof c&&(b=""),c||(c="gregorian"),"string"!=typeof b&&(b=""),!b)return"";if("NaN"==this.getLocalDate(c)||!this.getLocalDate(c))return"";var e=this.getLocalMonth(c),f=this.getLocalDate(c),g=this.getLocalFullYear(c),h=this.getLocalWeekNumber(c),i=this.getDay(),j={},k=this.getHours(),l=k>=12,m=l?k-12:k,n=this.getLocalDayOfYear(c);0==m&&(m=12);var o=this.getMinutes(),p=this.getSeconds();j["%a"]=JoomlaCalLocale.shortDays[i],j["%A"]=JoomlaCalLocale.days[i],j["%b"]=JoomlaCalLocale.shortMonths[e],j["%B"]=JoomlaCalLocale.months[e],j["%C"]=1+Math.floor(g/100),j["%d"]=f<10?"0"+f:f,j["%e"]=f,j["%H"]=k<10?"0"+k:k,j["%I"]=m<10?"0"+m:m,j["%j"]=n<100?n<10?"00"+n:"0"+n:n,j["%k"]=k,j["%l"]=m,j["%m"]=e<9?"0"+(1+e):1+e,j["%M"]=o<10?"0"+o:o,j["%n"]="\n",j["%p"]=l?JoomlaCalLocale.PM:JoomlaCalLocale.AM,j["%P"]=l?JoomlaCalLocale.pm:JoomlaCalLocale.am,j["%s"]=Math.floor(this.getTime()/1e3),j["%S"]=p<10?"0"+p:p,j["%t"]="\t",j["%U"]=j["%W"]=j["%V"]=h<10?"0"+h:h,j["%u"]=i+1,j["%w"]=i,j["%y"]=(""+g).substr(2,2),j["%Y"]=g,j["%%"]="%";var q=/%./g,r=b.replace(q,function(a){return j[a]||a});return"[object Array]"===Object.prototype.toString.call(JoomlaCalLocale.localLangNumbers)&&"gregorian"!=c&&d&&(r=a.convertNumbers(r)),r}}(Date); \ No newline at end of file diff --git a/media/system/js/fields/calendar-locales/date/jalali/date-helper.js b/media/system/js/fields/calendar-locales/date/jalali/date-helper.js new file mode 100644 index 0000000000000..7cce0687f4c40 --- /dev/null +++ b/media/system/js/fields/calendar-locales/date/jalali/date-helper.js @@ -0,0 +1,605 @@ +/** BEGIN: DATE OBJECT PATCHES **/ +/** Adds the number of days array to the Date object. */ +Date.gregorian_MD = [31,28,31,30,31,30,31,31,30,31,30,31]; +Date.local_MD = [31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29]; + +/** Constants used for time computations */ +Date.SECOND = 1000 /* milliseconds */; +Date.MINUTE = 60 * Date.SECOND; +Date.HOUR = 60 * Date.MINUTE; +Date.DAY = 24 * Date.HOUR; +Date.WEEK = 7 * Date.DAY; + +/** MODIFY ONLY THE MARKED PARTS OF THE METHODS **/ +/************ START *************/ +/** INTERFACE METHODS FOR THE CALENDAR PICKER **/ + +/********************** *************************/ +/**************** SETTERS ***********************/ +/********************** *************************/ + +/** Sets the date for the current date without h/m/s. */ +Date.prototype.setLocalDateOnly = function (dateType, date) { + if (dateType != 'gregorian') { + /** Modify to match the current calendar when overriding **/ + return ''; + } else { + var tmp = new Date(date); + this.setDate(1); + this.setFullYear(tmp.getFullYear()); + this.setMonth(tmp.getMonth()); + this.setDate(tmp.getDate()); + } +}; + +/** Sets the full date for the current date. */ +Date.prototype.setLocalDate = function (dateType, d) { + if (dateType != 'gregorian') { + /** Modify to match the current calendar when overriding **/ + return this.setJalaliDate(d); + } else { + return this.setDate(d); + } +}; + +/** Sets the month for the current date. */ +Date.prototype.setLocalMonth = function (dateType, m, d) { + if (dateType != 'gregorian') { + /** Modify to match the current calendar when overriding **/ + return this.setJalaliMonth(m, d); + } else { + if (d == undefined) this.getDate(); + return this.setMonth(m); + } +}; + +/** Sets the year for the current date. */ +Date.prototype.setOtherFullYear = function(dateType, y) { + if (dateType != 'gregorian') { + /** Modify to match the current calendar when overriding **/ + var date = new Date(this); + date.setLocalFullYear(y); + if (date.getLocalMonth('jalali') != this.getLocalMonth('jalali')) this.setLocalDate('jalali', 29); + return this.setLocalFullYear('jalali', y); + } else { + var date = new Date(this); + date.setFullYear(y); + if (date.getMonth() != this.getMonth()) this.setDate(28); + return this.setUTCFullYear(y); + } +}; + +/** Sets the year for the current date. */ +Date.prototype.setLocalFullYear = function (dateType, y) { + if (dateType != 'gregorian') { + /** Modify to match the current calendar when overriding **/ + return this.setJalaliFullYear(y); + } else { + var date = new Date(this); + date.setFullYear(y); + if (date.getMonth() != this.getMonth()) this.setDate(28); + return this.setFullYear(y); + } +}; + +/********************** *************************/ +/**************** GETTERS ***********************/ +/********************** *************************/ + +/** The number of days per week **/ +Date.prototype.getLocalWeekDays = function (dateType, y) { + if (dateType != 'gregorian') { + /** Modify to match the current calendar when overriding **/ + return 6; + } else { + return 6; // 7 days per week + } +}; + +/** Returns the year for the current date. */ +Date.prototype.getOtherFullYear = function (dateType) { + if (dateType != 'gregorian') { + /** Modify to match the current calendar when overriding **/ + return this.getJalaliFullYear(); + } else { + return this.getFullYear(); + } +}; + +/** Returns the year for the current date. */ +Date.prototype.getLocalFullYear = function (dateType) { + if (dateType != 'gregorian') { + /** Modify to match the current calendar when overriding **/ + return this.getJalaliFullYear(); + } else { + return this.getFullYear(); + } +}; + +/** Returns the month the date. */ +Date.prototype.getLocalMonth = function (dateType) { + if (dateType != 'gregorian') { + /** Modify to match the current calendar when overriding **/ + return this.getJalaliMonth(); + } else { + return this.getMonth(); + } +}; + +/** Returns the date. */ +Date.prototype.getLocalDate = function (dateType) { + if (dateType != 'gregorian') { + /** Modify to match the current calendar when overriding **/ + return this.getJalaliDate(); + } else { + return this.getDate(); + } +}; + +/** Returns the number of day in the year. */ +Date.prototype.getLocalDay = function(dateType) { + if (dateType != 'gregorian') { + return this.getJalaliDay(); + } else { + return this.getDay(); + } +}; + +/** Returns the number of days in the current month */ +Date.prototype.getLocalMonthDays = function(dateType, month) { + if (dateType != 'gregorian') { + /** Modify to match the current calendar when overriding **/ + var year = this.getLocalFullYear('jalali'); + if (typeof month == "undefined") { + month = this.getLocalMonth('jalali'); + } + if (((0 == (year%4)) && ( (0 != (year%100)) || (0 == (year%400)))) && month == 1) { + return 29; + } else { + Date.local_MD[month]; + } + } else { + var year = this.getFullYear(); + if (typeof month == "undefined") { + month = this.getMonth(); + } + if (((0 == (year%4)) && ( (0 != (year%100)) || (0 == (year%400)))) && month == 1) { + return 29; + } else { + return Date.gregorian_MD[month]; + } + } +}; + +/** Returns the week number for the current date. */ +Date.prototype.getLocalWeekNumber = function(dateType) { + if (dateType != 'gregorian') { + var d = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0); + var DoW = d.getDay(); + d.setDate(d.getDate() - (DoW + 6) % 7 + 3); // Nearest Thu + var ms = d.valueOf(); // GMT + d.setMonth(0); + d.setDate(4); // Thu in Week 1 + return Math.round((ms - d.valueOf()) / (7 * 864e5)) + 1; + } else { + var d = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0); + var DoW = d.getDay(); + d.setDate(d.getDate() - (DoW + 6) % 7 + 3); // Nearest Thu + var ms = d.valueOf(); // GMT + d.setMonth(0); + d.setDate(4); // Thu in Week 1 + return Math.round((ms - d.valueOf()) / (7 * 864e5)) + 1; + } +}; + +/** Returns the number of day in the year. */ +Date.prototype.getLocalDayOfYear = function(dateType) { + if (dateType != 'gregorian') { + var now = new Date(this.getOtherFullYear(dateType), this.getLocalMonth(dateType), this.getLocalDate(dateType), 0, 0, 0); + var then = new Date(this.getOtherFullYear(dateType), 0, 0, 0, 0, 0); + var time = now - then; + return Math.floor(time / Date.DAY); + } else { + var now = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0); + var then = new Date(this.getFullYear(), 0, 0, 0, 0, 0); + var time = now - then; + return Math.floor(time / Date.DAY); + } +}; + +/** Returns the number of days in the current month */ +Date.prototype.getMonthDays = function(month) { + var year = this.getFullYear(); + if (typeof month == "undefined") { + month = this.getMonth(); + } + if (((0 == (year%4)) && ( (0 != (year%100)) || (0 == (year%400)))) && month == 1) { + return 29; + } else { + if (Date.dateType != 'gregorian') { + Date.local_MD[month]; + } else { + return Date.gregorian_MD[month]; + } + } +}; + +/** Checks date and time equality */ +Date.prototype.equalsTo = function(date) { + return ((this.getFullYear() == date.getFullYear()) && + (this.getMonth() == date.getMonth()) && + (this.getDate() == date.getDate()) && + (this.getHours() == date.getHours()) && + (this.getMinutes() == date.getMinutes())); +}; + +/** Converts foreign date to gregorian date. */ +Date.localCalToGregorian = function(y, m, d) { + /** Modify to match the current calendar when overriding **/ + return JalaliDate.jalaliToGregorian(y, m, d); +}; + +/** Converts gregorian date to foreign date. */ +Date.gregorianToLocalCal = function(y, m, d) { + /** Modify to match the current calendar when overriding **/ + return JalaliDate.gregorianToJalali(y, m, d); +}; +/** INTERFACE METHODS FOR THE CALENDAR PICKER **/ +/************* END **************/ + +/** Prints the date in a string according to the given format. */ +Date.prototype.print = function (str, dateType, translate) { + /** Handle calendar type **/ + if (typeof dateType !== 'string') str = ''; + if (!dateType) dateType = 'gregorian'; + + /** Handle wrong format **/ + if (typeof str !== 'string') str = ''; + if (!str) return ''; + + + if (this.getLocalDate(dateType) == 'NaN' || !this.getLocalDate(dateType)) return ''; + var m = this.getLocalMonth(dateType); + var d = this.getLocalDate(dateType); + var y = this.getLocalFullYear(dateType); + var wn = this.getLocalWeekNumber(dateType); + var w = this.getLocalDay(dateType); + var s = {}; + var hr = this.getHours(); + var pm = (hr >= 12); + var ir = (pm) ? (hr - 12) : hr; + var dy = this.getLocalDayOfYear(dateType); + if (ir == 0) + ir = 12; + var min = this.getMinutes(); + var sec = this.getSeconds(); + s["%a"] = JoomlaCalLocale.shortDays[w]; // abbreviated weekday name + s["%A"] = JoomlaCalLocale.days[w]; // full weekday name + s["%b"] = JoomlaCalLocale.shortMonths[m]; // abbreviated month name + s["%B"] = JoomlaCalLocale.months[m]; // full month name + // FIXME: %c : preferred date and time representation for the current locale + s["%C"] = 1 + Math.floor(y / 100); // the century number + s["%d"] = (d < 10) ? ("0" + d) : d; // the day of the month (range 01 to 31) + s["%e"] = d; // the day of the month (range 1 to 31) + // FIXME: %D : american date style: %m/%d/%y + // FIXME: %E, %F, %G, %g, %h (man strftime) + s["%H"] = (hr < 10) ? ("0" + hr) : hr; // hour, range 00 to 23 (24h format) + s["%I"] = (ir < 10) ? ("0" + ir) : ir; // hour, range 01 to 12 (12h format) + s["%j"] = (dy < 100) ? ((dy < 10) ? ("00" + dy) : ("0" + dy)) : dy; // day of the year (range 001 to 366) + s["%k"] = hr; // hour, range 0 to 23 (24h format) + s["%l"] = ir; // hour, range 1 to 12 (12h format) + s["%m"] = (m < 9) ? ("0" + (1+m)) : (1+m); // month, range 01 to 12 + s["%M"] = (min < 10) ? ("0" + min) : min; // minute, range 00 to 59 + s["%n"] = "\n"; // a newline character + s["%p"] = pm ? JoomlaCalLocale.PM : JoomlaCalLocale.AM; + s["%P"] = pm ? JoomlaCalLocale.pm : JoomlaCalLocale.am; + // FIXME: %r : the time in am/pm notation %I:%M:%S %p + // FIXME: %R : the time in 24-hour notation %H:%M + s["%s"] = Math.floor(this.getTime() / 1000); + s["%S"] = (sec < 10) ? ("0" + sec) : sec; // seconds, range 00 to 59 + s["%t"] = "\t"; // a tab character + // FIXME: %T : the time in 24-hour notation (%H:%M:%S) + s["%U"] = s["%W"] = s["%V"] = (wn < 10) ? ("0" + wn) : wn; + s["%u"] = w + 1; // the day of the week (range 1 to 7, 1 = MON) + s["%w"] = w; // the day of the week (range 0 to 6, 0 = SUN) + // FIXME: %x : preferred date representation for the current locale without the time + // FIXME: %X : preferred time representation for the current locale without the date + s["%y"] = ('' + y).substr(2, 2); // year without the century (range 00 to 99) + s["%Y"] = y; // year with the century + s["%%"] = "%"; // a literal '%' character + + var re = /%./g; + + var tmpDate = str.replace(re, function (par) { return s[par] || par; }); + if (Object.prototype.toString.call(JoomlaCalLocale.localLangNumbers) === '[object Array]' && translate) + tmpDate = Date.convertNumbers(tmpDate); + + return tmpDate; +}; + +Date.parseFieldDate = function(str, fmt, dateType) { + var today = new Date(); + var y = 0; + var m = -1; + var d = 0; + var a = str.split(/\W+/); + var b = fmt.match(/%./g); + var i = 0, j = 0; + var hr = 0; + var min = 0; + for (i = 0; i < a.length; ++i) { + if (!a[i]) + continue; + switch (b[i]) { + case "%d": + case "%e": + d = parseInt(a[i], 10); + break; + + case "%m": + m = parseInt(a[i], 10) - 1; + break; + + case "%Y": + case "%y": + y = parseInt(a[i], 10); + (y < 100) && (y += (y > 29) ? 1900 : 2000); + break; + + case "%b": + case "%B": + for (j = 0; j < 12; ++j) { + if (dateType != 'gregorian') { + if (JoomlaCalLocale.months[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) { m = j; break; } + } else { + if (JoomlaCalLocale.months[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) { m = j; break; } + } + } + break; + + case "%H": + case "%I": + case "%k": + case "%l": + hr = parseInt(a[i], 10); + break; + + case "%P": + case "%p": + if (/pm/i.test(a[i]) && hr < 12) + hr += 12; + else if (/am/i.test(a[i]) && hr >= 12) + hr -= 12; + break; + + case "%M": + min = parseInt(a[i], 10); + break; + } + } + if (isNaN(y)) y = today.getFullYear(); + if (isNaN(m)) m = today.getMonth(); + if (isNaN(d)) d = today.getDate(); + if (isNaN(hr)) hr = today.getHours(); + if (isNaN(min)) min = today.getMinutes(); + if (y != 0 && m != -1 && d != 0) + return new Date(y, m, d, hr, min, 0); + y = 0; m = -1; d = 0; + for (i = 0; i < a.length; ++i) { + if (a[i].search(/[a-zA-Z]+/) != -1) { + var t = -1; + for (j = 0; j < 12; ++j) { + if (dateType != 'gregorian') { + if (JoomlaCalLocale.months[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) { t = j; break; } + } else { + if (JoomlaCalLocale.months[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) { t = j; break; } + } + } + if (t != -1) { + if (m != -1) { + d = m+1; + } + m = t; + } + } else if (parseInt(a[i], 10) <= 12 && m == -1) { + m = a[i]-1; + } else if (parseInt(a[i], 10) > 31 && y == 0) { + y = parseInt(a[i], 10); + (y < 100) && (y += (y > 29) ? 1900 : 2000); + } else if (d == 0) { + d = a[i]; + } + } + if (y == 0) + y = today.getFullYear(); + if (m != -1 && d != 0) + return new Date(y, m, d, hr, min, 0); + return today; +}; + +/* + * JalaliJSCalendar - Jalali Extension for Date Object + * Copyright (c) 2008 Ali Farhadi (http://farhadi.ir/) + * Released under the terms of the GNU General Public License. + * See the GPL for details (http://www.gnu.org/licenses/gpl.html). + * + * Based on code from http://farsiweb.info + */ + +JalaliDate = { + g_days_in_month: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], + j_days_in_month: [31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29] +}; + +JalaliDate.jalaliToGregorian = function(j_y, j_m, j_d) +{ + j_y = parseInt(j_y); + j_m = parseInt(j_m); + j_d = parseInt(j_d); + var jy = j_y-979; + var jm = j_m-1; + var jd = j_d-1; + + var j_day_no = 365*jy + parseInt(jy / 33)*8 + parseInt((jy%33+3) / 4); + for (var i=0; i < jm; ++i) j_day_no += JalaliDate.j_days_in_month[i]; + + j_day_no += jd; + + var g_day_no = j_day_no+79; + + var gy = 1600 + 400 * parseInt(g_day_no / 146097); /* 146097 = 365*400 + 400/4 - 400/100 + 400/400 */ + g_day_no = g_day_no % 146097; + + var leap = true; + if (g_day_no >= 36525) /* 36525 = 365*100 + 100/4 */ + { + g_day_no--; + gy += 100*parseInt(g_day_no/ 36524); /* 36524 = 365*100 + 100/4 - 100/100 */ + g_day_no = g_day_no % 36524; + + if (g_day_no >= 365) + g_day_no++; + else + leap = false; + } + + gy += 4*parseInt(g_day_no/ 1461); /* 1461 = 365*4 + 4/4 */ + g_day_no %= 1461; + + if (g_day_no >= 366) { + leap = false; + + g_day_no--; + gy += parseInt(g_day_no/ 365); + g_day_no = g_day_no % 365; + } + + for (var i = 0; g_day_no >= JalaliDate.g_days_in_month[i] + (i == 1 && leap); i++) + g_day_no -= JalaliDate.g_days_in_month[i] + (i == 1 && leap); + var gm = i+1; + var gd = g_day_no+1; + + return [gy, gm, gd]; +}; + +JalaliDate.checkDate = function(j_y, j_m, j_d) +{ + return !(j_y < 0 || j_y > 32767 || j_m < 1 || j_m > 12 || j_d < 1 || j_d > + (JalaliDate.j_days_in_month[j_m-1] + (j_m == 12 && !((j_y-979)%33%4)))); +}; + +JalaliDate.gregorianToJalali = function(g_y, g_m, g_d) +{ + g_y = parseInt(g_y); + g_m = parseInt(g_m); + g_d = parseInt(g_d); + var gy = g_y-1600; + var gm = g_m-1; + var gd = g_d-1; + + var g_day_no = 365*gy+parseInt((gy+3) / 4)-parseInt((gy+99)/100)+parseInt((gy+399)/400); + + for (var i=0; i < gm; ++i) + g_day_no += JalaliDate.g_days_in_month[i]; + if (gm>1 && ((gy%4==0 && gy%100!=0) || (gy%400==0))) + /* leap and after Feb */ + ++g_day_no; + g_day_no += gd; + + var j_day_no = g_day_no-79; + + var j_np = parseInt(j_day_no/ 12053); + j_day_no %= 12053; + + var jy = 979+33*j_np+4*parseInt(j_day_no/1461); + + j_day_no %= 1461; + + if (j_day_no >= 366) { + jy += parseInt((j_day_no-1)/ 365); + j_day_no = (j_day_no-1)%365; + } + + for (var i = 0; i < 11 && j_day_no >= JalaliDate.j_days_in_month[i]; ++i) { + j_day_no -= JalaliDate.j_days_in_month[i]; + } + var jm = i+1; + var jd = j_day_no+1; + + + return [jy, jm, jd]; +}; + +Date.prototype.setJalaliFullYear = function(y, m, d) { + var gd = this.getDate(); + var gm = this.getMonth(); + var gy = this.getFullYear(); + var j = JalaliDate.gregorianToJalali(gy, gm+1, gd); + if (y < 100) y += 1300; + j[0] = y; + if (m != undefined) { + if (m > 11) { + j[0] += Math.floor(m / 12); + m = m % 12; + } + j[1] = m + 1; + } + if (d != undefined) j[2] = d; + var g = JalaliDate.jalaliToGregorian(j[0], j[1], j[2]); + return this.setFullYear(g[0], g[1]-1, g[2]); +}; + +Date.prototype.setJalaliMonth = function(m, d) { + var gd = this.getDate(); + var gm = this.getMonth(); + var gy = this.getFullYear(); + var j = JalaliDate.gregorianToJalali(gy, gm+1, gd); + if (m > 11) { + j[0] += Math.floor(m / 12); + m = m % 12; + } + j[1] = m+1; + if (d != undefined) j[2] = d; + var g = JalaliDate.jalaliToGregorian(j[0], j[1], j[2]); + return this.setFullYear(g[0], g[1]-1, g[2]); +}; + +Date.prototype.setJalaliDate = function(d) { + var gd = this.getDate(); + var gm = this.getMonth(); + var gy = this.getFullYear(); + var j = JalaliDate.gregorianToJalali(gy, gm+1, gd); + j[2] = d; + var g = JalaliDate.jalaliToGregorian(j[0], j[1], j[2]); + return this.setFullYear(g[0], g[1]-1, g[2]); +}; + +Date.prototype.getJalaliFullYear = function() { + var gd = this.getDate(); + var gm = this.getMonth(); + var gy = this.getFullYear(); + var j = JalaliDate.gregorianToJalali(gy, gm+1, gd); + return j[0]; +}; + +Date.prototype.getJalaliMonth = function() { + var gd = this.getDate(); + var gm = this.getMonth(); + var gy = this.getFullYear(); + var j = JalaliDate.gregorianToJalali(gy, gm+1, gd); + return j[1]-1; +}; + +Date.prototype.getJalaliDate = function() { + var gd = this.getDate(); + var gm = this.getMonth(); + var gy = this.getFullYear(); + var j = JalaliDate.gregorianToJalali(gy, gm+1, gd); + return j[2]; +}; + +Date.prototype.getJalaliDay = function() { + var day = this.getDay(); + day = (day + 1) % 7; + return day; +}; \ No newline at end of file diff --git a/media/system/js/fields/calendar-locales/date/jalali/date-helper.min.js b/media/system/js/fields/calendar-locales/date/jalali/date-helper.min.js new file mode 100644 index 0000000000000..673f00a139c30 --- /dev/null +++ b/media/system/js/fields/calendar-locales/date/jalali/date-helper.min.js @@ -0,0 +1 @@ +Date.gregorian_MD=[31,28,31,30,31,30,31,31,30,31,30,31],Date.local_MD=[31,31,31,31,31,31,30,30,30,30,30,29],Date.SECOND=1e3,Date.MINUTE=60*Date.SECOND,Date.HOUR=60*Date.MINUTE,Date.DAY=24*Date.HOUR,Date.WEEK=7*Date.DAY,Date.prototype.setLocalDateOnly=function(a,b){if("gregorian"!=a)return"";var c=new Date(b);this.setDate(1),this.setFullYear(c.getFullYear()),this.setMonth(c.getMonth()),this.setDate(c.getDate())},Date.prototype.setLocalDate=function(a,b){return"gregorian"!=a?this.setJalaliDate(b):this.setDate(b)},Date.prototype.setLocalMonth=function(a,b,c){return"gregorian"!=a?this.setJalaliMonth(b,c):(void 0==c&&this.getDate(),this.setMonth(b))},Date.prototype.setOtherFullYear=function(a,b){if("gregorian"!=a){var c=new Date(this);return c.setLocalFullYear(b),c.getLocalMonth("jalali")!=this.getLocalMonth("jalali")&&this.setLocalDate("jalali",29),this.setLocalFullYear("jalali",b)}var c=new Date(this);return c.setFullYear(b),c.getMonth()!=this.getMonth()&&this.setDate(28),this.setUTCFullYear(b)},Date.prototype.setLocalFullYear=function(a,b){if("gregorian"!=a)return this.setJalaliFullYear(b);var c=new Date(this);return c.setFullYear(b),c.getMonth()!=this.getMonth()&&this.setDate(28),this.setFullYear(b)},Date.prototype.getLocalWeekDays=function(a,b){return 6},Date.prototype.getOtherFullYear=function(a){return"gregorian"!=a?this.getJalaliFullYear():this.getFullYear()},Date.prototype.getLocalFullYear=function(a){return"gregorian"!=a?this.getJalaliFullYear():this.getFullYear()},Date.prototype.getLocalMonth=function(a){return"gregorian"!=a?this.getJalaliMonth():this.getMonth()},Date.prototype.getLocalDate=function(a){return"gregorian"!=a?this.getJalaliDate():this.getDate()},Date.prototype.getLocalDay=function(a){return"gregorian"!=a?this.getJalaliDay():this.getDay()},Date.prototype.getLocalMonthDays=function(a,b){if("gregorian"==a){var c=this.getFullYear();return"undefined"==typeof b&&(b=this.getMonth()),0!=c%4||0==c%100&&0!=c%400||1!=b?Date.gregorian_MD[b]:29}var c=this.getLocalFullYear("jalali");return"undefined"==typeof b&&(b=this.getLocalMonth("jalali")),0!=c%4||0==c%100&&0!=c%400||1!=b?void Date.local_MD[b]:29},Date.prototype.getLocalWeekNumber=function(a){if("gregorian"!=a){var b=new Date(this.getFullYear(),this.getMonth(),this.getDate(),0,0,0),c=b.getDay();b.setDate(b.getDate()-(c+6)%7+3);var d=b.valueOf();return b.setMonth(0),b.setDate(4),Math.round((d-b.valueOf())/6048e5)+1}var b=new Date(this.getFullYear(),this.getMonth(),this.getDate(),0,0,0),c=b.getDay();b.setDate(b.getDate()-(c+6)%7+3);var d=b.valueOf();return b.setMonth(0),b.setDate(4),Math.round((d-b.valueOf())/6048e5)+1},Date.prototype.getLocalDayOfYear=function(a){if("gregorian"!=a){var b=new Date(this.getOtherFullYear(a),this.getLocalMonth(a),this.getLocalDate(a),0,0,0),c=new Date(this.getOtherFullYear(a),0,0,0,0,0),d=b-c;return Math.floor(d/Date.DAY)}var b=new Date(this.getFullYear(),this.getMonth(),this.getDate(),0,0,0),c=new Date(this.getFullYear(),0,0,0,0,0),d=b-c;return Math.floor(d/Date.DAY)},Date.prototype.getMonthDays=function(a){var b=this.getFullYear();return"undefined"==typeof a&&(a=this.getMonth()),0!=b%4||0==b%100&&0!=b%400||1!=a?"gregorian"==Date.dateType?Date.gregorian_MD[a]:void Date.local_MD[a]:29},Date.prototype.equalsTo=function(a){return this.getFullYear()==a.getFullYear()&&this.getMonth()==a.getMonth()&&this.getDate()==a.getDate()&&this.getHours()==a.getHours()&&this.getMinutes()==a.getMinutes()},Date.localCalToGregorian=function(a,b,c){return JalaliDate.jalaliToGregorian(a,b,c)},Date.gregorianToLocalCal=function(a,b,c){return JalaliDate.gregorianToJalali(a,b,c)},Date.prototype.print=function(a,b,c){if("string"!=typeof b&&(a=""),b||(b="gregorian"),"string"!=typeof a&&(a=""),!a)return"";if("NaN"==this.getLocalDate(b)||!this.getLocalDate(b))return"";var d=this.getLocalMonth(b),e=this.getLocalDate(b),f=this.getLocalFullYear(b),g=this.getLocalWeekNumber(b),h=this.getLocalDay(b),i={},j=this.getHours(),k=j>=12,l=k?j-12:j,m=this.getLocalDayOfYear(b);0==l&&(l=12);var n=this.getMinutes(),o=this.getSeconds();i["%a"]=JoomlaCalLocale.shortDays[h],i["%A"]=JoomlaCalLocale.days[h],i["%b"]=JoomlaCalLocale.shortMonths[d],i["%B"]=JoomlaCalLocale.months[d],i["%C"]=1+Math.floor(f/100),i["%d"]=e<10?"0"+e:e,i["%e"]=e,i["%H"]=j<10?"0"+j:j,i["%I"]=l<10?"0"+l:l,i["%j"]=m<100?m<10?"00"+m:"0"+m:m,i["%k"]=j,i["%l"]=l,i["%m"]=d<9?"0"+(1+d):1+d,i["%M"]=n<10?"0"+n:n,i["%n"]="\n",i["%p"]=k?JoomlaCalLocale.PM:JoomlaCalLocale.AM,i["%P"]=k?JoomlaCalLocale.pm:JoomlaCalLocale.am,i["%s"]=Math.floor(this.getTime()/1e3),i["%S"]=o<10?"0"+o:o,i["%t"]="\t",i["%U"]=i["%W"]=i["%V"]=g<10?"0"+g:g,i["%u"]=h+1,i["%w"]=h,i["%y"]=(""+f).substr(2,2),i["%Y"]=f,i["%%"]="%";var p=/%./g,q=a.replace(p,function(a){return i[a]||a});return"[object Array]"===Object.prototype.toString.call(JoomlaCalLocale.localLangNumbers)&&c&&(q=Date.convertNumbers(q)),q},Date.parseFieldDate=function(a,b,c){var d=new Date,e=0,f=-1,g=0,h=a.split(/\W+/),i=b.match(/%./g),j=0,k=0,l=0,m=0;for(j=0;j29?1900:2e3);break;case"%b":case"%B":for(k=0;k<12;++k)if("gregorian"!=c){if(JoomlaCalLocale.months[k].substr(0,h[j].length).toLowerCase()==h[j].toLowerCase()){f=k;break}}else if(JoomlaCalLocale.months[k].substr(0,h[j].length).toLowerCase()==h[j].toLowerCase()){f=k;break}break;case"%H":case"%I":case"%k":case"%l":l=parseInt(h[j],10);break;case"%P":case"%p":/pm/i.test(h[j])&&l<12?l+=12:/am/i.test(h[j])&&l>=12&&(l-=12);break;case"%M":m=parseInt(h[j],10)}if(isNaN(e)&&(e=d.getFullYear()),isNaN(f)&&(f=d.getMonth()),isNaN(g)&&(g=d.getDate()),isNaN(l)&&(l=d.getHours()),isNaN(m)&&(m=d.getMinutes()),0!=e&&f!=-1&&0!=g)return new Date(e,f,g,l,m,0);for(e=0,f=-1,g=0,j=0;j31&&0==e?(e=parseInt(h[j],10),e<100&&(e+=e>29?1900:2e3)):0==g&&(g=h[j]);return 0==e&&(e=d.getFullYear()),f!=-1&&0!=g?new Date(e,f,g,l,m,0):d},JalaliDate={g_days_in_month:[31,28,31,30,31,30,31,31,30,31,30,31],j_days_in_month:[31,31,31,31,31,31,30,30,30,30,30,29]},JalaliDate.jalaliToGregorian=function(a,b,c){a=parseInt(a),b=parseInt(b),c=parseInt(c);for(var d=a-979,e=b-1,f=c-1,g=365*d+8*parseInt(d/33)+parseInt((d%33+3)/4),h=0;h=36525&&(i--,j+=100*parseInt(i/36524),i%=36524,i>=365?i++:k=!1),j+=4*parseInt(i/1461),i%=1461,i>=366&&(k=!1,i--,j+=parseInt(i/365),i%=365);for(var h=0;i>=JalaliDate.g_days_in_month[h]+(1==h&&k);h++)i-=JalaliDate.g_days_in_month[h]+(1==h&&k);var l=h+1,m=i+1;return[j,l,m]},JalaliDate.checkDate=function(a,b,c){return!(a<0||a>32767||b<1||b>12||c<1||c>JalaliDate.j_days_in_month[b-1]+(12==b&&!((a-979)%33%4)))},JalaliDate.gregorianToJalali=function(a,b,c){a=parseInt(a),b=parseInt(b),c=parseInt(c);for(var d=a-1600,e=b-1,f=c-1,g=365*d+parseInt((d+3)/4)-parseInt((d+99)/100)+parseInt((d+399)/400),h=0;h1&&(d%4==0&&d%100!=0||d%400==0)&&++g,g+=f;var i=g-79,j=parseInt(i/12053);i%=12053;var k=979+33*j+4*parseInt(i/1461);i%=1461,i>=366&&(k+=parseInt((i-1)/365),i=(i-1)%365);for(var h=0;h<11&&i>=JalaliDate.j_days_in_month[h];++h)i-=JalaliDate.j_days_in_month[h];var l=h+1,m=i+1;return[k,l,m]},Date.prototype.setJalaliFullYear=function(a,b,c){var d=this.getDate(),e=this.getMonth(),f=this.getFullYear(),g=JalaliDate.gregorianToJalali(f,e+1,d);a<100&&(a+=1300),g[0]=a,void 0!=b&&(b>11&&(g[0]+=Math.floor(b/12),b%=12),g[1]=b+1),void 0!=c&&(g[2]=c);var h=JalaliDate.jalaliToGregorian(g[0],g[1],g[2]);return this.setFullYear(h[0],h[1]-1,h[2])},Date.prototype.setJalaliMonth=function(a,b){var c=this.getDate(),d=this.getMonth(),e=this.getFullYear(),f=JalaliDate.gregorianToJalali(e,d+1,c);a>11&&(f[0]+=Math.floor(a/12),a%=12),f[1]=a+1,void 0!=b&&(f[2]=b);var g=JalaliDate.jalaliToGregorian(f[0],f[1],f[2]);return this.setFullYear(g[0],g[1]-1,g[2])},Date.prototype.setJalaliDate=function(a){var b=this.getDate(),c=this.getMonth(),d=this.getFullYear(),e=JalaliDate.gregorianToJalali(d,c+1,b);e[2]=a;var f=JalaliDate.jalaliToGregorian(e[0],e[1],e[2]);return this.setFullYear(f[0],f[1]-1,f[2])},Date.prototype.getJalaliFullYear=function(){var a=this.getDate(),b=this.getMonth(),c=this.getFullYear(),d=JalaliDate.gregorianToJalali(c,b+1,a);return d[0]},Date.prototype.getJalaliMonth=function(){var a=this.getDate(),b=this.getMonth(),c=this.getFullYear(),d=JalaliDate.gregorianToJalali(c,b+1,a);return d[1]-1},Date.prototype.getJalaliDate=function(){var a=this.getDate(),b=this.getMonth(),c=this.getFullYear(),d=JalaliDate.gregorianToJalali(c,b+1,a);return d[2]},Date.prototype.getJalaliDay=function(){var a=this.getDay();return a=(a+1)%7}; \ No newline at end of file diff --git a/media/system/js/fields/calendar-locales/en.js b/media/system/js/fields/calendar-locales/en.js new file mode 100644 index 0000000000000..4280fefcf8fe8 --- /dev/null +++ b/media/system/js/fields/calendar-locales/en.js @@ -0,0 +1,19 @@ +window.JoomlaCalLocale = { + today : "Today", + weekend : [0, 6], + wk : "wk", + time : "Time:", + days : ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], + shortDays : ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], + months : ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], + shortMonths : ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], + AM : "AM", + PM : "PM", + am : "am", + pm : "pm", + dateType : "gregorian", + minYear : 1900, + maxYear : 2100, + exit: "Close", + save: "Clear" +}; \ No newline at end of file diff --git a/media/system/js/fields/calendar-locales/fa-ir.js b/media/system/js/fields/calendar-locales/fa-ir.js new file mode 100644 index 0000000000000..1ffca6583ca30 --- /dev/null +++ b/media/system/js/fields/calendar-locales/fa-ir.js @@ -0,0 +1,20 @@ +window.JoomlaCalLocale = { + today : "امروز", + weekend : [5], + wk : "هفته", + time : "زمان", + days : ["یکشنبه","دوشنبه","سه شنبه","چهارشنبه","پنجشنبه","جمعه","شنبه"], + shortDays : ["یک","دو","سه","چهار","پنج","جمعه","شنبه"], + months : ["فروردین","اردیبهشت","خرداد","تیر","مرداد","شهریور","مهر","آبان","آذر","دی","بهمن","اسفند"], + shortMonths : ["فروردین","اردیبهشت","خرداد","تیر","مرداد","شهریور","مهر","آبان","آذر","دی","بهمن","اسفند"], + AM : "ق.ظ.", + PM : "ب.ظ.", + am : "ق.ظ.", + pm : "ب.ظ.", + dateType : "jalali", + minYear : 1268, + maxYear : 1458, + exit: "ستن", + save: "پاک", + localLangNumbers: ["۰","۱","۲","۳","۴","۵","۶","۷","۸","۹"] +}; \ No newline at end of file diff --git a/media/system/js/fields/calendar-locales/fr.js b/media/system/js/fields/calendar-locales/fr.js new file mode 100644 index 0000000000000..9fd1189b9e61c --- /dev/null +++ b/media/system/js/fields/calendar-locales/fr.js @@ -0,0 +1,19 @@ +window.JoomlaCalLocale = { + today : "Aujourd'hui", + weekend : [0, 6], + wk : "wk", + time : "Heure :", + days : ["Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi"], + shortDays : ["Dim", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam"], + months : ["Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre"], + shortMonths : ["Jan", "Fév", "Mar", "Avr", "Mai", "Jui", "Juol", "Aoû", "Sep", "Oct", "Nov", "Déc"], + AM : "AM", + PM : "PM", + am : "am", + pm : "pm", + dateType : "gregorian", + minYear : 1900, + maxYear : 2100, + exit: "Fermer", + save: "Effacer" +}; \ No newline at end of file diff --git a/media/system/js/fields/calendar-locales/prs-af.js b/media/system/js/fields/calendar-locales/prs-af.js new file mode 100644 index 0000000000000..1ffca6583ca30 --- /dev/null +++ b/media/system/js/fields/calendar-locales/prs-af.js @@ -0,0 +1,20 @@ +window.JoomlaCalLocale = { + today : "امروز", + weekend : [5], + wk : "هفته", + time : "زمان", + days : ["یکشنبه","دوشنبه","سه شنبه","چهارشنبه","پنجشنبه","جمعه","شنبه"], + shortDays : ["یک","دو","سه","چهار","پنج","جمعه","شنبه"], + months : ["فروردین","اردیبهشت","خرداد","تیر","مرداد","شهریور","مهر","آبان","آذر","دی","بهمن","اسفند"], + shortMonths : ["فروردین","اردیبهشت","خرداد","تیر","مرداد","شهریور","مهر","آبان","آذر","دی","بهمن","اسفند"], + AM : "ق.ظ.", + PM : "ب.ظ.", + am : "ق.ظ.", + pm : "ب.ظ.", + dateType : "jalali", + minYear : 1268, + maxYear : 1458, + exit: "ستن", + save: "پاک", + localLangNumbers: ["۰","۱","۲","۳","۴","۵","۶","۷","۸","۹"] +}; \ No newline at end of file diff --git a/media/system/js/fields/calendar-vanilla.js b/media/system/js/fields/calendar-vanilla.js new file mode 100644 index 0000000000000..e01f441143226 --- /dev/null +++ b/media/system/js/fields/calendar-vanilla.js @@ -0,0 +1,1070 @@ +/** + * @copyright Copyright (C) 2005 - 2016 Open Source Matters, Inc. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ +!(function(window, document){ + 'use strict'; + + /** Method to convert numbers to local symbols. */ + Date.convertNumbers = function(str) { + var str = str.toString(); + + if (Object.prototype.toString.call(JoomlaCalLocale.localLangNumbers) === '[object Array]') { + for (var i = 0; i < JoomlaCalLocale.localLangNumbers.length; i++) { + str = str.replace(new RegExp(i, 'g'), JoomlaCalLocale.localLangNumbers[i]); + } + } + return str; + }; + + /** Traslates to english numbers a string. */ + Date.toEnglish = function(str) { + str = this.toString(); + var nums = [0,1,2,3,4,5,6,7,8,9]; + for (var i = 0; i < 10; i++) { + str = str.replace(new RegExp(nums[i], 'g'), i); + } + return str; + }; + + var JoomlaCalendar = function (element) { + + // Initialize only if the element exists + if (!element) { + throw new Error("Calendar setup failed:\n No valid element found, Please check your code"); + } + + if (typeof Date.parseFieldDate !== 'function') { + throw new Error("Calendar setup failed:\n No valid date helper, Please check your code"); + } + + if (element._joomlaCalendar) { + throw new Error('JoomlaCalendar instance already exists for the element'); + } + + element._joomlaCalendar = this; + + this.writable = true; + this.params = {}; + this.element = element; + this.inputField = element.getElementsByTagName('input')[0]; + this.button = element.getElementsByTagName('button')[0]; + + if (!this.inputField) { + throw new Error("Calendar setup failed:\n No valid input found, Please check your code"); + } + + // Prepare the parameters + this.params = { + debug: false, + clicked: false, + element: {style: {display: "none"}}, + writable: true + }; + + var self = this, + btn = this.button, + instanceParams = { + inputField : this.inputField, + dateType : JoomlaCalLocale.dateType ? JoomlaCalLocale.dateType : 'gregorian', + direction : (document.dir != undefined) ? document.dir : document.getElementsByTagName("html")[0].getAttribute("dir"), + firstDayOfWeek : btn.getAttribute("data-firstday") ? parseInt(btn.getAttribute("data-firstday")) : 0, + dateFormat : "%Y-%m-%d %H:%M:%S", + weekend : JoomlaCalLocale.weekend ? JoomlaCalLocale.weekend : [0,6], + minYear : JoomlaCalLocale.minYear ? JoomlaCalLocale.minYear : 1900, + maxYear : JoomlaCalLocale.maxYear ? JoomlaCalLocale.maxYear : 2100, + minYearTmp : btn.getAttribute("data-min-year"), + maxYearTmp : btn.getAttribute("data-max-year"), + weekendTmp : btn.getAttribute("data-weekend"), + time24 : true, + showsOthers : (parseInt(btn.getAttribute("data-show-others")) === 1) ? true : false, + showsTime : true, + weekNumbers : (parseInt(btn.getAttribute("data-week-numbers")) === 1) ? true : false, + showsTodayBtn : true, + compressedHeader: (parseInt(btn.getAttribute("data-only-months-nav")) === 1) ? true : false, + }; + + // Keep B/C + if (btn.getAttribute("data-dayformat")) { + instanceParams.dateFormat = btn.getAttribute("data-dayformat") ? btn.getAttribute("data-dayformat") : "%Y-%m-%d %H:%M:%S"; + } + + if (btn.getAttribute("data-time-24")) { + instanceParams.time24 = parseInt(btn.getAttribute("data-time-24")) === 24 ? true : false; + } + + if (btn.getAttribute("data-show-time")) { + instanceParams.showsTime = parseInt(btn.getAttribute("data-show-time")) === 1 ? true : false; + } + + if (btn.getAttribute("data-today-btn")) { + instanceParams.showsTodayBtn = parseInt(btn.getAttribute("data-today-btn")) === 1 ? true : false; + } + + // Merge the parameters + for (var param in instanceParams) { + this.params[param] = instanceParams[param]; + } + + // Evaluate the min year + if (isInt(self.params.minYearTmp)) { + self.params.minYear = getBoundary(parseInt(self.params.minYearTmp), self.params.dateType); + } + // Evaluate the max year + if (isInt(self.params.maxYearTmp)) { + self.params.maxYear = getBoundary(parseInt(self.params.maxYearTmp), self.params.dateType); + } + // Evaluate the weekend days + if (self.params.weekendTmp !== "undefined") { + self.params.weekend = self.params.weekendTmp.split(',').map(function(item) { return parseInt(item, 10); }); + } + + // Event handler need to define here, to be able access in current context + this._dayMouseDown = function(event) { + return self._handleDayMouseDown(event); + }; + this._calKeyEvent = function(event) { + return self._handleCalKeyEvent(event); + }; + this._documentClick = function(event) { + return self._handleDocumentClick(event); + }; + + // Set it up + this.checkInputs(); + + // For the fields with readonly tag calendar will not initiate fully + if (this.inputField.getAttribute('readonly')) + return; + + this._create(); + this._bindEvents(); + }; + + JoomlaCalendar.prototype.checkInputs = function () { + // Get the date from the input + var inputAltValueDate = Date.parseFieldDate(this.inputField.getAttribute('data-alt-value'), this.params.dateFormat, 'gregorian'); + + if (this.inputField.value.length) { + this.date = inputAltValueDate; + this.inputField.value = inputAltValueDate.print(this.params.dateFormat, this.params.dateType, true); + } else { + this.date = new Date(); + } + }; + + /** Time Control */ + JoomlaCalendar.prototype.updateTime = function (hours, mins, secs) { + var self = this, + date = self.date; + + var d = self.date.getLocalDate(self.params.dateType), + m = self.date.getLocalMonth(self.params.dateType), + y = self.date.getLocalFullYear(self.params.dateType), + ampm = this.inputField.parentNode.parentNode.querySelectorAll('.time-ampm')[0]; + + if (!self.params.time24) { + if (/pm/i.test(ampm.value) && hours < 12) + hours = parseInt(hours) + 12; + else if (/am/i.test(ampm.value) && hours == 12) + hours = 0; + } + + date.setHours(hours); + date.setMinutes(parseInt(mins, 10)); + date.setSeconds(date.getSeconds()); + date.setLocalFullYear(self.params.dateType, y); + date.setLocalMonth(self.params.dateType, m); + date.setLocalDate(self.params.dateType, d); + self.dateClicked = false; + + this.callHandler(); + }; + + /** Method to set the date to the given date object */ + JoomlaCalendar.prototype.setDate = function (date) { + if (!date.equalsTo(this.date)) { + this.date = date; + this.processCalendar(this.params.firstDayOfWeek, date); + } + }; + + /** Method to set the current date by a number, step */ + JoomlaCalendar.prototype.moveCursorBy = function (step) { + var date = new Date(this.date); + date.setDate(date.getDate() - step); + this.setDate(date); + }; + + /** Reset select element */ + JoomlaCalendar.prototype.resetSelected = function (element) { + var options = element.options; + var i = options.length; + while (i--) { + var current = options[i]; + if (current.selected) { + current.selected = false; + } + } + }; + + /** Method to set the value for the input field */ + JoomlaCalendar.prototype.callHandler = function () { + /** Output the date **/ + if (this.params.dateType == 'gregorian') { + this.inputField.setAttribute('data-alt-value', this.date.print(this.params.dateFormat, this.params.dateType, false)); + if (this.inputField.getAttribute('data-alt-value') && this.inputField.getAttribute('data-alt-value') != '0000-00-00 00:00:00') { + this.inputField.value = this.date.print(this.params.dateFormat, this.params.dateType, true); + } + } else { + this.inputField.setAttribute('data-alt-value', this.date.print(this.params.dateFormat, 'gregorian', false)); + this.inputField.setAttribute('data-local-value', this.date.print(this.params.dateFormat, this.params.dateType, false)); + this.inputField.value = this.date.print(this.params.dateFormat, this.params.dateType, true); + } + + if (typeof this.inputField.onchange == "function") { + this.inputField.onchange(); + } + + if (this.dateClicked && typeof this.params.onUpdate == "function") { + this.params.onUpdate(this); + } + + if (this.dateClicked) { + this.close(); + } else { + this.processCalendar(); + } + }; + + /** Method to close/hide the calendar */ + JoomlaCalendar.prototype.close = function () { + document.activeElement.blur(); + this.hide(); + }; + + /** Method to show the calendar. */ + JoomlaCalendar.prototype.show = function () { + /** This is needed for IE8 */ + if(navigator.appName.indexOf("Internet Explorer")!=-1){ + var badBrowser=( + navigator.appVersion.indexOf("MSIE 9")==-1 && + navigator.appVersion.indexOf("MSIE 1")==-1 + ); + + if(badBrowser){ + if (window.jQuery && jQuery().chosen) { + var selItems = this.element.getElementsByTagName('select'); + for (var i = 0; i < selItems.length; i++) { + jQuery(selItems[i]).chosen('destroy'); + } + } + } + } + + this.checkInputs(); + this.inputField.focus(); + var rows = this.table.getElementsByTagName("tr"); + for (var i = rows.length; i > 0;) { + var row = rows[--i]; + var cells = row.getElementsByTagName("td"); + for (var j = cells.length; j > 0;) { + var cell = cells[--j]; + } + } + + this.dropdownElement.style.display = "block"; + this.hidden = false; + + document.addEventListener("keydown", this._calKeyEvent, true); + document.addEventListener("keypress", this._calKeyEvent, true); + document.addEventListener("mousedown", this._documentClick, true); + + /** Move the calendar to top position if it doesn't fit below. */ + var containerTmp = this.element.querySelector('.js-calendar'); + + if ((window.innerHeight + window.scrollY) < containerTmp.getBoundingClientRect().bottom + 20) { + containerTmp.style.marginTop = - (containerTmp.getBoundingClientRect().height + this.inputField.getBoundingClientRect().height) + "px"; + } + + this.processCalendar(); + }; + + /** Method to hide the calendar. */ + JoomlaCalendar.prototype.hide = function () { + document.removeEventListener("keydown", this._calKeyEvent, true); + document.removeEventListener("keypress", this._calKeyEvent, true); + document.removeEventListener("mousedown", this._documentClick, true); + + this.dropdownElement.style.display = "none"; + this.hidden = true; + }; + + /** Method to catch clicks outside of the calendar (used as close call) */ + JoomlaCalendar.prototype._handleDocumentClick = function (ev) { + var el = ev.target; + + if (el !== null && !el.classList.contains('time')) { + for (; el !== null && el !== this.element; el = el.parentNode); + } + + if (el === null) { + document.activeElement.blur(); + this.hide(); + return stopCalEvent(ev); + } + }; + + /** Method to handle mouse click events (menus, buttons) **/ + JoomlaCalendar.prototype._handleDayMouseDown = function (ev) { + var self = this, + el = ev.currentTarget, + target = ev.target || ev.srcElement; + + if (el.nodeName !== 'TD') { // A bootstrap inner button was pressed? + var testel = el.getParent('TD'); + if (testel.nodeName === 'TD') { // Yes so use that element's td + el = testel; + } else { // No - try to find the table this way + el = el.getParent('TD'); + if (el.classList.contains('js-calendar')) { el = el.getElementsByTagName('table')[0]; } + } + } else { // Check that doesn't have a button and is not a day td + if (!(target.classList.contains('js-btn')) && !el.classList.contains('day') && !el.classList.contains('title')) { return; } + } + + if (!el || el.disabled) + return false; + + if (typeof el.navtype === "undefined" || el.navtype != 300) { + if (el.navtype == 50) { el._current = el.innerHTML; } + + if (target == el || target.parentNode == el) { self.cellClick(el, ev); } + + var mon = null; + if (typeof el.month != "undefined") mon = el; + if (typeof el.parentNode.month != "undefined") mon = el.parentNode; + var date = null; + if (mon) { + date = new Date(self.date); + if (mon.month != date.getLocalMonth(self.params.dateType)) { + date.setLocalMonth(self.params.dateType, mon.month); + self.setDate(date); + self.dateClicked = false; + this.callHandler(); + } + } else { + var year = null; + if (typeof el.year != "undefined") year = target; + if (typeof el.parentNode.year != "undefined") year = target.parentNode; + if (year) { + date = new Date(self.date); + if (year.year != date.getLocalFullYear(self.params.dateType)) { + date.setFullYear(self.params.dateType, year.year); + self.setDate(date); + self.dateClicked = false; + this.callHandler(); + } + } + } + } + + return stopCalEvent(ev); + }; + + /** Method to handle mouse click events (dates) **/ + JoomlaCalendar.prototype.cellClick = function (el, ev) { + var self = this, + closing = false, + newdate = false, + date = null; + + if (typeof el.navtype == "undefined") { + if (self.currentDateEl) { + el.classList.add("selected"); + self.currentDateEl = el.caldate; + closing = (self.currentDateEl == el.caldate); + if (!closing) { self.currentDateEl = el.caldate; } + } + self.date.setLocalDateOnly('gregorian', el.caldate); + date = self.date; + var other_month = !(self.dateClicked = !el.otherMonth); + if (self.currentDateEl) { newdate = !el.disabled; } + if (other_month) { + this.processCalendar(); + } + } else { + if (el.navtype == 100) { + el.classList.remove("hilite"); + this.inputField.setAttribute('data-alt-value', "0000-00-00 00:00:00"); + this.inputField.setAttribute('value', ''); + this.inputField.value = ''; + this.close(); + return; + } + if (el.navtype == 200) { + this.close(); + return; + } + date = new Date(self.date); + if (el.navtype == 0) { + self.date.setLocalDateOnly('gregorian', new Date()); // TODAY + self.dateClicked = true; + this.callHandler(); + this.close(); + return; + } + + self.dateClicked = false; + var year = date.getOtherFullYear(self.params.dateType), mon = date.getLocalMonth(self.params.dateType); + switch (el.navtype) { + case 400: + break; + case -2: // Prev year + if (!self.params.compressedHeader) + if (year > self.params.minYear) { + date.setOtherFullYear(self.params.dateType, year - 1); + } + break; + case -1: // Prev month + var day = date.getLocalDate(self.params.dateType); + if (mon > 0) { + var max = date.getLocalMonthDays(self.params.dateType, mon - 1); + if (day > max) date.setLocalDate(self.params.dateType, max); + date.setLocalMonth(self.params.dateType, mon - 1); + } else if (year-- > self.params.minYear) { + date.setOtherFullYear(self.params.dateType, year); + var max = date.getLocalMonthDays(self.params.dateType, 11); + if (day > max) date.setLocalDate(self.params.dateType, max); + date.setLocalMonth(self.params.dateType, 11); + } + break; + case 1: // Next month + var day = date.getLocalDate(self.params.dateType); + if (mon < 11) { + var max = date.getLocalMonthDays(self.params.dateType, mon + 1); + if (day > max) date.setLocalDate(self.params.dateType, max); + date.setLocalMonth(self.params.dateType, mon + 1); + } else if (year < self.params.maxYear) { + date.setOtherFullYear(self.params.dateType, year + 1); + var max = date.getLocalMonthDays(self.params.dateType, 0); + if (day > max) date.setLocalDate(self.params.dateType, max); + date.setLocalMonth(self.params.dateType, 0); + } + break; + case 2: // Next year + if (!self.params.compressedHeader) + if (year < self.params.maxYear) { + date.setOtherFullYear(self.params.dateType, year + 1); + } + break; + case 0: // Today + break; + } + + if (!date.equalsTo(self.date)) { + this.setDate(date); + newdate = true; + } else if (el.navtype == 0) { + newdate = closing = true; + } + } + + if (newdate) { + if (self.params.showsTime) + this.dateClicked = false; + ev && this.callHandler(); + } + + el.classList.remove("hilite"); + + if (closing && !self.params.showsTime) { + self.dateClicked = false; + ev && this.close(); + } + }; + + /** Method to handle keyboard click events **/ + JoomlaCalendar.prototype._handleCalKeyEvent = function (ev) { + var self = this, + K = parseInt(ev.keyCode); + + // Get value from input + if (ev.target === this.inputField && (K === 13 || K === 9) && !ev.shiftKey) { + if (this.inputField.value != '') { + self.date = Date.parseFieldDate(this.inputField.value, self.params.dateFormat, self.params.dateType); + this.processCalendar(self.params.firstDayOfWeek, self.date); + this.cellClick(self.currentDateEl, ev); + } else { + this.inputField.value = ''; + this.inputField.setAttribute('value', ''); + this.inputField.setAttribute('data-alt-value', '0000-00-00 00:00:00'); + } + this.close(); + } + + if (self.params.direction == 'rtl') { + if (K == 37) K = 39; + else if (K == 39) K = 37; + } + + if (ev.shiftKey && K === 32) { // KEY Shift + space (now) + this.cellClick(self._nav_now, ev); + } + if (K === 27) { // KEY esc (close); + this.close(); + } + if (ev.shiftKey && K === 13) { // KEY enter (select and close) + if (this.params.showsTime) + this.dateClicked = false; + this.cellClick(self.currentDateEl, ev); + } + if (K === 38) { // KEY up (previous week) + this.moveCursorBy(7); + } + if (K === 40) { // KEY down (next week) + this.moveCursorBy( -7); + } + if (K === 37) { // KEY left (previous day) + this.moveCursorBy(1); + } + if (K === 39) { // KEY right (next day) + this.moveCursorBy( -1); + } + if (ev.target === this.inputField && !(K>48 || K<57 || K===186 || K===189 || K===190 || K === 32)) + return stopCalEvent(ev); + }; + + /** Method to create the html stracture of the calendar */ + JoomlaCalendar.prototype._create = function () { + var self = this, + parent = this.element, + table = createElement("table"), + div = createElement("div"); + + this.table = table; + table.className = 'table'; + table.cellSpacing = 0; + table.cellPadding = 0; + table.style.marginBottom = 0; + + this.dropdownElement = div; + parent.appendChild(div); + + if (this.params.direction) { + div.style.direction = this.params.direction; + } + + div.className = 'js-calendar'; + div.style.position = "absolute"; + div.style.boxShadow = "0px 0px 70px 0px rgba(0,0,0,0.67)"; + div.style.minWidth = this.inputField.width; + div.style.padding = '0'; + div.style.display = "none"; + div.style.left = "auto"; + div.style.top = "auto"; + div.style.zIndex = 1060; + div.style.borderRadius = "20px"; + + this.wrapper = createElement('div'); + this.wrapper.className = 'calendar-container'; + div.appendChild(this.wrapper); + this.wrapper.appendChild(table); + + var thead = createElement("thead", table); + thead.className = 'calendar-header'; + + var cell = null, + row = null, + cal = this, + hh = function (text, cs, navtype, node, styles, classes) { + node = node ? node : "td"; + classes = classes ? 'class="' + classes + '"' : ''; + styles = styles ? styles : {}; + cell = createElement(node, row); + cell.colSpan = cs; + for (var key in styles) { + cell.style[key] = styles[key]; + } + if (navtype != 0 && Math.abs(navtype) <= 2) { cell.className += " nav"; } + + cell.addEventListener("mousedown", self._dayMouseDown, true); + + cell.calendar = cal; + cell.navtype = navtype; + if (navtype != 0 && Math.abs(navtype) <= 2) { + cell.innerHTML = "" + text + ""; + } else { + cell.innerHTML = "
" + text + "
"; + } + return cell; + }; + + if (this.params.compressedHeader === false) { // Head - year + row = createElement("tr", thead); + row.className = "calendar-head-row"; + this._nav_py = hh("‹", 1, -2, '', {"text-align": "center", "font-size": "2em", "line-height": "1em"}, 'js-btn btn-prev-year'); // Previous year button + this.title = hh('
', this.params.weekNumbers ? 6 : 5, 300); + this.title.className = "title"; + this._nav_ny = hh(" ›", 1, 2, '', {"text-align": "center", "font-size": "2em", "line-height": "1em"}, 'js-btn btn-next-year'); // Next year button + } + + row = createElement("tr", thead); // Head - month + row.className = "calendar-head-row"; + this._nav_pm = hh("‹", 1, -1, '', {"text-align": "center", "font-size": "2em", "line-height": "1em"}, 'js-btn btn-prev-month'); // Previous month button + this._nav_month = hh('
', this.params.weekNumbers ? 6 : 5, 888, 'td', {'textAlign': 'center'}); + this._nav_month.className = "title"; + this._nav_nm = hh(" ›", 1, 1, '', {"text-align": "center", "font-size": "2em", "line-height": "1em"}, 'js-btn btn-next-month'); // Next month button + + row = createElement("tr", thead); // day names + row.className = "daynames"; + if (this.params.weekNumbers) { + cell = createElement("td", row); + cell.className = "day-name wn"; + cell.innerHTML = JoomlaCalLocale.wk; + } + for (var i = 7; i > 0; --i) { + cell = createElement("td", row); + if (!i) { cell.calendar = self; } + } + this.firstdayname = (this.params.weekNumbers) ? row.firstChild.nextSibling : row.firstChild; + + var fdow = this.params.firstDayOfWeek, + cell = this.firstdayname, + weekend = JoomlaCalLocale.weekend; + + for (var i = 0; i < 7; ++i) { + var realday = (i + fdow) % 7; + cell.classList.add("day-name"); + this.params.weekNumbers ? cell.classList.add('day-name-week') : ''; + + if (i) { + cell.calendar = self; + cell.fdow = realday; + } + if (weekend.indexOf(weekend) != -1) { cell.classList.add("weekend"); } + + cell.innerHTML = JoomlaCalLocale.shortDays[(i + fdow) % 7]; + cell = cell.nextSibling; + } + + var tbody = createElement("tbody", table); + this.tbody = tbody; + for (i = 6; i > 0; --i) { + row = createElement("tr", tbody); + if (this.params.weekNumbers) { cell = createElement("td", row); } + + for (var j = 7; j > 0; --j) { + cell = createElement("td", row); + cell.calendar = this; + cell.addEventListener("mousedown", this._dayMouseDown, true); + } + } + + if (this.params.showsTime) { + row = createElement("tr", tbody); + row.className = "time"; + + cell = createElement("td", row); + cell.className = "time time-title"; + cell.colSpan = 1; + cell.style.verticalAlign = 'middle'; + cell.innerHTML = JoomlaCalLocale.time || " "; + + var cell1 = createElement("td", row); + cell1.className = "time hours-select"; + cell1.colSpan = 2; + + var cell2 = createElement("td", row); + cell2.className = "time minutes-select"; + cell2.colSpan = 2; + + (function () { + function makeTimePart(className, selected, range_start, range_end, cellTml) { + var part = createElement("select", cellTml), num; + part.calendar = self; + part.className = className; + part.setAttribute('data-chosen', true); // avoid Chosen, hack + part.style.width = '100%'; + part.navtype = 50; + part._range = []; + for (var i = range_start; i <= range_end; ++i) { + var txt, selAttr = ''; + if (i == selected) + selAttr = true; + if (i < 10 && range_end >= 10) { + num = '0' + i; + txt = Date.convertNumbers('0') + Date.convertNumbers(i); + } else { + num = '' + i; + txt = '' + Date.convertNumbers(i); + } + part.options.add(new Option(txt, num, selAttr, selAttr)); + } + return part; + } + var hrs = self.date.getHours(), + mins = self.date.getMinutes(), + t12 = !self.params.time24, + pm = (self.date.getHours() > 12); + + if (t12 && pm) { + hrs -= 12; + } + + var H = makeTimePart("time time-hours", hrs, t12 ? 1 : 0, t12 ? 12 : 23, cell1), + M = makeTimePart("time time-minutes", mins, 0, 59, cell2), + AP = null; + + cell = createElement("td", row); + cell.className = "time ampm-select"; + cell.colSpan = self.params.weekNumbers ? 1 : 2; + + if (t12) { + var selAttr = true, + altDate = Date.parseFieldDate(self.inputField.getAttribute('data-alt-value'), self.params.dateFormat, 'gregorian'); + pm = (altDate.getHours() > 12); + + var part = createElement("select", cell); + part.className = "time-ampm"; + part.style.width = '100%'; + part.options.add(new Option(JoomlaCalLocale.PM, "pm", pm ? selAttr : '', pm ? selAttr : '')); + part.options.add(new Option(JoomlaCalLocale.AM, "am", pm ? '' : selAttr, pm ? '' : selAttr)); + AP = part; + + // Event listener for the am/pm select + AP.addEventListener("change", function (event) { + self.updateTime(event.target.parentNode.parentNode.childNodes[1].childNodes[0].value, + event.target.parentNode.parentNode.childNodes[2].childNodes[0].value, + event.target.parentNode.parentNode.childNodes[3].childNodes[0].value); + }, false); + } else { + cell.innerHTML = " "; + cell.colSpan = self.params.weekNumbers ? 4 : 3; + } + + H.addEventListener("change", function (event) { + self.updateTime(event.target.parentNode.parentNode.childNodes[1].childNodes[0].value, + event.target.parentNode.parentNode.childNodes[2].childNodes[0].value, + event.target.parentNode.parentNode.childNodes[3].childNodes[0].value); + }, false); + M.addEventListener("change", function (event) { + self.updateTime(event.target.parentNode.parentNode.childNodes[1].childNodes[0].value, + event.target.parentNode.parentNode.childNodes[2].childNodes[0].value, + event.target.parentNode.parentNode.childNodes[3].childNodes[0].value); + }, false); + })(); + } + + row = createElement("tr", tbody); + row.className = "btn-row"; + var clearAttr = this.inputField.hasAttribute('required') ? 'none;' : 'block;'; + this._nav_save = hh('' + + JoomlaCalLocale.save + '', 2, 100, 'td', {'textAlign': 'center'}); + + if (!this.inputField.hasAttribute('required')) { + var savea = row.querySelector('a[data-action="clear"]'); + savea.addEventListener("click", + function (e) { + var el = savea.parentNode.parentNode; + if (el.tagName === 'TD') { + self.cellClick(self._nav_save, e); + } + }, true); + } + + if (this.params.showsTodayBtn) { // Head - today + + this._nav_now = hh('' + + JoomlaCalLocale.today + '', this.params.weekNumbers ? 4 : 3, 0, 'td', {'textAlign': 'center'}); + var todaya = row.querySelector('a[data-action="today"]'); + todaya.addEventListener('click', function (e) { + var el = todaya.parentNode.parentNode; + if (el.tagName === 'TD') { self.cellClick(self._nav_now, e); } + }, true); + } else { + cell = createElement("td", row); + cell.innerHTML = " "; + cell.colSpan = this.params.weekNumbers ? 4 : 3; + } + + this._nav_exit = hh('' + + JoomlaCalLocale.exit + '', 2, 200, 'td', {'textAlign': 'center'}); + var exita = row.querySelector('a[data-action="exit"]'); + exita.addEventListener('click', function (e) { + var el = exita.parentNode.parentNode; + if (el.tagName === 'TD') { self.cellClick(self._nav_exit, e); } + }, true); + + this.processCalendar(); + }; + + /** Method to append numbers to the calendar table */ + JoomlaCalendar.prototype.processCalendar = function () { + this.table.style.visibility = "hidden"; + + var firstDayOfWeek = this.params.firstDayOfWeek, + date = this.date, + today = new Date(), + TY = today.getLocalFullYear(this.params.dateType), + TM = today.getLocalMonth(this.params.dateType), + TD = today.getLocalDate(this.params.dateType), + year = date.getOtherFullYear(this.params.dateType), + hrs = date.getHours(), + mins = date.getMinutes(), + secs = date.getSeconds(), + t12 = !this.params.time24; + + if (year < this.params.minYear) { // Check min,max year + year = this.params.minYear; + date.getOtherFullYear(this.params.dateType, year); + } else if (year > this.params.maxYear) { + year = this.params.maxYear; + date.getOtherFullYear(this.params.dateType, year); + } + + this.params.firstDayOfWeek = firstDayOfWeek; + this.date = new Date(date); + + var month = date.getLocalMonth(this.params.dateType); + var mday = date.getLocalDate(this.params.dateType); + + // Compute the first day that would actually be displayed in the calendar, even if it's from the previous month. + date.setLocalDate(this.params.dateType, 1); + var day1 = (date.getLocalDay(this.params.dateType) - this.params.firstDayOfWeek) % 7; + + if (day1 < 0) { + day1 += 7; + } + + date.setLocalDate(this.params.dateType, - day1); + date.setLocalDate(this.params.dateType, date.getLocalDate(this.params.dateType) + 1); + + var row = this.tbody.firstChild, + ar_days = this.ar_days = new Array(), + weekend = JoomlaCalLocale.weekend, + monthDays = parseInt(date.getLocalWeekDays(this.params.dateType)); + + /** Fill the table **/ + for (var i = 0; i < monthDays; ++i, row = row.nextSibling) { + var cell = row.firstChild; + if (this.params.weekNumbers) { + cell.className = "day wn"; + cell.innerHTML = date.getLocalWeekNumber(this.params.dateType); //date.convertNumbers(); + cell = cell.nextSibling; + } + + row.className = "daysrow"; + var hasdays = false, iday, + dpos = ar_days[i] = [], + totalDays = monthDays + 1; + + for (var j = 0; j < totalDays; ++j, cell = cell.nextSibling, date.setLocalDate(this.params.dateType, iday + 1)) { + cell.className = "day"; + cell.style['textAlign'] = 'center'; + iday = date.getLocalDate(this.params.dateType); + var wday = date.getLocalDay(this.params.dateType); + cell.pos = i << 4 | j; + dpos[j] = cell; + var current_month = (date.getLocalMonth(this.params.dateType) == month); + if (!current_month) { + if (this.params.showsOthers) { + cell.className += " disabled othermonth "; + cell.otherMonth = true; + } else { + cell.className += " emptycell"; + cell.innerHTML = " "; + cell.disabled = true; + continue; + } + } else { + cell.otherMonth = false; + hasdays = true; + cell.style.cursor = "pointer"; + } + cell.disabled = false; + cell.innerHTML = this.params.debug ? iday : Date.convertNumbers(iday); // translated day number for each cell + if (!cell.disabled) { + cell.caldate = new Date(date); + if (current_month && iday == mday) { + cell.className += " selected"; + this.currentDateEl = cell; + } + if (date.getLocalFullYear(this.params.dateType) == TY && date.getLocalMonth(this.params.dateType) == TM && iday == TD) { + cell.className += " today"; + } + if (weekend.indexOf(wday) != -1) + cell.className += " weekend"; + } + } + if (!(hasdays || this.params.showsOthers)) { + row.style.display = 'none'; + row.className = "emptyrow"; + } else { + row.style.display = ''; + } + } + + /* Set the time */ + if (this.params.showsTime) { + if (hrs > 12 && t12) hrs -= 12; + + hrs = (hrs < 10) ? "0" + hrs : hrs; + mins = (mins < 10) ? "0" + mins : mins; + + var hoursEl = this.table.querySelector('.time-hours'), + minsEl = this.table.querySelector('.time-minutes'); + + /* remove the selected class for the hours*/ + this.resetSelected(hoursEl); + hoursEl.value = hrs; + + /* remove the selected class for the minutes*/ + this.resetSelected(minsEl); + minsEl.value = mins; + + if (!this.params.time24) + { + var dateAlt = new Date(this.inputField.getAttribute('data-alt-value')), + ampmEl = this.table.querySelector('.time-ampm'), + hrsAlt = dateAlt.getHours(); + + if (hrsAlt > 12) { + /* remove the selected class for the am-pm*/ + this.resetSelected(ampmEl); + ampmEl.value = 'pm'; + } + } + } + + if (!this.params.compressedHeader) { + this._nav_month.getElementsByTagName('span')[0].innerHTML = this.params.debug ? month + ' ' + JoomlaCalLocale.months[month] : JoomlaCalLocale.months[month]; + this.title.getElementsByTagName('span')[0].innerHTML = this.params.debug ? year + ' ' + Date.convertNumbers(year.toString()) : Date.convertNumbers(year.toString()); + } else { + var tmpYear = Date.convertNumbers(year.toString()); + this._nav_month.getElementsByTagName('span')[0].innerHTML = !this.params.monthBefore ? JoomlaCalLocale.months[month] + ' - ' + tmpYear : tmpYear + ' - ' + JoomlaCalLocale.months[month] ; + } + this.table.style.visibility = "visible"; + }; + + /** Method to listen for the click event on the input button. **/ + JoomlaCalendar.prototype._bindEvents = function () { + var self = this; + this.inputField.addEventListener('focus', function() { + self.show(); + }, true); + this.inputField.addEventListener('blur', function(event) { + if (event.relatedTarget != null && (event.relatedTarget.classList.contains('time-hours') || event.relatedTarget.classList.contains('time-minutes') || event.relatedTarget.classList.contains('time-ampm'))) return; + var elem = event.target; + while (elem.parentNode) { + elem = elem.parentNode; + if (elem.classList.contains('field-calendar')) return; + } + self.close(); + }, true); + this.button.addEventListener('click', function() { + self.show(); + }, false); + }; + + /** Helpers **/ + var stopCalEvent = function (ev) { ev || (ev = window.event); ev.preventDefault(); ev.stopPropagation(); return false; }; + var createElement = function (type, parent) { var el = null; el = document.createElement(type); if (typeof parent != "undefined") { parent.appendChild(el); } return el; }; + var isInt = function (input) { return !isNaN(input) && (function(x) { return (x | 0) === x; })(parseFloat(input)) }; + var getBoundary = function (input, type) { var date = new Date(); var y = date.getLocalFullYear(type); return y + input; }; + /** + * IE8 polyfill for indexOf() + */ + if (!Array.prototype.indexOf) { + Array.prototype.indexOf = function(elt) { + var len = this.length >>> 0, + from = Number(arguments[1]) || 0; + + from = (from < 0) ? Math.ceil(from) : Math.floor(from); + + if (from < 0) { + from += len; + } + + for (; from < len; from++) { + if (from in this && this[from] === elt) { + return from; + } + } + return -1; + }; + } + + /** Method to get the active calendar element through any descendant element. */ + JoomlaCalendar.getCalObject = function(element) { + if (!element) { + return false; + } + while (element.parentNode) { + element = element.parentNode; + if (element.classList.contains('field-calendar')) { + return element; + } + } + return false; + }; + + /** Method to change input values with the data-alt-value values. **/ + JoomlaCalendar.prototype.setAltValue = function() { + var input = this.inputField; + + if (input.getAttribute("data-alt-value") && input.getAttribute("data-alt-value")) { + input.value = input.getAttribute("data-alt-value"); + } else { + input.value = ''; + } + }; + + /** Init the Calendars on the page */ + JoomlaCalendar.init = function (className) { + var elements, i, instance; + + elements = document.querySelectorAll(className); + + // Fall back for translation strings + window.JoomlaCalLocale = window.JoomlaCalLocale ? JoomlaCalLocale : {}; + JoomlaCalLocale.today = JoomlaCalLocale.today ? JoomlaCalLocale.today : 'today'; + JoomlaCalLocale.weekend = JoomlaCalLocale.weekend ? JoomlaCalLocale.weekend : [0,6]; + JoomlaCalLocale.localLangNumbers = JoomlaCalLocale.localLangNumbers ? JoomlaCalLocale.localLangNumbers : [0,1,2,3,4,5,6,7,8,9]; + JoomlaCalLocale.wk = JoomlaCalLocale.wk ? JoomlaCalLocale.wk : 'wk'; + JoomlaCalLocale.AM = JoomlaCalLocale.AM ? JoomlaCalLocale.AM : 'AM'; + JoomlaCalLocale.PM = JoomlaCalLocale.PM ? JoomlaCalLocale.PM : 'PM'; + JoomlaCalLocale.am = JoomlaCalLocale.am ? JoomlaCalLocale.am : 'am'; + JoomlaCalLocale.pm = JoomlaCalLocale.pm ? JoomlaCalLocale.pm : 'pm'; + JoomlaCalLocale.dateType = JoomlaCalLocale.dateType ? JoomlaCalLocale.dateType : 'gregorian'; + JoomlaCalLocale.time = JoomlaCalLocale.time ? JoomlaCalLocale.time : 'time'; + JoomlaCalLocale.days = JoomlaCalLocale.days ? JoomlaCalLocale.days : '["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]'; + JoomlaCalLocale.shortDays = JoomlaCalLocale.shortDays ? JoomlaCalLocale.shortDays : ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]; + JoomlaCalLocale.months = JoomlaCalLocale.months ? JoomlaCalLocale.months : ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; + JoomlaCalLocale.shortMonths = JoomlaCalLocale.shortMonths ? JoomlaCalLocale.shortMonths : ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; + JoomlaCalLocale.minYear = JoomlaCalLocale.minYear ? JoomlaCalLocale.minYear : 1900; + JoomlaCalLocale.maxYear = JoomlaCalLocale.maxYear ? JoomlaCalLocale.maxYear : 2100; + JoomlaCalLocale.exit = JoomlaCalLocale.exit ? JoomlaCalLocale.exit : 'Cancel'; + JoomlaCalLocale.clear = JoomlaCalLocale.clear ? JoomlaCalLocale.clear : 'Clear'; + + for (i = 0; i < elements.length; i++) { + var element = elements[i]; + instance = element._joomlaCalendar; + + if (!instance) { + instance = new JoomlaCalendar(element); + instance.inputField.form.addEventListener('submit', function () { + instance.setAltValue(); + }); + } + } + }; + + window.JoomlaCalendar = JoomlaCalendar; + + /** Instantiate all the calendar fields when the document is ready */ + document.addEventListener("DOMContentLoaded", function() { + JoomlaCalendar.init(".field-calendar"); + }); + +})(window, document); diff --git a/media/system/js/fields/calendar-vanilla.min.js b/media/system/js/fields/calendar-vanilla.min.js new file mode 100644 index 0000000000000..b0cd29a6ec09e --- /dev/null +++ b/media/system/js/fields/calendar-vanilla.min.js @@ -0,0 +1 @@ +!function(a,b){"use strict";Date.convertNumbers=function(a){var a=a.toString();if("[object Array]"===Object.prototype.toString.call(JoomlaCalLocale.localLangNumbers))for(var b=0;b0;)for(var g=f[--e],h=g.getElementsByTagName("td"),i=h.length;i>0;){h[--i]}this.dropdownElement.style.display="block",this.hidden=!1,b.addEventListener("keydown",this._calKeyEvent,!0),b.addEventListener("keypress",this._calKeyEvent,!0),b.addEventListener("mousedown",this._documentClick,!0);var k=this.element.querySelector(".js-calendar");a.innerHeight+a.scrollYc.params.minYear&&f.setOtherFullYear(c.params.dateType,h-1);break;case-1:var j=f.getLocalDate(c.params.dateType);if(i>0){var k=f.getLocalMonthDays(c.params.dateType,i-1);j>k&&f.setLocalDate(c.params.dateType,k),f.setLocalMonth(c.params.dateType,i-1)}else if(h-- >c.params.minYear){f.setOtherFullYear(c.params.dateType,h);var k=f.getLocalMonthDays(c.params.dateType,11);j>k&&f.setLocalDate(c.params.dateType,k),f.setLocalMonth(c.params.dateType,11)}break;case 1:var j=f.getLocalDate(c.params.dateType);if(i<11){var k=f.getLocalMonthDays(c.params.dateType,i+1);j>k&&f.setLocalDate(c.params.dateType,k),f.setLocalMonth(c.params.dateType,i+1)}else if(hk&&f.setLocalDate(c.params.dateType,k),f.setLocalMonth(c.params.dateType,0)}break;case 2:c.params.compressedHeader||h48||c<57||186===c||189===c||190===c||32===c))return d(a)},c.prototype._create=function(){var a=this,b=this.element,c=e("table"),d=e("div");this.table=c,c.className="table",c.cellSpacing=0,c.cellPadding=0,c.style.marginBottom=0,this.dropdownElement=d,b.appendChild(d),this.params.direction&&(d.style.direction=this.params.direction),d.className="js-calendar",d.style.position="absolute",d.style.boxShadow="0px 0px 70px 0px rgba(0,0,0,0.67)",d.style.minWidth=this.inputField.width,d.style.padding="0",d.style.display="none",d.style.left="auto",d.style.top="auto",d.style.zIndex=1060,d.style.borderRadius="20px",this.wrapper=e("div"),this.wrapper.className="calendar-container",d.appendChild(this.wrapper),this.wrapper.appendChild(c);var f=e("thead",c);f.className="calendar-header";var g=null,h=null,i=this,j=function(b,c,d,f,j,k){f=f?f:"td",k=k?'class="'+k+'"':"",j=j?j:{},g=e(f,h),g.colSpan=c;for(var l in j)g.style[l]=j[l];return 0!=d&&Math.abs(d)<=2&&(g.className+=" nav"),g.addEventListener("mousedown",a._dayMouseDown,!0),g.calendar=i,g.navtype=d,0!=d&&Math.abs(d)<=2?g.innerHTML=""+b+"":g.innerHTML="
"+b+"
",g};this.params.compressedHeader===!1&&(h=e("tr",f),h.className="calendar-head-row",this._nav_py=j("‹",1,-2,"",{"text-align":"center","font-size":"2em","line-height":"1em"},"js-btn btn-prev-year"),this.title=j('
',this.params.weekNumbers?6:5,300),this.title.className="title",this._nav_ny=j(" ›",1,2,"",{"text-align":"center","font-size":"2em","line-height":"1em"},"js-btn btn-next-year")),h=e("tr",f),h.className="calendar-head-row",this._nav_pm=j("‹",1,-1,"",{"text-align":"center","font-size":"2em","line-height":"1em"},"js-btn btn-prev-month"),this._nav_month=j('
',this.params.weekNumbers?6:5,888,"td",{textAlign:"center"}),this._nav_month.className="title",this._nav_nm=j(" ›",1,1,"",{"text-align":"center","font-size":"2em","line-height":"1em"},"js-btn btn-next-month"),h=e("tr",f),h.className="daynames",this.params.weekNumbers&&(g=e("td",h),g.className="day-name wn",g.innerHTML=JoomlaCalLocale.wk);for(var k=7;k>0;--k)g=e("td",h),k||(g.calendar=a);this.firstdayname=this.params.weekNumbers?h.firstChild.nextSibling:h.firstChild;for(var l=this.params.firstDayOfWeek,g=this.firstdayname,m=JoomlaCalLocale.weekend,k=0;k<7;++k){var n=(k+l)%7;g.classList.add("day-name"),this.params.weekNumbers?g.classList.add("day-name-week"):"",k&&(g.calendar=a,g.fdow=n),m.indexOf(m)!=-1&&g.classList.add("weekend"),g.innerHTML=JoomlaCalLocale.shortDays[(k+l)%7],g=g.nextSibling}var o=e("tbody",c);for(this.tbody=o,k=6;k>0;--k){h=e("tr",o),this.params.weekNumbers&&(g=e("td",h));for(var p=7;p>0;--p)g=e("td",h),g.calendar=this,g.addEventListener("mousedown",this._dayMouseDown,!0)}if(this.params.showsTime){h=e("tr",o),h.className="time",g=e("td",h),g.className="time time-title",g.colSpan=1,g.style.verticalAlign="middle",g.innerHTML=JoomlaCalLocale.time||" ";var q=e("td",h);q.className="time hours-select",q.colSpan=2;var r=e("td",h);r.className="time minutes-select",r.colSpan=2,function(){function b(b,c,d,f,g){var i,h=e("select",g);h.calendar=a,h.className=b,h.setAttribute("data-chosen",!0),h.style.width="100%",h.navtype=50,h._range=[];for(var j=d;j<=f;++j){var k,l="";j==c&&(l=!0),j<10&&f>=10?(i="0"+j,k=Date.convertNumbers("0")+Date.convertNumbers(j)):(i=""+j,k=""+Date.convertNumbers(j)),h.options.add(new Option(k,i,l,l))}return h}var c=a.date.getHours(),d=a.date.getMinutes(),f=!a.params.time24,i=a.date.getHours()>12;f&&i&&(c-=12);var j=b("time time-hours",c,f?1:0,f?12:23,q),k=b("time time-minutes",d,0,59,r),l=null;if(g=e("td",h),g.className="time ampm-select",g.colSpan=a.params.weekNumbers?1:2,f){var m=!0,n=Date.parseFieldDate(a.inputField.getAttribute("data-alt-value"),a.params.dateFormat,"gregorian");i=n.getHours()>12;var o=e("select",g);o.className="time-ampm",o.style.width="100%",o.options.add(new Option(JoomlaCalLocale.PM,"pm",i?m:"",i?m:"")),o.options.add(new Option(JoomlaCalLocale.AM,"am",i?"":m,i?"":m)),l=o,l.addEventListener("change",function(b){a.updateTime(b.target.parentNode.parentNode.childNodes[1].childNodes[0].value,b.target.parentNode.parentNode.childNodes[2].childNodes[0].value,b.target.parentNode.parentNode.childNodes[3].childNodes[0].value)},!1)}else g.innerHTML=" ",g.colSpan=a.params.weekNumbers?4:3;j.addEventListener("change",function(b){a.updateTime(b.target.parentNode.parentNode.childNodes[1].childNodes[0].value,b.target.parentNode.parentNode.childNodes[2].childNodes[0].value,b.target.parentNode.parentNode.childNodes[3].childNodes[0].value)},!1),k.addEventListener("change",function(b){a.updateTime(b.target.parentNode.parentNode.childNodes[1].childNodes[0].value,b.target.parentNode.parentNode.childNodes[2].childNodes[0].value,b.target.parentNode.parentNode.childNodes[3].childNodes[0].value)},!1)}()}h=e("tr",o),h.className="btn-row";var s=this.inputField.hasAttribute("required")?"none;":"block;";if(this._nav_save=j(''+JoomlaCalLocale.save+"",2,100,"td",{textAlign:"center"}),!this.inputField.hasAttribute("required")){var t=h.querySelector('a[data-action="clear"]');t.addEventListener("click",function(b){var c=t.parentNode.parentNode;"TD"===c.tagName&&a.cellClick(a._nav_save,b)},!0)}if(this.params.showsTodayBtn){this._nav_now=j(''+JoomlaCalLocale.today+"",this.params.weekNumbers?4:3,0,"td",{textAlign:"center"});var u=h.querySelector('a[data-action="today"]');u.addEventListener("click",function(b){var c=u.parentNode.parentNode;"TD"===c.tagName&&a.cellClick(a._nav_now,b)},!0)}else g=e("td",h),g.innerHTML=" ",g.colSpan=this.params.weekNumbers?4:3;this._nav_exit=j(''+JoomlaCalLocale.exit+"",2,200,"td",{textAlign:"center"});var v=h.querySelector('a[data-action="exit"]');v.addEventListener("click",function(b){var c=v.parentNode.parentNode;"TD"===c.tagName&&a.cellClick(a._nav_exit,b)},!0),this.processCalendar()},c.prototype.processCalendar=function(){this.table.style.visibility="hidden";var a=this.params.firstDayOfWeek,b=this.date,c=new Date,d=c.getLocalFullYear(this.params.dateType),e=c.getLocalMonth(this.params.dateType),f=c.getLocalDate(this.params.dateType),g=b.getOtherFullYear(this.params.dateType),h=b.getHours(),i=b.getMinutes(),k=(b.getSeconds(),!this.params.time24);gthis.params.maxYear&&(g=this.params.maxYear,b.getOtherFullYear(this.params.dateType,g)),this.params.firstDayOfWeek=a,this.date=new Date(b);var l=b.getLocalMonth(this.params.dateType),m=b.getLocalDate(this.params.dateType);b.setLocalDate(this.params.dateType,1);var n=(b.getLocalDay(this.params.dateType)-this.params.firstDayOfWeek)%7;n<0&&(n+=7),b.setLocalDate(this.params.dateType,-n),b.setLocalDate(this.params.dateType,b.getLocalDate(this.params.dateType)+1);for(var o=this.tbody.firstChild,p=this.ar_days=new Array,q=JoomlaCalLocale.weekend,r=parseInt(b.getLocalWeekDays(this.params.dateType)),s=0;s12&&k&&(h-=12),h=h<10?"0"+h:h,i=i<10?"0"+i:i;var B=this.table.querySelector(".time-hours"),C=this.table.querySelector(".time-minutes");if(this.resetSelected(B),B.value=h,this.resetSelected(C),C.value=i,!this.params.time24){var D=new Date(this.inputField.getAttribute("data-alt-value")),E=this.table.querySelector(".time-ampm"),F=D.getHours();F>12&&(this.resetSelected(E),E.value="pm")}}if(this.params.compressedHeader){var G=Date.convertNumbers(g.toString());this._nav_month.getElementsByTagName("span")[0].innerHTML=this.params.monthBefore?G+" - "+JoomlaCalLocale.months[l]:JoomlaCalLocale.months[l]+" - "+G}else this._nav_month.getElementsByTagName("span")[0].innerHTML=this.params.debug?l+" "+JoomlaCalLocale.months[l]:JoomlaCalLocale.months[l],this.title.getElementsByTagName("span")[0].innerHTML=this.params.debug?g+" "+Date.convertNumbers(g.toString()):Date.convertNumbers(g.toString());this.table.style.visibility="visible"},c.prototype._bindEvents=function(){var a=this;this.inputField.addEventListener("focus",function(){a.show()},!0),this.inputField.addEventListener("blur",function(b){if(null==b.relatedTarget||!(b.relatedTarget.classList.contains("time-hours")||b.relatedTarget.classList.contains("time-minutes")||b.relatedTarget.classList.contains("time-ampm"))){for(var c=b.target;c.parentNode;)if(c=c.parentNode,c.classList.contains("field-calendar"))return;a.close()}},!0),this.button.addEventListener("click",function(){a.show()},!1)};var d=function(b){return b||(b=a.event),b.preventDefault(),b.stopPropagation(),!1},e=function(a,c){var d=null;return d=b.createElement(a),"undefined"!=typeof c&&c.appendChild(d),d},f=function(a){return!isNaN(a)&&function(a){return(0|a)===a}(parseFloat(a))},g=function(a,b){var c=new Date,d=c.getLocalFullYear(b);return d+a};Array.prototype.indexOf||(Array.prototype.indexOf=function(a){var b=this.length>>>0,c=Number(arguments[1])||0;for(c=c<0?Math.ceil(c):Math.floor(c),c<0&&(c+=b);c +
+
+
+ + +
+
+ +
+ diff --git a/tests/javascript/calendar/spec-setup.js b/tests/javascript/calendar/spec-setup.js new file mode 100644 index 0000000000000..e734ecce38828 --- /dev/null +++ b/tests/javascript/calendar/spec-setup.js @@ -0,0 +1,14 @@ +/** + * @copyright Copyright (C) 2005 - 2016 Open Source Matters, Inc. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + * @package Joomla + * @subpackage JavaScript Tests + * @since __DEPLOY_VERSION__ + * @version 1.0.0 + */ + +define(['jquery', 'text!testsRoot/calendar/fixtures/fixture.html', 'libs/fields/calendar-vanilla'], function ($, fixture) { + + $('body').append(fixture); + +}); diff --git a/tests/javascript/calendar/spec.js b/tests/javascript/calendar/spec.js new file mode 100644 index 0000000000000..36756db353383 --- /dev/null +++ b/tests/javascript/calendar/spec.js @@ -0,0 +1,77 @@ +/** + * @copyright Copyright (C) 2005 - 2016 Open Source Matters, Inc. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + * @package Joomla + * @subpackage JavaScript Tests + * @since __DEPLOY_VERSION__ + * @version 1.0.0 + */ + +define(['jquery', 'testsRoot/calendar/spec-setup', 'jasmineJquery'], function ($) { + + describe('Calendar set for the input element', function () { + beforeAll(function () { + JoomlaCalendar.init(".field-calendar"); + }); + + it('Should have calendar element under the input element', function () { + expect($('body')).toContainElement('.js-calendar'); + }); + + it('Should appear on button click', function () { + $('.field-calendar').find('button').click(); + + expect($('.js-calendar').css('display')).toEqual('block'); + }); + + it('Should have the correct date', function () { + expect($('.field-calendar').find('input').val()).toEqual('2016-09-01 05:17:00'); + }); + + // it('Should have the correct date clicking on previous year button', function () { + // + // console.info($('.field-calendar').find('.btn-prev-year')); + // $('.field-calendar').find('.btn-prev-year').trigger('click'); + // + // expect($('.field-calendar').find('input').val()).toEqual('2015-09-01 00:17:15'); + // }); + // + // it('Should have the correct date clicking on next year button', function () { + // + // console.info($('.field-calendar').find('.btn-next-year')); + // $('.field-calendar').find('.btn-next-year').trigger('click'); + // + // expect($('.field-calendar').find('input').val()).toEqual('2016-09-01 00:17:15'); + // }); + // + // it('Should have the correct date clicking on previous month button', function () { + // + // console.info($('.field-calendar').find('.btn-prev-month')); + // $('.field-calendar').find('.btn-prev-moth').trigger('click'); + // + // expect($('.field-calendar').find('input').val()).toEqual('2016-08-01 00:17:15'); + // }); + // + // it('Should have the correct date clicking on next month button', function () { + // + // console.info($('.field-calendar').find('.btn-next-month')); + // $('.field-calendar').find('.btn-next-moth').trigger('click'); + // + // expect($('.field-calendar').find('input').val()).toEqual('2016-09-01 00:17:15'); + // }); + // + // it('Should have the correct date clicking on today button', function () { + // + // console.info($('.field-calendar').find('.btn-today')); + // $('.field-calendar').find('.btn-today').trigger('click'); + // + // expect($('.field-calendar').find('input').val()).toEqual('2016-09-01 00:17:15'); + // }); + // + // it('Should hide on other body element click/focus', function () { + // $('#cal-close-btn').focus(); + // + // expect($('.j-calendar').css('display')).not.toEqual('block'); + // }); + }); +}); diff --git a/tests/javascript/test-main.js b/tests/javascript/test-main.js index 0de1ff533994c..96b5acd50b9ca 100644 --- a/tests/javascript/test-main.js +++ b/tests/javascript/test-main.js @@ -24,7 +24,9 @@ require.config({ 'jasmineJquery': 'tests/javascript/node_modules/jasmine-jquery/lib/jasmine-jquery', 'libs': 'media/system/js', 'testsRoot': 'tests/javascript', - 'text': 'tests/javascript/node_modules/text/text' + 'text': 'tests/javascript/node_modules/text/text', + 'calLang': 'media/system/js/fields/calendar-locales/en', + 'calDate': 'media/system/js/fields/calendar-locales/date/gregorian/date-helper' }, shim: { @@ -45,6 +47,9 @@ require.config({ }, 'libs/combobox': { deps: ['jquery'] + }, + 'libs/fields/calendar-vanilla': { + deps: ['calLang', 'calDate'] } }, diff --git a/tests/unit/suites/libraries/cms/html/JHtmlBehaviorTest.php b/tests/unit/suites/libraries/cms/html/JHtmlBehaviorTest.php index 4721a044d1304..fd52415e79469 100644 --- a/tests/unit/suites/libraries/cms/html/JHtmlBehaviorTest.php +++ b/tests/unit/suites/libraries/cms/html/JHtmlBehaviorTest.php @@ -441,24 +441,6 @@ public function testTree($expected, $id, $params = array(), $root = array()) ); } - /** - * Tests the calendar method. - * - * @return void - * - * @since 3.1 - */ - public function testCalendar() - { - JHtmlBehavior::calendar(); - - $this->assertEquals( - array('JHtmlBehavior::calendar' => true), - JHtmlBehaviorInspector::getLoaded(), - 'The calendar behavior is not loaded with all dependencies' - ); - } - /** * Tests the colorpicker method. * diff --git a/tests/unit/suites/libraries/cms/html/JHtmlTest.php b/tests/unit/suites/libraries/cms/html/JHtmlTest.php index 5e27d719d918d..7f9267ecb1b75 100644 --- a/tests/unit/suites/libraries/cms/html/JHtmlTest.php +++ b/tests/unit/suites/libraries/cms/html/JHtmlTest.php @@ -1439,35 +1439,38 @@ public function testCalendar() strlen($input), 'Line:' . __LINE__ . ' The calendar method should return something without error.' ); + $readonly = isset($data['attribs']['readonly']) ? 'readonly="readonly"' : ''; + + $xml = new SimpleXMLElement(''); - $xml = new SimpleXMLElement('' . $input . ''); $this->assertEquals( - 'text', - (string) $xml->div->input['type'], - 'Line:' . __LINE__ . ' The calendar input should have `type == "text"`' + 'calendar', + (string) $xml->attributes()->type, + 'Line:' . __LINE__ . ' The calendar input should have `type == "calendar"`' ); $this->assertEquals( $data['friendly_date'], - (string) $xml->div->input['title'], + (string) $xml->attributes()->title, 'Line:'.__LINE__.' The calendar input should have `title == "' . $data['friendly_date'] . '"`' ); $this->assertEquals( $data['name'], - (string) $xml->div->input['name'], + (string) $xml->attributes()->name, 'Line:'.__LINE__.' The calendar input should have `name == "' . $data['name'] . '"`' ); $this->assertEquals( $data['id'], - (string) $xml->div->input['id'], + (string) $xml->attributes()->id, 'Line:'.__LINE__.' The calendar input should have `id == "' . $data['id'] . '"`' ); $this->assertEquals( $data['formattedDate'], - (string) $xml->div->input['value'], + (string) $xml->attributes()->value, 'Line:' . __LINE__ . ' The calendar input should have `value == "' . $data['formattedDate'] . '"`' ); @@ -1475,69 +1478,28 @@ public function testCalendar() { $this->assertEquals( $data['attribs']['readonly'], - (string) $xml->div->input['readonly'], - 'Line:' . __LINE__ . ' The readonly calendar input should have `readonly == "' . $data['attribs']['readonly'] . '"`' - ); - - $this->assertTrue( - isset($xml->div->button['style']), - 'Line:' . __LINE__ . ' The calendar input should not have a visible button' - ); - - $this->assertArrayNotHasKey( - '/media/system/js/calendar.js', - JFactory::getDocument()->_scripts, - 'Line:' . __LINE__ . ' JS file "calendar.js" shouldn\'t be loaded' - ); - - $this->assertArrayNotHasKey( - '/media/system/js/calendar-setup.js', - JFactory::getDocument()->_scripts, - 'Line:' . __LINE__ . ' JS file "calendar-setup.js" shouldn\'t be loaded' - ); - - $this->assertArrayNotHasKey( - 'text/javascript', - JFactory::getDocument()->_script, - 'Line:' . __LINE__ . ' Inline JS for the calendar shouldn\'t be loaded' + $xml->attributes()->readonly, + 'Line:' . __LINE__ . ' The calendar input should have readonly attribute' ); } - else - { - $this->assertFalse( - isset($xml->div->input['readonly']), - 'Line:' . __LINE__ . ' The calendar input shouldn\'t have readonly attribute' - ); - $this->assertFalse( - isset($xml->div->button['style']), - 'Line:' . __LINE__ . ' The calendar input should visible button' - ); - - $this->assertEquals( - $data['id'] . '_img', - (string) $xml->div->button['id'], - 'Line:' . __LINE__ . ' The calendar button should have `id == "' . $data['id'] . '_img' . '"`' - ); - - $this->assertArrayHasKey( - '/media/system/js/calendar.js', - JFactory::getDocument()->_scripts, - 'Line:'.__LINE__.' JS file "calendar.js" should be loaded' - ); + $this->assertArrayHasKey( + '/media/system/js/fields/calendar-locales/en.js', + JFactory::getDocument()->_scripts, + 'Line:'.__LINE__.' JS file "calendar-vanilla.min.js" should be loaded' + ); - $this->assertArrayHasKey( - '/media/system/js/calendar-setup.js', - JFactory::getDocument()->_scripts, - 'Line:'.__LINE__.' JS file "calendar-setup.js" should be loaded' - ); + $this->assertArrayHasKey( + '/media/system/js/fields/calendar-locales/date/gregorian/date-helper.min.js', + JFactory::getDocument()->_scripts, + 'Line:'.__LINE__.' JS file "date.js" should be loaded' + ); - $this->assertContains( - 'jQuery(document).ready(function($) {Calendar.setup({', - JFactory::getDocument()->_script['text/javascript'], - 'Line:' . __LINE__ . ' Inline JS for the calendar should be loaded' - ); - } + $this->assertArrayHasKey( + '/media/system/js/fields/calendar-vanilla.min.js', + JFactory::getDocument()->_scripts, + 'Line:'.__LINE__.' JS file "calendar-vanilla.min.js" should be loaded' + ); } }