Skip to content

Commit

Permalink
Replace jscalendar with bootstrap-datetimepicker library
Browse files Browse the repository at this point in the history
- 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
syncguru authored and dregad committed Dec 20, 2016
1 parent c21783d commit 6f73af1
Show file tree
Hide file tree
Showing 21 changed files with 1,029 additions and 100 deletions.
12 changes: 5 additions & 7 deletions bug_actiongroup_page.php
Expand Up @@ -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();
?>

Expand Down Expand Up @@ -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">';

Expand Down
15 changes: 5 additions & 10 deletions bug_change_status_page.php
Expand Up @@ -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 );
Expand Down Expand Up @@ -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>

Expand Down
13 changes: 5 additions & 8 deletions bug_report_page.php
Expand Up @@ -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();

Expand Down Expand Up @@ -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 } ?>
Expand Down
12 changes: 4 additions & 8 deletions bug_update_page.php
Expand Up @@ -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();
Expand Down Expand Up @@ -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 );
Expand Down
10 changes: 5 additions & 5 deletions config_defaults_inc.php
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions core/constant_inc.php
Expand Up @@ -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=' );
Expand Down
11 changes: 1 addition & 10 deletions core/http_api.php
Expand Up @@ -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' );
Expand All @@ -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();
Expand Down
17 changes: 17 additions & 0 deletions core/lang_api.php
Expand Up @@ -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];
}
18 changes: 17 additions & 1 deletion core/layout_api.php
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
9 changes: 9 additions & 0 deletions css/ace-mantis.css
Expand Up @@ -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 {
Expand Down
5 changes: 5 additions & 0 deletions css/bootstrap-datetimepicker.min.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 6f73af1

Please sign in to comment.