diff --git a/WHATSNEW.md b/WHATSNEW.md index 61c3aaaaf3b589f35444e7126f6dd3a4768eb772..653f8a5c0462d8d7630c5506b4b4099a29fe27c1 100644 --- a/WHATSNEW.md +++ b/WHATSNEW.md @@ -1,3 +1,45 @@ +osTicket v1.9.7 +=============== +### Enhancements + * Remote IP is logged for staff replies (#1846) + * Add option to require client login to view knowledge base (#1851) + * Internal activity alert, replacing the internal note alert, includes alerts + of responses made by other agents (#1865) + * Email system now uses LF instead of CRLF as the default (#1909) + * Mass actions for user directory (#1924) + * Unassign tickets on transfer if current assignee is not a member of the new + department and the department has "Restrict assignment to members" enabled + (#1923) + +### Improvements + * Clear overdue flag when a ticket is closed, thanks @A-Lawrence (#1739) + * Clear attached file listing on client post (regression) (#1845) + * Delete ticket custom data on delete (#1840) + * Trim whitespace from filter match data on update (#1844) + * Fix dropping of custom data on API post (#1839) + * Fix advanced search on create date (#1848) + * Fix initial load and pagination of dashboard page (#1856) + * Fix incorrect internal/public category setting in drop down for new FAQ + (#1867) + * Add UTF-8 BOM to CSV export for correct Unicode detection (#1869) + * Fix not considering the setting for alert assigned on new message (#1850) + * Skip new activity notice if collaborator(s) included in email To or Cc + header (#1871) + * Fix inability to uncheck a custom data checkbox (#1866) + * Fix advanced search for unassigned tickets (#1857) + * Fix navigation warning if not using the lock feature (#1898) + * Fix detection of message of some bounce notices (#1914) + * Fix SQL alert with multiple Message-ID headers (#1920) + * Add a warning if attempting to configure archiving for POP accounts (#1921) + * Fix missing UTF-8 output encoding header for staff control panel (#1918) + * Fix z-index issue between popup previews and modal dialogs (#1919) + * Record imported file backend when importing files (f1e31ba) + +### Performance and Security + * Fix XSS vulnerability in sequence management (88bedbd) + * Defer loading of thread email header information when loading ticket thread + (#1900) + osTicket v1.9.6 =============== ### Enhancements diff --git a/include/class.charset.php b/include/class.charset.php index 5411e6b4abcb1347a0e22998678b13d57fe119d3..aa26cb2ccb36cb4232c144408d2405430dde3fe6 100644 --- a/include/class.charset.php +++ b/include/class.charset.php @@ -24,14 +24,16 @@ class Charset { $match = array(); switch (true) { // Windows charsets - force correct format - case preg_match('`^Windows-?(\d+)$`', $charset, $match): + case preg_match('`^Windows-?(\d+)$`i', $charset, $match): return 'Windows-'.$match[1]; // ks_c_5601-1987: Korean alias for cp949 - case preg_match('`^ks_c_5601-1987`', $charset): + case preg_match('`^ks_c_5601-1987`i', $charset): return 'cp949'; + case preg_match('`^iso-?(\S+)$`i', $charset, $match): + return "ISO-".$match[1]; // Incorrect, bogus, ambiguous or empty charsets // ISO-8859-1 is assumed - case preg_match('`^(default|x-user-defined|iso|us-ascii)`', $charset): + case preg_match('`^(default|x-user-defined|iso|us-ascii)$`i', $charset): case preg_match('`^\s*$`', $charset): return 'ISO-8859-1'; } diff --git a/include/class.dynamic_forms.php b/include/class.dynamic_forms.php index 36dfce384166d14798fd6ce5462cab2bc63cda16..834a40deb372b4c10b942c348d8110cfa674ad3f 100644 --- a/include/class.dynamic_forms.php +++ b/include/class.dynamic_forms.php @@ -140,12 +140,13 @@ class DynamicForm extends VerySimpleModel { return $visible > 0; } - function instanciate($sort=1, $data=false) { - $entry = DynamicFormEntry::create(array( - 'form_id'=>$this->get('id'), 'sort'=>$sort)); + function instanciate($sort=1, $data=null) { + $inst = DynamicFormEntry::create( + array('form_id'=>$this->get('id'), 'sort'=>$sort) + ); if ($data) - $entry->setSource($data); - return $entry; + $inst->setSource($data); + return $inst; } function getTranslateTag($subtag) { @@ -196,8 +197,7 @@ class DynamicForm extends VerySimpleModel { if (isset($ht['fields'])) { $inst->save(); foreach ($ht['fields'] as $f) { - $f = DynamicFormField::create(array('form' => $inst)); - $f->setForm($inst); + $field = DynamicFormField::create(array('form' => $inst) + $f); $f->save(); } } @@ -274,7 +274,7 @@ class DynamicForm extends VerySimpleModel { if ($exclude && in_array($f->get('name'), $exclude)) continue; - $impl = $f->getImpl(); + $impl = $f->getImpl($f); if (!$impl->hasData() || $impl->isPresentationOnly()) continue; @@ -404,6 +404,9 @@ class TicketForm extends DynamicForm { return; $f = $answer->getField(); + if (!$f->getFormId()) + return; + $name = $f->get('name') ?: ('field_'.$f->get('id')); $fields = sprintf('`%s`=', $name) . db_input( implode(',', $answer->getSearchKeys())); @@ -545,6 +548,9 @@ class DynamicFormField extends VerySimpleModel { return $this->_field; } + function getForm() { return $this->form; } + function getFormId() { return $this->form_id; } + /** * setConfiguration * @@ -1137,11 +1143,13 @@ class DynamicFormEntry extends VerySimpleModel { return true; } - static function create($ht=false) { + static function create($ht=false, $data=null) { $inst = parent::create($ht); $inst->set('created', new SqlFunction('NOW')); foreach ($inst->getDynamicFields() as $field) { - if (!$field->getImpl()->hasData()) + if (!($impl = $field->getImpl($field))) + continue; + if (!$impl->hasData() || !$impl->isStorable()) continue; $a = DynamicFormEntryAnswer::create( array('field'=>$field, 'entry'=>$inst)); @@ -1259,6 +1267,15 @@ class DynamicFormEntryAnswer extends VerySimpleModel { $v = $this->toString(); return is_string($v) ? $v : (string) $this->getValue(); } + + function delete() { + if (!parent::delete()) + return false; + + // Allow the field to cleanup anything else in the database + $this->getField()->db_cleanup(); + return true; + } } class SelectionField extends FormField { @@ -1362,7 +1379,7 @@ class SelectionField extends FormField { } function toString($items) { - return ($items && is_array($items)) + return is_array($items) ? implode(', ', $items) : (string) $items; } diff --git a/include/class.forms.php b/include/class.forms.php index 00d9a1c126a4a4d237a76de0096e6785e887bb14..d63b17129e439a20c114195f3fbc0e253ad6eb66 100644 --- a/include/class.forms.php +++ b/include/class.forms.php @@ -140,6 +140,7 @@ class Form { include(STAFFINC_DIR . 'templates/dynamic-form.tmpl.php'); else include(CLIENTINC_DIR . 'templates/dynamic-form.tmpl.php'); + echo $this->getMedia(); } function getMedia() { @@ -492,6 +493,15 @@ class FormField { return $this->toString($this->value); } + /** + * When data for this field is deleted permanently from some storage + * backend (like a database), other associated data may need to be + * cleaned as well. This hook allows fields to participate when the data + * for a field is cleaned up. + */ + function db_cleanup() { + } + /** * Returns an HTML friendly value for the data in the field. */ @@ -2140,6 +2150,14 @@ class FileUploadField extends FormField { } return implode(', ', $files); } + + function db_cleanup() { + // Delete associated attachments from the database, if any + $this->getFiles(); + if (isset($this->attachments)) { + $this->attachments->deleteAll(); + } + } } class InlineFormData extends ArrayObject { diff --git a/include/class.mailer.php b/include/class.mailer.php index ff1a463c3cfc9a444fdcb75020efbe4e2234b9ca..a58e37c0581b2f246932ebdb74e8d6bd3f739e7d 100644 --- a/include/class.mailer.php +++ b/include/class.mailer.php @@ -353,12 +353,13 @@ class Mailer { if (isset($options['thread']) && $options['thread'] instanceof ThreadEntry ) { - if ($references = $options['thread']->getEmailReferences()) - $headers += array('References' => $references); if ($irt = $options['thread']->getEmailMessageId()) { // This is an response from an email, like and autoresponse. // Web posts will not have a email message-id - $headers += array('In-Reply-To' => $irt); + $headers += array( + 'In-Reply-To' => $irt, + 'References' => $options['thread']->getEmailReferences() + ); } elseif ($parent = $options['thread']->getParent()) { // Use the parent item as the email information source. This diff --git a/include/class.mailfetch.php b/include/class.mailfetch.php index 3b0c7cecddcaa349ddd589415df13c50aa8908b0..0fa55e099358a53c56a0e6e29a99e21b910bdd7b 100644 --- a/include/class.mailfetch.php +++ b/include/class.mailfetch.php @@ -658,7 +658,7 @@ class MailFetcher { $vars['in-reply-to'] = @$headers['in-reply-to'] ?: null; } // Fetch deliver status report - $data['message'] = $this->getDeliveryStatusMessage($mid) ?: $this->getBody($mid); + $vars['message'] = $this->getDeliveryStatusMessage($mid) ?: $this->getBody($mid); $vars['thread-type'] = 'N'; $vars['flags']['bounce'] = true; } diff --git a/include/class.organization.php b/include/class.organization.php index c5b8de4d1895198180ec3efd5f7915f98ecde79b..ffd25216f52026e82a41d0f4a9b105bd82f17a5c 100644 --- a/include/class.organization.php +++ b/include/class.organization.php @@ -152,15 +152,12 @@ class Organization extends OrganizationModel { var $_forms; function addDynamicData($data) { + $entry = $this->addForm(OrganizationForm::objects()->one(), 1, $data); + // FIXME: For some reason, the second save here is required or the + // custom data is not properly saved + $entry->save(); - $of = OrganizationForm::getInstance($this->id, true); - foreach ($of->getFields() as $f) - if (isset($data[$f->get('name')])) - $of->setAnswer($f->get('name'), $data[$f->get('name')]); - - $of->save(); - - return $of; + return $entry; } function getDynamicData($create=true) { @@ -240,12 +237,12 @@ class Organization extends OrganizationModel { } } - function addForm($form, $sort=1) { - $form = $form->instanciate(); - $form->set('sort', $sort); - $form->set('object_type', 'O'); - $form->set('object_id', $this->getId()); - $form->save(); + function addForm($form, $sort=1, $data) { + $entry = $form->instanciate($sort, $data); + $entry->set('object_type', 'O'); + $entry->set('object_id', $this->getId()); + $entry->save(); + return $entry; } function getFilterData() { @@ -353,6 +350,7 @@ class Organization extends OrganizationModel { $this->name = $name->getClean(); $this->save(); } + $entry->setSource($vars); $entry->save(); } @@ -381,6 +379,15 @@ class Organization extends OrganizationModel { return $this->save(); } + function delete() { + if (!parent::delete()) + return false; + + foreach ($this->getDynamicData(false) as $entry) { + $entry->delete(); + } + } + static function fromVars($vars) { if (!($org = Organization::lookup(array('name' => $vars['name'])))) { @@ -399,14 +406,15 @@ class Organization extends OrganizationModel { static function fromForm($form) { - if(!$form) return null; + if (!$form) + return null; //Validate the form $valid = true; if (!$form->isValid()) $valid = false; - //Make sure the email is not in-use + // Make sure the name is not in-use if (($field=$form->getField('name')) && $field->getClean() && Organization::lookup(array('name' => $field->getClean()))) { @@ -452,9 +460,9 @@ class OrganizationForm extends DynamicForm { return static::$form; } - static function getInstance($object_id=0, $new=false) { + static function getInstance($object_id=0, $new=false, $data=null) { if ($new || !isset(static::$instance)) - static::$instance = static::getDefaultForm()->instanciate(); + static::$instance = static::getDefaultForm()->instanciate(1, $data); static::$instance->object_type = 'O'; diff --git a/include/class.orm.php b/include/class.orm.php index 6a823273fc85b00e595499fe8b5fdbb4693ffa89..58aeaede544bc124cc7e1cf6a905d6baad12871c 100644 --- a/include/class.orm.php +++ b/include/class.orm.php @@ -235,7 +235,9 @@ class VerySimpleModel { function set($field, $value) { // Update of foreign-key by assignment to model instance if (isset(static::$meta['joins'][$field])) { - static::_inspect(); + // XXX: This is likely not necessary + if (!isset(static::$meta['joins'][$field]['fkey'])) + static::_inspect(); $j = static::$meta['joins'][$field]; if ($j['list'] && ($value instanceof InstrumentedList)) { // Magic list property @@ -385,7 +387,7 @@ class VerySimpleModel { // local foreign key field values static::_inspect(); foreach (static::$meta['joins'] as $prop => $j) { - if (isset($this->ht[$prop]) + if (isset($this->ht[$prop]) && ($foreign = $this->ht[$prop]) && $foreign instanceof VerySimpleModel && !in_array($j['local'], $pk) @@ -435,7 +437,7 @@ class VerySimpleModel { if ($refetch) { // Preserve non database information such as list relationships // across the refetch - $this->ht = + $this->ht = static::objects()->filter($this->getPk())->values()->one() + $this->ht; } @@ -443,7 +445,7 @@ class VerySimpleModel { // Attempt to update foreign, unsaved objects with the PK of // this newly created object foreach (static::$meta['joins'] as $prop => $j) { - if (isset($this->ht[$prop]) + if (isset($this->ht[$prop]) && ($foreign = $this->ht[$prop]) && in_array($j['local'], $pk) ) { diff --git a/include/class.template.php b/include/class.template.php index d8e2b8a5d61af30a15e9ad1347772dc417b53695..00a81c066c486a9fe9f95c1fea17b3bae57c683e 100644 --- a/include/class.template.php +++ b/include/class.template.php @@ -65,8 +65,8 @@ class EmailTemplateGroup { 'desc'=>/* @trans */ 'Alert sent to agents, if enabled, when user replies to an existing ticket.'), 'note.alert'=>array( 'group'=>'ticket.staff', - 'name'=>/* @trans */ 'Internal Note Alert', - 'desc'=>/* @trans */ 'Alert sent to selected agents, if enabled, on new internal note.'), + 'name'=>/* @trans */ 'Internal Activity Alert', + 'desc'=>/* @trans */ 'Alert sent out to Agents when internal activity such as an internal note or an agent reply is appended to a ticket.'), 'assigned.alert'=>array( 'group'=>'ticket.staff', 'name'=>/* @trans */ 'Ticket Assignment Alert', diff --git a/include/class.ticket.php b/include/class.ticket.php index 30b7ed09bc8eac8c1613fc42e230eb34c631aace..b9f740d67210e2b5deb6c1cb768693f76cb32742 100644 --- a/include/class.ticket.php +++ b/include/class.ticket.php @@ -2826,24 +2826,33 @@ implements RestrictedAccess, Threadable { } } + if (!$user) { + $interesting = array('name', 'email'); + $user_form = UserForm::getUserForm()->getForm($vars); + // Add all the user-entered info for filtering + foreach ($interesting as $F) { + $field = $user_form->getField($F); + $vars[$F] = $field->toString($field->getClean()); + } + // Attempt to lookup the user and associated data + $user = User::lookupByEmail($vars['email']); + } + // Add in user and organization data for filtering if ($user) { $vars += $user->getFilterData(); $vars['email'] = $user->getEmail(); - $vars['name'] = $user->getName(); + $vars['name'] = $user->getName()->getOriginal(); if ($org = $user->getOrganization()) { $vars += $org->getFilterData(); } } - // Unpack the basic user information + // Don't include org information based solely on email domain + // for existing user instances else { - $interesting = array('name', 'email'); - $user_form = UserForm::getUserForm()->getForm($vars); - // Add all the user-entered info for filtering + // Unpack all known user info from the request foreach ($user_form->getFields() as $f) { $vars['field.'.$f->get('id')] = $f->toString($f->getClean()); - if (in_array($f->get('name'), $interesting)) - $vars[$f->get('name')] = $vars['field.'.$f->get('id')]; } // Add in organization data if one exists for this email domain list($mailbox, $domain) = explode('@', $vars['email'], 2); diff --git a/include/class.user.php b/include/class.user.php index 195e0de47aaa66f73ac15c681a154fca366948eb..71fa471918f79cba6e16aff797eba074cfddd2e2 100644 --- a/include/class.user.php +++ b/include/class.user.php @@ -285,7 +285,7 @@ class User extends UserModel { return $this->created; } - function addForm($form, $sort=1, $data=false) { + function addForm($form, $sort=1, $data=null) { $entry = $form->instanciate($sort, $data); $entry->set('object_type', 'U'); $entry->set('object_id', $this->getId()); diff --git a/include/client/templates/dynamic-form.tmpl.php b/include/client/templates/dynamic-form.tmpl.php index 92514f476de426580e0d0e331c2b2095251e5e5e..bcfc9ada252471feb406527b69b274ff945e183f 100644 --- a/include/client/templates/dynamic-form.tmpl.php +++ b/include/client/templates/dynamic-form.tmpl.php @@ -5,8 +5,6 @@ ?> <tr><td colspan="2"><hr /> <div class="form-header" style="margin-bottom:0.5em"> - <?php print ($form instanceof DynamicFormEntry) - ? $form->getForm()->getMedia() : $form->getMedia(); ?> <h3><?php echo Format::htmlchars($form->getTitle()); ?></h3> <div><?php echo Format::display($form->getInstructions()); ?></div> </div> diff --git a/include/client/view.inc.php b/include/client/view.inc.php index bc331dee94d8eab2efc2a64d6cbdc72ac74b3de4..249f3058bbf7a5981116c86528ca0776ebaf2751 100644 --- a/include/client/view.inc.php +++ b/include/client/view.inc.php @@ -184,6 +184,7 @@ if (!$ticket->isClosed() || $ticket->isReopenable()) { ?> if ($messageField->isAttachmentsEnabled()) { ?> <?php print $attachments->render(array('client'=>true)); + print $attachments->getForm()->getMedia(); ?> <?php } ?> diff --git a/include/i18n/en_US/help/tips/staff.department.yaml b/include/i18n/en_US/help/tips/staff.department.yaml index 0c6f555c240fb2b4609e8f325c2bf8059c0624fc..28637faa31a1c7738208b306bf2a9f2c95ae1a38 100644 --- a/include/i18n/en_US/help/tips/staff.department.yaml +++ b/include/i18n/en_US/help/tips/staff.department.yaml @@ -72,7 +72,7 @@ group_membership: sandboxing: title: Ticket Assignment Restrictions content: > - Enable this to restrict ticket assignement to only include members + Enable this to restrict ticket assignment to include only members of this Department. Department membership can be extended to Groups, if <span class="doc-desc-title">Alerts & Notices Recipients</span> includes groups members. diff --git a/include/mpdf/config_fonts.php b/include/mpdf/config_fonts.php index 31c4e3015c289a003309130f9731ec82d52bf257..3fd7fe003d1f9642bed30edc6285c514d1028458 100755 --- a/include/mpdf/config_fonts.php +++ b/include/mpdf/config_fonts.php @@ -303,10 +303,11 @@ $this->mono_fonts = array('dejavusansmono','freemono','liberationmono','courier' // Add fonts from language packs -list($phar_fonts, $phar_subs) = Internationalization::getTtfFonts(); -$this->fontdata += $phar_fonts; -foreach ($phar_subs as $simple) { - if (!in_array($simple, $this->backupSubsFont)) - $this->backupSubsFont[] = $simple; +if (list($phar_fonts, $phar_subs) = Internationalization::getTtfFonts()) { + $this->fontdata += $phar_fonts; + foreach ($phar_subs as $simple) { + if (!in_array($simple, $this->backupSubsFont)) + $this->backupSubsFont[] = $simple; + } } ?> diff --git a/include/staff/filter.inc.php b/include/staff/filter.inc.php index 61e563bc077c5ec1a4eeef94191e6408ab981b67..5b4cfddcf95762c4ec963fea9283fa574dcccd1c 100644 --- a/include/staff/filter.inc.php +++ b/include/staff/filter.inc.php @@ -78,7 +78,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info); </td> <td> <select name="target"> - <option value="">— <?php echo __('Select a Channel');?> ‐</option> + <option value="">— <?php echo __('Select a Channel');?> —</option> <?php foreach(Filter::getTargets() as $k => $v) { echo sprintf('<option value="%s" %s>%s</option>', diff --git a/include/staff/orgs.inc.php b/include/staff/orgs.inc.php index fff47ba84ba16bb6f2d5cf6dbc35407b6c08f942..84288aeda3ad643af8183b1e1a5a37c84ca4ccf6 100644 --- a/include/staff/orgs.inc.php +++ b/include/staff/orgs.inc.php @@ -209,7 +209,8 @@ $(function() { $(document).on('click', 'a.add-org', function(e) { e.preventDefault(); $.orgLookup('ajax.php/orgs/add', function (org) { - window.location.href = 'orgs.php?id='+org.id; + var url = 'orgs.php?id=' + org.id; + $.pjax({url: url, container: '#pjax-container'}) }); return false; diff --git a/include/staff/ticket-edit.inc.php b/include/staff/ticket-edit.inc.php index b1e8dcf77a5c00d0b06d7b7b046be334e3597f07..fe92935d10799e14796174c8cde866561857d635 100644 --- a/include/staff/ticket-edit.inc.php +++ b/include/staff/ticket-edit.inc.php @@ -138,7 +138,6 @@ if ($_POST) <?php if ($forms) foreach ($forms as $form) { $form->render(true, false, array('mode'=>'edit','width'=>160,'entry'=>$form)); - print $form->getForm()->getMedia(); } ?> </table> <table class="form_table" width="940" border="0" cellspacing="0" cellpadding="2"> diff --git a/include/staff/users.inc.php b/include/staff/users.inc.php index e83671a684eb9bd63cfb79a83d57180bb615b587..848abf4dc1f35eed7bea90308af83504ab464b34 100644 --- a/include/staff/users.inc.php +++ b/include/staff/users.inc.php @@ -244,10 +244,11 @@ $(function() { $(document).on('click', 'a.popup-dialog', function(e) { e.preventDefault(); $.userLookup('ajax.php/' + $(this).attr('href').substr(1), function (user) { + var url = window.location.href; if (user && user.id) - window.location.href = 'users.php?id='+user.id; - else - $.pjax({url: window.location.href, container: '#pjax-container'}) + url = 'users.php?id='+user.id; + $.pjax({url: url, container: '#pjax-container'}) + return false; }); return false; @@ -283,11 +284,14 @@ $(function() { $(document).on('dialog:close', function(e, json) { $form = $('form#users-list'); try { - var json = $.parseJSON(json); - $form.find('#org_id').val(json.id); - goBaby('setorg', true); + var json = $.parseJSON(json), + org_id = $form.find('#org_id'); + if (json.id) { + org_id.val(json.id); + goBaby('setorg', true); + } } - catch (e) { console.log(e); } + catch (e) { } }); }); </script> diff --git a/include/tnef_decoder.php b/include/tnef_decoder.php index 70e455851fc69d236f822ed033fdb7e731219f57..0459998d48109087da43cdb135e2260ba38ae75a 100644 --- a/include/tnef_decoder.php +++ b/include/tnef_decoder.php @@ -345,7 +345,14 @@ class TnefAttributeStreamReader extends TnefStreamReader { } return $text; + + case self::TypeCLSID: + return $this->_getx(16); + + default: + throw new TnefException(sprintf('0x%04x: Bad data type', $type)); } + } function next() { diff --git a/scp/forms.php b/scp/forms.php index 2e164f24385de0ff92431634de3a114a20409bd3..59084775c088e9bd5e845c7b651e3542879e05a3 100644 --- a/scp/forms.php +++ b/scp/forms.php @@ -127,7 +127,7 @@ if($_POST) { if (!$errors) { $form->save(true); foreach ($form_fields as $field) { - $field->set('form_id', $form->get('id')); + $field->form = $form; $field->save(); } // No longer adding a new form diff --git a/scp/js/scp.js b/scp/js/scp.js index af56fc43e0b95c6bdccfd1ca2f63dc90dc63c3bb..8f99d9545c636d7b4e802521632f33c162ca1b19 100644 --- a/scp/js/scp.js +++ b/scp/js/scp.js @@ -526,11 +526,11 @@ $.toggleOverlay = function (show) { return $.toggleOverlay(!$('#overlay').is(':visible')); } if (show) { - $('#overlay').fadeIn(); + $('#overlay').stop().hide().fadeIn(); $('body').css('overflow', 'hidden'); } else { - $('#overlay').fadeOut(); + $('#overlay').stop().fadeOut(); $('body').css('overflow', 'auto'); } }; @@ -574,13 +574,15 @@ $.dialog = function (url, codes, cb, options) { data: $form.serialize(), cache: false, success: function(resp, status, xhr) { - var done = $.Event('dialog:close'); if (xhr && xhr.status && codes && $.inArray(xhr.status, codes) != -1) { $.toggleOverlay(false); $popup.hide(); $('div.body', $popup).empty(); - if(cb) cb(xhr, resp); + if (cb && (false === cb(xhr, resp))) + // Don't fire event if callback returns false + return; + var done = $.Event('dialog:close'); $popup.trigger(done, [resp, status, xhr]); } else { try { @@ -623,7 +625,7 @@ $.confirm = function(message, title) { var D = $.Deferred(), $popup = $('.dialog#popup'), hide = function() { - $('#overlay').hide(); + $.toggleOverlay(false); $popup.hide(); }; $('div#popup-loading', $popup).hide(); @@ -646,7 +648,7 @@ $.confirm = function(message, title) { .attr('value', __('OK')) .click(function() { hide(); D.resolve(); }) ))).append($('<div class="clear"></div>')); - $('#overlay').fadeIn(); + $.toggleOverlay(true); $popup.show(); return D.promise(); }; @@ -654,7 +656,7 @@ $.confirm = function(message, title) { $.userLookup = function (url, cb) { $.dialog(url, 201, function (xhr) { var user = $.parseJSON(xhr.responseText); - if (cb) cb(user); + if (cb) return cb(user); }, { onshow: function() { $('#user-search').focus(); } }); @@ -790,6 +792,7 @@ $(document).on('pjax:start', function() { $(window).unbind('beforeunload'); // Close popups $('.dialog .body').empty().parent().hide(); + $.toggleOverlay(false); // Close tooltips $('.tip_box').remove(); }); @@ -805,7 +808,8 @@ $(document).on('pjax:send', function(event) { // right $('#loadingbar').stop(false, true).width((50 + Math.random() * 30) + "%"); - $('#overlay').css('background-color','white').fadeIn(); + $('#overlay').css('background-color','white'); + $.toggleOverlay(true); }); $(document).on('pjax:complete', function() { diff --git a/scp/tickets.php b/scp/tickets.php index 86247b2b03e0089e8f0dff7d42b5483cb232abdd..4d15d30dee7ce88608d9ab9991436433321fd126 100644 --- a/scp/tickets.php +++ b/scp/tickets.php @@ -168,7 +168,7 @@ if($_POST && !$errors): $errors['assignId'] = __('Select assignee'); elseif ($_POST['assignId'][0]!='s' && $_POST['assignId'][0]!='t' && !$claim) $errors['assignId']= sprintf('%s - %s', - __('Invalid assignee '), + __('Invalid assignee'), __('get technical support')); elseif ($_POST['assignId'][0]!='s' && $dept->assignMembersOnly()