Permalink
Browse files

Replace jscalendar with bootstrap-datetimepicker library

- Enable datetimepciker on all pages by default
- Relocate inline JS code into standalone files
- Remove CSP exceptions for jscalendar
- Multi-language support

Fixes #20040
  • Loading branch information...
1 parent c21783d commit 6f73af1609974df5a9bbd2f29dee5e54afbae0e5 @syncguru syncguru committed with dregad Nov 7, 2016
@@ -221,12 +221,6 @@
default:
trigger_error( ERROR_GENERIC, ERROR );
}
-if( $f_action === 'UP_DUE_DATE' ) {
- require_js( 'jscalendar/calendar.js' );
- require_js( 'jscalendar/lang/calendar-en.js' );
- require_js( 'jscalendar/calendar-setup.js' );
- require_css( 'calendar-blue.css' );
-}
bug_group_action_print_top();
?>
@@ -289,7 +283,11 @@
}
}
- echo '<input type="text" id="due_date" name="due_date" class="datetime" size="20" maxlength="16" value="' . $t_date_to_display . '" />';
+ echo '<input type="text" id="due_date" name="due_date" class="datetimepicker input-sm" size="20" maxlength="16" ' .
+ 'data-picker-locale="' . lang_get_current_datetime_locale() .
+ '" data-picker-format="' . config_get( 'calendar_js_date_format' ) . '"' .
+ '" value="' . $t_date_to_display . '" />';
+ echo '<i class="fa fa-calendar fa-xlg"></i>';
} else {
echo '<select name="' . $t_form . '" class="input-sm">';
@@ -96,12 +96,6 @@
}
$t_can_update_due_date = access_has_bug_level( config_get( 'due_date_update_threshold' ), $f_bug_id );
-if( $t_can_update_due_date ) {
- require_js( 'jscalendar/calendar.js' );
- require_js( 'jscalendar/lang/calendar-en.js' );
- require_js( 'jscalendar/calendar-setup.js' );
- require_css( 'calendar-blue.css' );
-}
# get new issue handler if set, otherwise default to original handler
$f_handler_id = gpc_get_int( 'handler_id', $t_bug->handler_id );
@@ -246,10 +240,11 @@
<?php echo lang_get( 'due_date' ) ?>
</th>
<td>
- <input type="text" id="due_date" name="due_date"
- class="datetime" size="20" maxlength="16"
- <?php helper_get_tab_index() ?>
- value="<?php echo $t_date_to_display ?>" />
+ <input type="text" id="due_date" name="due_date" class="datetimepicker input-sm" size="20" maxlength="16"
+ data-picker-locale="<?php lang_get_current_datetime_locale() ?>"
+ data-picker-format="<?php echo config_get( 'calendar_js_date_format' ) ?>
+ <?php helper_get_tab_index() ?> value="<?php echo $t_date_to_display ?>" />
+ <i class="fa fa-calendar fa-xlg"></i>';
</td>
</tr>
View
@@ -222,13 +222,6 @@
$t_show_attachments = in_array( 'attachments', $t_fields ) && file_allow_bug_upload();
$t_show_view_state = in_array( 'view_state', $t_fields ) && access_has_project_level( config_get( 'set_view_status_threshold' ) );
-if( $t_show_due_date ) {
- require_js( 'jscalendar/calendar.js' );
- require_js( 'jscalendar/lang/calendar-en.js' );
- require_js( 'jscalendar/calendar-setup.js' );
- require_css( 'calendar-blue.css' );
-}
-
# don't index bug report page
html_robots_noindex();
@@ -362,7 +355,11 @@ class="dropzone-form"
<label for="due_date"><?php print_documentation_link( 'due_date' ) ?></label>
</th>
<td>
- <?php echo '<input ' . helper_get_tab_index() . ' type="text" id="due_date" name="due_date" class="datetime" size="20" maxlength="16" value="' . $t_date_to_display . '" />' ?>
+ <?php echo '<input ' . helper_get_tab_index() . ' type="text" id="due_date" name="due_date" class="datetimepicker input-sm" ' .
+ 'data-picker-locale="' . lang_get_current_datetime_locale() .
+ '" data-picker-format="' . config_get( 'calendar_js_date_format' ) . '" ' .
+ 'size="20" maxlength="16" value="' . $t_date_to_display . '" />' ?>
+ <i class="fa fa-calendar fa-xlg"></i>
</td>
</tr>
<?php } ?>
View
@@ -155,13 +155,6 @@
$t_formatted_bug_id = $t_show_id ? bug_format_id( $f_bug_id ) : '';
$t_project_name = $t_show_project ? string_display_line( project_get_name( $t_bug->project_id ) ) : '';
-if( $t_show_due_date ) {
- require_js( 'jscalendar/calendar.js' );
- require_js( 'jscalendar/lang/calendar-en.js' );
- require_js( 'jscalendar/calendar-setup.js' );
- require_css( 'calendar-blue.css' );
-}
-
layout_page_header( bug_format_summary( $f_bug_id, SUMMARY_CAPTION ) );
layout_page_begin();
@@ -360,7 +353,10 @@
if( !date_is_null( $t_bug->due_date ) ) {
$t_date_to_display = date( config_get( 'calendar_date_format' ), $t_bug->due_date );
}
- echo '<input ' . helper_get_tab_index() . ' type="text" id="due_date" name="due_date" class="datetime" size="20" maxlength="16" value="' . $t_date_to_display . '" />';
+ echo '<input ' . helper_get_tab_index() . ' type="text" id="due_date" name="due_date" class="datetimepicker input-sm" size="20" ' .
+ 'data-picker-locale="' . lang_get_current_datetime_locale() . '" data-picker-format="' . config_get( 'calendar_js_date_format' ) . '" ' .
+ '" maxlength="16" value="' . $t_date_to_display . '" />';
+ echo '<i class="fa fa-calendar fa-xlg"></i>';
} else {
if( !date_is_null( $t_bug->due_date ) ) {
echo date( config_get( 'short_date_format' ), $t_bug->due_date );
@@ -1140,15 +1140,15 @@
$g_complete_date_format = 'Y-m-d H:i T';
/**
- * jscalendar date format string
- * go to http://www.php.net/manual/en/function.date.php
+ * calendar widget (datetimepicker) format string
+ * go to http://momentjs.com/docs/#/displaying/format/
* for detailed instructions on date formatting
- * @global string $g_calendar_js_date_format
+ * @global string $g_calendar_date_format
*/
-$g_calendar_js_date_format = '\%Y-\%m-\%d \%H:\%M';
+$g_calendar_js_date_format = 'Y-M-D H:m';
/**
- * jscalendar date format string
+ * calendar widget (datetimepicker) format string
* go to http://www.php.net/manual/en/function.date.php
* for detailed instructions on date formatting
* @global string $g_calendar_date_format
@@ -617,6 +617,10 @@
define ( 'BOOTSTRAP_HASH', 'sha256-KXn5puMvxCw+dAYznun+drMdG1IFl3agK0p/pqT9KAo=' );
define ( 'FONT_AWESOME_VERSION', '4.6.3' );
+# Moment & DateTimePicker
+define ( 'MOMENT_VERSION', '2.15.2' );
+define ( 'DATETIME_PICKER_VERSION', '4.17.43' );
+
# Chart JS
define ( 'CHARTJS_VERSION', '2.1.6' );
define ( 'CHARTJS_HASH', 'sha256-Emd9qupGNNjtRpaQjhpA4hn+PWAETkO2GB3gzBL3thM=' );
View
@@ -223,6 +223,7 @@ function http_security_headers() {
http_csp_add( 'style-src', 'ajax.googleapis.com' );
http_csp_add( 'style-src', 'maxcdn.bootstrapcdn.com' );
http_csp_add( 'style-src', 'fonts.googleapis.com' );
+ http_csp_add( 'style-src', 'cdnjs.cloudflare.com' );
http_csp_add( 'font-src', 'fonts.gstatic.com' );
http_csp_add( 'font-src', 'maxcdn.bootstrapcdn.com' );
@@ -231,17 +232,7 @@ function http_security_headers() {
http_csp_add( 'script-src', 'maxcdn.bootstrapcdn.com' );
http_csp_add( 'img-src', 'ajax.googleapis.com' );
- }
-
- # Relaxing policy for bug report page to allow inline scripts.
- # Should be removed once #20040 is fixed.
- if( 'bug_report_page.php' == basename( $_SERVER['SCRIPT_NAME'] ) ) {
- http_csp_add( 'script-src', "'unsafe-inline'" );
- }
- # The JS Calendar control does unsafe eval, remove once we upgrade the control (see #20040)
- if( 'bug_update_page.php' == basename( $_SERVER['SCRIPT_NAME'] ) ) {
- http_csp_add( 'script-src', "'unsafe-eval'" );
}
http_csp_emit_header();
View
@@ -354,3 +354,20 @@ function lang_get_defaulted( $p_string, $p_default = null, $p_lang = null ) {
}
}
}
+
+
+/**
+ * Maps current lang string to moment.js locale https://github.com/moment/moment/tree/develop/locale
+ * @return string
+ */
+
+function lang_get_current_datetime_locale() {
+ $t_lang = lang_get_current();
+
+ # Lookup $g_language_auto_map by value and then return the first key
+ $t_auto_map = config_get( 'language_auto_map' );
+ $t_entry = array_search( $t_lang, $t_auto_map );
+ $t_key_arr = explode( ',', $t_entry );
+
+ return $t_key_arr[0];
+}
View
@@ -257,12 +257,18 @@ function layout_head_css() {
# theme text fonts
html_css_cdn_link( 'https://fonts.googleapis.com/css?family=Open+Sans:300,400' );
+
+ # datetimepicker
+ html_css_cdn_link( 'https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/' . DATETIME_PICKER_VERSION . '/css/bootstrap-datetimepicker.min.css' );
} else {
html_css_link( 'bootstrap-' . BOOTSTRAP_VERSION . '.min.css' );
html_css_link( 'font-awesome-' . FONT_AWESOME_VERSION . '.min.css' );
# theme text fonts
html_css_link( 'open-sans.css' );
+
+ # datetimepicker
+ html_css_link( 'bootstrap-datetimepicker.min.css' );
}
# page specific plugin styles
@@ -307,11 +313,21 @@ function layout_head_javascript() {
* @return null
*/
function layout_body_javascript() {
- # bootstrap
+
if ( config_get_global( 'cdn_enabled' ) == ON ) {
+ # bootstrap
html_javascript_cdn_link( 'https://maxcdn.bootstrapcdn.com/bootstrap/' . BOOTSTRAP_VERSION . '/js/bootstrap.min.js', BOOTSTRAP_HASH );
+
+ # moment & datetimepicker
+ html_javascript_cdn_link( 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/' . MOMENT_VERSION . '/moment-with-locales.min.js' );
+ html_javascript_cdn_link( 'https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/' . DATETIME_PICKER_VERSION . '/js/bootstrap-datetimepicker.min.js' );
} else {
+ # bootstrap
html_javascript_link( 'bootstrap-' . BOOTSTRAP_VERSION . '.min.js' );
+
+ # moment & datetimepicker
+ html_javascript_link( 'moment-with-locales.min.js' );
+ html_javascript_link( 'bootstrap-datetimepicker.min.js' );
}
# theme scripts
View
@@ -281,6 +281,15 @@ textarea.input-xs, select.input-xs[multiple] {
display: block;
}
+/* databicker */
+input.datetimepicker {
+ margin:0 5px 0 0;
+}
+
+.bootstrap-datetimepicker-widget.dropdown-menu {
+ color: #333333;
+}
+
/* Small devices (tablets, 768px and up) */
@media (min-width: 768px) {
.page-content {
@@ -0,0 +1,5 @@
+/*!
+ * Datetimepicker for Bootstrap 3
+ * version : 4.17.42
+ * https://github.com/Eonasdan/bootstrap-datetimepicker/
+ */.bootstrap-datetimepicker-widget{list-style:none}.bootstrap-datetimepicker-widget.dropdown-menu{margin:2px 0;padding:4px;width:19em}@media (min-width:768px){.bootstrap-datetimepicker-widget.dropdown-menu.timepicker-sbs{width:38em}}@media (min-width:992px){.bootstrap-datetimepicker-widget.dropdown-menu.timepicker-sbs{width:38em}}@media (min-width:1200px){.bootstrap-datetimepicker-widget.dropdown-menu.timepicker-sbs{width:38em}}.bootstrap-datetimepicker-widget.dropdown-menu:before,.bootstrap-datetimepicker-widget.dropdown-menu:after{content:'';display:inline-block;position:absolute}.bootstrap-datetimepicker-widget.dropdown-menu.bottom:before{border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0,0,0,0.2);top:-7px;left:7px}.bootstrap-datetimepicker-widget.dropdown-menu.bottom:after{border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid white;top:-6px;left:8px}.bootstrap-datetimepicker-widget.dropdown-menu.top:before{border-left:7px solid transparent;border-right:7px solid transparent;border-top:7px solid #ccc;border-top-color:rgba(0,0,0,0.2);bottom:-7px;left:6px}.bootstrap-datetimepicker-widget.dropdown-menu.top:after{border-left:6px solid transparent;border-right:6px solid transparent;border-top:6px solid white;bottom:-6px;left:7px}.bootstrap-datetimepicker-widget.dropdown-menu.pull-right:before{left:auto;right:6px}.bootstrap-datetimepicker-widget.dropdown-menu.pull-right:after{left:auto;right:7px}.bootstrap-datetimepicker-widget .list-unstyled{margin:0}.bootstrap-datetimepicker-widget a[data-action]{padding:6px 0}.bootstrap-datetimepicker-widget a[data-action]:active{box-shadow:none}.bootstrap-datetimepicker-widget .timepicker-hour,.bootstrap-datetimepicker-widget .timepicker-minute,.bootstrap-datetimepicker-widget .timepicker-second{width:54px;font-weight:bold;font-size:1.2em;margin:0}.bootstrap-datetimepicker-widget button[data-action]{padding:6px}.bootstrap-datetimepicker-widget .btn[data-action="incrementHours"]::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0;content:"Increment Hours"}.bootstrap-datetimepicker-widget .btn[data-action="incrementMinutes"]::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0;content:"Increment Minutes"}.bootstrap-datetimepicker-widget .btn[data-action="decrementHours"]::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0;content:"Decrement Hours"}.bootstrap-datetimepicker-widget .btn[data-action="decrementMinutes"]::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0;content:"Decrement Minutes"}.bootstrap-datetimepicker-widget .btn[data-action="showHours"]::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0;content:"Show Hours"}.bootstrap-datetimepicker-widget .btn[data-action="showMinutes"]::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0;content:"Show Minutes"}.bootstrap-datetimepicker-widget .btn[data-action="togglePeriod"]::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0;content:"Toggle AM/PM"}.bootstrap-datetimepicker-widget .btn[data-action="clear"]::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0;content:"Clear the picker"}.bootstrap-datetimepicker-widget .btn[data-action="today"]::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0;content:"Set the date to today"}.bootstrap-datetimepicker-widget .picker-switch{text-align:center}.bootstrap-datetimepicker-widget .picker-switch::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0;content:"Toggle Date and Time Screens"}.bootstrap-datetimepicker-widget .picker-switch td{padding:0;margin:0;height:auto;width:auto;line-height:inherit}.bootstrap-datetimepicker-widget .picker-switch td span{line-height:2.5;height:2.5em;width:100%}.bootstrap-datetimepicker-widget table{width:100%;margin:0}.bootstrap-datetimepicker-widget table td,.bootstrap-datetimepicker-widget table th{text-align:center;border-radius:4px}.bootstrap-datetimepicker-widget table th{height:20px;line-height:20px;width:20px}.bootstrap-datetimepicker-widget table th.picker-switch{width:145px}.bootstrap-datetimepicker-widget table th.disabled,.bootstrap-datetimepicker-widget table th.disabled:hover{background:none;color:#777;cursor:not-allowed}.bootstrap-datetimepicker-widget table th.prev::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0;content:"Previous Month"}.bootstrap-datetimepicker-widget table th.next::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0;content:"Next Month"}.bootstrap-datetimepicker-widget table thead tr:first-child th{cursor:pointer}.bootstrap-datetimepicker-widget table thead tr:first-child th:hover{background:#eee}.bootstrap-datetimepicker-widget table td{height:54px;line-height:54px;width:54px}.bootstrap-datetimepicker-widget table td.cw{font-size:.8em;height:20px;line-height:20px;color:#777}.bootstrap-datetimepicker-widget table td.day{height:20px;line-height:20px;width:20px}.bootstrap-datetimepicker-widget table td.day:hover,.bootstrap-datetimepicker-widget table td.hour:hover,.bootstrap-datetimepicker-widget table td.minute:hover,.bootstrap-datetimepicker-widget table td.second:hover{background:#eee;cursor:pointer}.bootstrap-datetimepicker-widget table td.old,.bootstrap-datetimepicker-widget table td.new{color:#777}.bootstrap-datetimepicker-widget table td.today{position:relative}.bootstrap-datetimepicker-widget table td.today:before{content:'';display:inline-block;border:solid transparent;border-width:0 0 7px 7px;border-bottom-color:#337ab7;border-top-color:rgba(0,0,0,0.2);position:absolute;bottom:4px;right:4px}.bootstrap-datetimepicker-widget table td.active,.bootstrap-datetimepicker-widget table td.active:hover{background-color:#337ab7;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.bootstrap-datetimepicker-widget table td.active.today:before{border-bottom-color:#fff}.bootstrap-datetimepicker-widget table td.disabled,.bootstrap-datetimepicker-widget table td.disabled:hover{background:none;color:#777;cursor:not-allowed}.bootstrap-datetimepicker-widget table td span{display:inline-block;width:54px;height:54px;line-height:54px;margin:2px 1.5px;cursor:pointer;border-radius:4px}.bootstrap-datetimepicker-widget table td span:hover{background:#eee}.bootstrap-datetimepicker-widget table td span.active{background-color:#337ab7;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.bootstrap-datetimepicker-widget table td span.old{color:#777}.bootstrap-datetimepicker-widget table td span.disabled,.bootstrap-datetimepicker-widget table td span.disabled:hover{background:none;color:#777;cursor:not-allowed}.bootstrap-datetimepicker-widget.usetwentyfour td.hour{height:27px;line-height:27px}.bootstrap-datetimepicker-widget.wider{width:21em}.bootstrap-datetimepicker-widget .datepicker-decades .decade{line-height:1.8em !important}.input-group.date .input-group-addon{cursor:pointer}.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}
Oops, something went wrong.

0 comments on commit 6f73af1

Please sign in to comment.