diff options
-rw-r--r-- | CHANGELOG | 1 | ||||
-rw-r--r-- | program/js/list.js | 4 | ||||
-rw-r--r-- | program/lib/Roundcube/rcube_utils.php | 79 | ||||
-rw-r--r-- | program/steps/addressbook/save.inc | 4 | ||||
-rw-r--r-- | tests/Framework/Utils.php | 26 |
5 files changed, 81 insertions, 33 deletions
@@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Fix an issue where shift + arrow-up key wasn't selecting all messages in collapsed thread (#1489397) - Added icon for priority column in messages list header (#1489234) - New feature "Canned Responses" to save and recall boilerplate text snippets - Fix HTML part detection when encapsulated inside multipart/signed (#1489372) diff --git a/program/js/list.js b/program/js/list.js index 0b6f416e3..8843cd94a 100644 --- a/program/js/list.js +++ b/program/js/list.js @@ -912,7 +912,8 @@ shift_select: function(id, control) from_rowIndex = this._rowIndex(this.rows[this.shift_start].obj), to_rowIndex = this._rowIndex(to_row.obj); - if (!to_row.expanded && to_row.has_children) + // if we're going down the list, and we hit a thread, and it's closed, select the whole thread + if (from_rowIndex < to_rowIndex && !to_row.expanded && to_row.has_children) if (to_row = this.rows[(this.row_children(id)).pop()]) to_rowIndex = this._rowIndex(to_row.obj); @@ -934,6 +935,7 @@ shift_select: function(id, control) } }, + /** * Helper method to emulate the rowIndex property of non-tr elements */ diff --git a/program/lib/Roundcube/rcube_utils.php b/program/lib/Roundcube/rcube_utils.php index 174fe398c..27a618d83 100644 --- a/program/lib/Roundcube/rcube_utils.php +++ b/program/lib/Roundcube/rcube_utils.php @@ -747,40 +747,13 @@ class rcube_utils */ public static function strtotime($date) { - $date = trim($date); - - // check for MS Outlook vCard date format YYYYMMDD - if (preg_match('/^([12][90]\d\d)([01]\d)([0123]\d)$/', $date, $m)) { - return mktime(0,0,0, intval($m[2]), intval($m[3]), intval($m[1])); - } - - // common little-endian formats, e.g. dd/mm/yyyy (not all are supported by strtotime) - if (preg_match('/^(\d{1,2})[.\/-](\d{1,2})[.\/-](\d{4})$/', $date, $m) - && $m[1] > 0 && $m[1] <= 31 && $m[2] > 0 && $m[2] <= 12 && $m[3] >= 1970 - ) { - return mktime(0,0,0, intval($m[2]), intval($m[1]), intval($m[3])); - } + $date = self::clean_datestr($date); // unix timestamp if (is_numeric($date)) { return (int) $date; } - // Clean malformed data - $date = preg_replace( - array( - '/GMT\s*([+-][0-9]+)/', // support non-standard "GMTXXXX" literal - '/[^a-z0-9\x20\x09:+-]/i', // remove any invalid characters - '/\s*(Mon|Tue|Wed|Thu|Fri|Sat|Sun)\s*/i', // remove weekday names - ), - array( - '\\1', - '', - '', - ), $date); - - $date = trim($date); - // if date parsing fails, we have a date in non-rfc format. // remove token from the end and try again while ((($ts = @strtotime($date)) === false) || ($ts < 0)) { @@ -808,8 +781,8 @@ class rcube_utils return $date; } - $dt = false; - $date = trim($date); + $dt = false; + $date = self::clean_datestr($date); // try to parse string with DateTime first if (!empty($date)) { @@ -834,6 +807,52 @@ class rcube_utils return $dt; } + /** + * Clean up date string for strtotime() input + * + * @param string $date Date string + * + * @return string Date string + */ + public static function clean_datestr($date) + { + $date = trim($date); + + // check for MS Outlook vCard date format YYYYMMDD + if (preg_match('/^([12][90]\d\d)([01]\d)([0123]\d)$/', $date, $m)) { + return sprintf('%04d-%02d-%02d 00:00:00', intval($m[1]), intval($m[2]), intval($m[3])); + } + + // Clean malformed data + $date = preg_replace( + array( + '/GMT\s*([+-][0-9]+)/', // support non-standard "GMTXXXX" literal + '/[^a-z0-9\x20\x09:+-\/]/i', // remove any invalid characters + '/\s*(Mon|Tue|Wed|Thu|Fri|Sat|Sun)\s*/i', // remove weekday names + ), + array( + '\\1', + '', + '', + ), $date); + + $date = trim($date); + + // try to fix dd/mm vs. mm/dd discrepancy, we can't do more here + if (preg_match('/^(\d{1,2})[.\/-](\d{1,2})[.\/-](\d{4})$/', $date, $m)) { + $mdy = $m[2] > 12 && $m[1] <= 12; + $day = $mdy ? $m[2] : $m[1]; + $month = $mdy ? $m[1] : $m[2]; + $date = sprintf('%04d-%02d-%02d 00:00:00', intval($m[3]), $month, $day); + } + // I've found that YYYY.MM.DD is recognized wrong, so here's a fix + else if (preg_match('/^(\d{4})\.(\d{1,2})\.(\d{1,2})$/', $date)) { + $date = str_replace('.', '-', $date) . ' 00:00:00'; + } + + return $date; + } + /* * Idn_to_ascii wrapper. * Intl/Idn modules version of this function doesn't work with e-mail address diff --git a/program/steps/addressbook/save.inc b/program/steps/addressbook/save.inc index 2adc53bcf..7911802b9 100644 --- a/program/steps/addressbook/save.inc +++ b/program/steps/addressbook/save.inc @@ -80,8 +80,8 @@ foreach ($GLOBALS['CONTACT_COLTYPES'] as $col => $colprop) { // normalize the submitted date strings if ($colprop['type'] == 'date') { - if ($timestamp = rcube_utils::strtotime($a_record[$col])) { - $a_record[$col] = date('Y-m-d', $timestamp); + if ($a_record[$col] && ($dt = rcube_utils::anytodatetime($a_record[$col]))) { + $a_record[$col] = $dt->format('Y-m-d'); } else { unset($a_record[$col]); diff --git a/tests/Framework/Utils.php b/tests/Framework/Utils.php index 2f4aec32e..1f1e57b0e 100644 --- a/tests/Framework/Utils.php +++ b/tests/Framework/Utils.php @@ -294,6 +294,32 @@ class Framework_Utils extends PHPUnit_Framework_TestCase } /** + * rcube:utils::anytodatetime() + */ + function test_anytodatetime() + { + $test = array( + '2013-04-22' => '2013-04-22', + '2013/04/22' => '2013-04-22', + '2013.04.22' => '2013-04-22', + '22-04-2013' => '2013-04-22', + '22/04/2013' => '2013-04-22', + '22.04.2013' => '2013-04-22', + '04/22/2013' => '2013-04-22', + '22.4.2013' => '2013-04-22', + '20130422' => '2013-04-22', + '1900-10-10' => '1900-10-10', + '01-01-1900' => '1900-01-01', + '01/30/1960' => '1960-01-30' + ); + + foreach ($test as $datetime => $ts) { + $result = rcube_utils::anytodatetime($datetime); + $this->assertSame($ts, $result ? $result->format('Y-m-d') : '', "Error parsing date: $datetime"); + } + } + + /** * rcube:utils::normalize _string() */ function test_normalize_string() |