diff --git a/include/class.mailer.php b/include/class.mailer.php index 5d7a135a354330624c1122f342a57c1ab3ab5c3f..ff10eec68e33bc33f24ed65250a22f9745e0889e 100644 --- a/include/class.mailer.php +++ b/include/class.mailer.php @@ -434,6 +434,9 @@ class Mailer { $recipient->getName(), $recipient->getEmail())); break; + case $recipient instanceof EmailAddress: + $mime->addTo($recipient->getAddress()); + break; default: // Assuming email address. $mime->addTo($recipient); diff --git a/include/class.queue.php b/include/class.queue.php index 920e73a80c8576828229b45c74c1468fb0ec54af..d4185fa978cd974ee8a1619ab96c1b634f422e7c 100644 --- a/include/class.queue.php +++ b/include/class.queue.php @@ -1301,7 +1301,7 @@ class CustomQueue extends VerySimpleModel { static function __create($vars) { $q = static::create($vars); $q->psave(); - foreach ($vars['columns'] as $info) { + foreach ($vars['columns'] ?: array() as $info) { $glue = new QueueColumnGlue($info); $glue->queue_id = $q->getId(); $glue->save(); diff --git a/include/class.search.php b/include/class.search.php index 6ad68f283dd04b2b835fde67935c464821ca8a89..a061cb58eecf3f153b3209c36cf377c7a2d7099c 100644 --- a/include/class.search.php +++ b/include/class.search.php @@ -1049,23 +1049,37 @@ class DepartmentChoiceField extends AdvancedSearchSelectionField { class AssigneeChoiceField extends ChoiceField { + + protected $_items; + + function getChoices($verbose=false) { global $thisstaff; - $items = array( - 'M' => __('Me'), - 'T' => __('One of my teams'), - ); - foreach (Staff::getStaffMembers() as $id=>$name) { - // Don't include $thisstaff (since that's 'Me') - if ($thisstaff && $thisstaff->getId() == $id) - continue; - $items['s' . $id] = $name; - } - foreach (Team::getTeams() as $id=>$name) { - $items['t' . $id] = $name; + if (!isset($this->_items)) { + $items = array( + 'M' => __('Me'), + 'T' => __('One of my teams'), + ); + foreach (Staff::getStaffMembers() as $id=>$name) { + // Don't include $thisstaff (since that's 'Me') + if ($thisstaff && $thisstaff->getId() == $id) + continue; + $items['s' . $id] = $name; + } + foreach (Team::getTeams() as $id=>$name) { + $items['t' . $id] = $name; + } + + $this->_items = $items; } - return $items; + + return $this->_items; + } + + function getChoice($k) { + $choices = $this->getChoices(); + return $choices[$k] ?: null; } function getSearchMethods() { @@ -1167,6 +1181,15 @@ class AssigneeChoiceField extends ChoiceField { function display($value) { return (string) $value; } + + function toString($value) { + if (!is_array($value)) + $value = array($value => $value); + $selection = array(); + foreach ($value as $k => $v) + $selection[] = $this->getChoice($k) ?: (string) $v; + return implode(', ', $selection); + } } class AssignedField extends AssigneeChoiceField { diff --git a/include/class.ticket.php b/include/class.ticket.php index c9811934a7189c9b979d7ca364c5016b6577fd5f..49513b52df6d61b1107366e85ff186838a9e2d6f 100644 --- a/include/class.ticket.php +++ b/include/class.ticket.php @@ -1660,6 +1660,9 @@ implements RestrictedAccess, Threadable, Searchable { unset($recipients[$key]); } + if (!count($recipients)) + return true; + //see if the ticket user is a recipient if ($owner->getEmail()->address != $poster->getEmail()->address && !in_array($owner->getEmail()->address, $skip)) $owner_recip = $owner->getEmail()->address; diff --git a/include/client/templates/thread-entries.tmpl.php b/include/client/templates/thread-entries.tmpl.php index edd71b4a8a0e927a34d067537522b1b8f487f72c..93843210969e4e3d79aea05b4ad692805dc5f95f 100644 --- a/include/client/templates/thread-entries.tmpl.php +++ b/include/client/templates/thread-entries.tmpl.php @@ -34,7 +34,9 @@ if (count($entries)) { $events->next(); $event = $events->current(); } + ?><div id="thread-entry-<?php echo $entry->getId(); ?>"><?php include 'thread-entry.tmpl.php'; + ?></div><?php } $i++; } diff --git a/include/client/tickets.inc.php b/include/client/tickets.inc.php index 9e678e31cbaa4a2ff9fec9d63fcb38ed172540b9..8c90e18216155cf9ed9cde53a54833e4449a9719 100644 --- a/include/client/tickets.inc.php +++ b/include/client/tickets.inc.php @@ -205,19 +205,19 @@ if ($closedTickets) {?> <thead> <tr> <th nowrap> - <a href="tickets.php?sort=ID&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="Sort By Ticket ID"><?php echo __('Ticket #');?><i class="icon-sort"></i></a> + <a href="tickets.php?sort=ID&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="Sort By Ticket ID"><?php echo __('Ticket #');?> <i class="icon-sort"></i></a> </th> <th width="120"> - <a href="tickets.php?sort=date&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="Sort By Date"><?php echo __('Create Date');?><i class="icon-sort"></i></a> + <a href="tickets.php?sort=date&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="Sort By Date"><?php echo __('Create Date');?> <i class="icon-sort"></i></a> </th> <th width="100"> - <a href="tickets.php?sort=status&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="Sort By Status"><?php echo __('Status');?><i class="icon-sort"></i></a> + <a href="tickets.php?sort=status&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="Sort By Status"><?php echo __('Status');?> <i class="icon-sort"></i></a> </th> <th width="320"> - <a href="tickets.php?sort=subj&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="Sort By Subject"><?php echo __('Subject');?><i class="icon-sort"></i></a> + <a href="tickets.php?sort=subject&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="Sort By Subject"><?php echo __('Subject');?> <i class="icon-sort"></i></a> </th> <th width="120"> - <a href="tickets.php?sort=dept&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="Sort By Department"><?php echo __('Department');?><i class="icon-sort"></i></a> + <a href="tickets.php?sort=dept&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="Sort By Department"><?php echo __('Department');?> <i class="icon-sort"></i></a> </th> </tr> </thead> diff --git a/include/upgrader/streams/core/934b8db8-ad9d0a5f.task.php b/include/upgrader/streams/core/934b8db8-ad9d0a5f.task.php index 886bcf6ebb0a7f53102efc66672e18073a032e29..619dfa4e98cab1a4619e4737d4fbd708d1a8ea0e 100644 --- a/include/upgrader/streams/core/934b8db8-ad9d0a5f.task.php +++ b/include/upgrader/streams/core/934b8db8-ad9d0a5f.task.php @@ -24,12 +24,13 @@ class QueueSortCreator extends MigrationTask { // Only save entries with "valid" criteria if (!$row['title'] || !($config = JsonDataParser::parse($row['config'], true)) - || !($criteria = CustomQueue::isolateCriteria($criteria))) + || !($criteria = self::isolateCriteria($config))) continue; + $row['root'] = 'T'; // Ticket Queue + $row['flags'] = 0; // Saved Search $row['config'] = JsonDataEncoder::encode(array( 'criteria' => $criteria, 'conditions' => array())); - $row['root'] = 'T'; CustomQueue::__create(array_intersect_key($row, array_flip( array('staff_id', 'title', 'config', 'flags', 'root', 'created', 'updated')))); @@ -53,7 +54,27 @@ class QueueSortCreator extends MigrationTask { // Set default queue to 'open' global $cfg; - $cfg->set('default_ticket_queue', 1); + if ($cfg) + $cfg->set('default_ticket_queue', 1); + } + + static function isolateCriteria($config) { + + if (is_string($config)) + $config = JsonDataParser::parse($config, true); + + foreach ($config as $k => $v) { + if (substr($k, -7) != '+search') + continue; + + // Fix up some entries + list($name,) = explode('+', $k, 2); + if (!isset($config["{$name}+method"])) + $config["{$name}+method"] = isset($config["{$name}+includes"]) + ? 'includes' : 'set'; + } + + return CustomQueue::isolateCriteria($config); } } return 'QueueSortCreator'; diff --git a/js/redactor-osticket.js b/js/redactor-osticket.js index 12a496c98825195224f72a12c1faed684e9dbc2f..da4b1c203277c2c696520f1a60d870c6138636e8 100644 --- a/js/redactor-osticket.js +++ b/js/redactor-osticket.js @@ -291,10 +291,20 @@ $(function() { var reset = $('input[type=reset]', el.closest('form')); if (reset) { reset.click(function() { + var file = $('.file'); + if (file) + file.remove(); if (el.attr('data-draft-id')) el.redactor('draft.deleteDraft').attr('data-draft-id', ''); - else - el.redactor('insert.set', '', false, false); + else { + try { + el.redactor('insert.set', '', false, false); + } + catch (error) { + el.redactor(); //reinitialize redactor + el.redactor('insert.set', '', false, false); + } + } }); } $('input[type=submit]', el.closest('form')).on('click', function() { @@ -302,7 +312,13 @@ $(function() { // where Redactor does not sync properly after adding an image. // Therefore, the ::get() call will not include text added after // the image was inserted. - el.redactor('code.sync'); + try { + el.redactor('code.sync'); + } + catch (error) { + el.redactor(); //reinitialize redactor + el.redactor('code.sync'); + } }); if (!$.clientPortal) { options['plugins'] = options['plugins'].concat( diff --git a/scp/js/scp.js b/scp/js/scp.js index 5092f7175aad8a9b8aa565df83775f53d9cbab00..82372a9f9ca1f64d76a06f2a16a5867b14044124 100644 --- a/scp/js/scp.js +++ b/scp/js/scp.js @@ -378,7 +378,8 @@ var scp_prep = function() { $('input[name^='+attr+']', ui.item.parent('tbody')).each(function(i, el) { $(el).val(i + 1 + offset); }); - } + }, + 'cancel': ':input,button,div[contenteditable=true]' }); // Scroll to a stop or top on scroll-up click