diff --git a/include/ajax.search.php b/include/ajax.search.php index eb1ef6ed36f534e2e1ad525e13cb4c3e8057e223..4a735f304055ed761ce9c148564aef6edc6ff62f 100644 --- a/include/ajax.search.php +++ b/include/ajax.search.php @@ -28,9 +28,13 @@ class SearchAjaxAPI extends AjaxController { if (!$thisstaff) Http::response(403, 'Agent login required'); - $search = SavedSearch::create(array( + $search = new SavedSearch(array( 'root' => 'T', + 'parent_id' => @$_GET['parent_id'] ?: 0, )); + if ($search->parent_id) { + $search->flags |= SavedSearch::FLAG_INHERIT_COLUMNS; + } if (isset($_SESSION[$context])) { // Use the most recent search if (!$key) { @@ -60,7 +64,7 @@ class SearchAjaxAPI extends AjaxController { if (!$thisstaff) Http::response(403, 'Agent login required'); - $search = SavedSearch::create(array('root'=>'T')); + $search = new SavedSearch(array('root'=>'T')); $searchable = $search->getSupportedMatches(); if (!($F = $searchable[$name])) Http::response(404, 'No such field: ', print_r($name, true)); @@ -82,7 +86,7 @@ class SearchAjaxAPI extends AjaxController { } function doSearch() { - $search = SavedSearch::create(array('root' => 'T')); + $search = new SavedSearch(array('root' => 'T')); $form = $search->getForm($_POST); if (false === $this->_setupSearch($search, $form)) { return; @@ -164,7 +168,7 @@ class SearchAjaxAPI extends AjaxController { function _saveSearch(SavedSearch $search) { $form = $search->getForm($_POST); $errors = array(); - if (!$search->update($_POST, $form, $errors) + if (!$search->update($_POST, $errors) || !$search->save() ) { return $this->_tryAgain($search, $form, $errors); diff --git a/include/class.queue.php b/include/class.queue.php index 461f2d02352db216c276d1bb85d80f77e2d517b1..0dab778b6f605480d52c0bb216d23a477895ccb3 100644 --- a/include/class.queue.php +++ b/include/class.queue.php @@ -60,7 +60,7 @@ class CustomQueue extends VerySimpleModel { function __onload() { // Ensure valid state - if ($this->hasFlag(self::FLAG_INHERIT_COLUMNS) || !$this->parent_id) + if ($this->hasFlag(self::FLAG_INHERIT_COLUMNS) && !$this->parent_id) $this->clearFlag(self::FLAG_INHERIT_COLUMNS); } @@ -454,7 +454,7 @@ class CustomQueue extends VerySimpleModel { return $items; } - function getColumns() { + function getColumns($use_template=false) { if ($this->columns_id && ($q = CustomQueue::lookup($this->columns_id)) ) { @@ -471,6 +471,10 @@ class CustomQueue extends VerySimpleModel { return $this->columns; } + // Use the columns of the "Open" queue as a default template + if ($use_template && ($template = CustomQueue::lookup(1))) + return $template->getColumns(); + // Last resort — use standard columns foreach (array( QueueColumn::placeholder(array( @@ -732,7 +736,11 @@ class CustomQueue extends VerySimpleModel { $this->parent_id > 0 && isset($vars['inherit-columns'])); // Update queue columns (but without save) - if (isset($vars['columns'])) { + if (!isset($vars['columns']) && $this->parent) { + // No columns -- imply column inheritance + $this->setFlag(self::FLAG_INHERIT_COLUMNS); + } + if (isset($vars['columns']) && !$this->hasFlag(self::FLAG_INHERIT_COLUMNS)) { $new = $vars['columns']; $order = array_keys($new); foreach ($this->columns as $col) { @@ -764,10 +772,6 @@ class CustomQueue extends VerySimpleModel { // Re-sort the in-memory columns array $this->columns->sort(function($c) { return $c->sort; }); } - elseif ($this->parent) { - // No columns -- imply column inheritance - $this->setFlag(self::FLAG_INHERIT_COLUMNS); - } // TODO: Move this to SavedSearch::update() and adjust // AjaxSearch::_saveSearch() diff --git a/include/class.search.php b/include/class.search.php index efbbdd3a90b093a32418d9ce9f604032313610b4..7dc62a5144c0c917eb392ba02dc109aaa49f9c66 100644 --- a/include/class.search.php +++ b/include/class.search.php @@ -660,7 +660,7 @@ class SavedSearch extends CustomQueue { ->exclude(array('flags__hasbit'=>self::FLAG_QUEUE)); } - function update($vars, $form=false, &$errors=array()) { + function update($vars, &$errors=array()) { if (!parent::update($vars, $errors)) return false; diff --git a/include/staff/queue.inc.php b/include/staff/queue.inc.php index cf116e4886bd8f8f364b85da2a1cf1380f72cda7..39f0f8007539e5c36eef6f1cd1c828c179aabfa5 100644 --- a/include/staff/queue.inc.php +++ b/include/staff/queue.inc.php @@ -136,77 +136,7 @@ else { <br><?php echo __( "Add, remove, and customize the content of the columns in this queue using the options below. Click a column header to manage or resize it"); ?></p> </div> - <table class="table two-column"> -<?php if ($queue->parent) { ?> - <tbody> - <tr> - <td colspan="3"> - <input type="checkbox" name="inherit-columns" <?php - if ($queue->inheritColumns()) echo 'checked="checked"'; ?> - onchange="javascript:$(this).closest('table').find('.if-not-inherited').toggle(!$(this).prop('checked'));" /> - <?php echo __('Inherit columns from the parent queue'); ?> - <br /><br /> - </td> - </tr> - </tbody> -<?php } ?> - <tbody class="if-not-inherited <?php if ($queue->inheritColumns()) echo 'hidden'; ?>"> - <tr class="header"> - <td style="width:36%"><small><b><?php echo __('Heading and Width'); ?></b></small></td> - <td><small><b><?php echo __('Column Details'); ?></b></small></td> - <td><small><b><?php echo __('Sortable'); ?></b></small></td> - </tr> - </tbody> - <tbody class="sortable-rows if-not-inherited <?php if ($queue->inheritColumns()) echo 'hidden'; ?>"> - <tr id="column-template" class="hidden"> - <td> - <i class="faded-more icon-sort"></i> - <input type="text" size="25" data-name="heading" - data-translate-tag="" /> - <input type="text" size="5" data-name="width" /> - </td> - <td> - <input type="hidden" data-name="queue_id" - value="<?php echo $queue->getId(); ?>"/> - <input type="hidden" data-name="column_id" /> - <div> - <a class="inline action-button" - href="#" onclick="javascript: - var colid = $(this).closest('tr').find('[data-name=column_id]').val(); - $.dialog('ajax.php/tickets/search/column/edit/' + colid, 201); - return false; - "><i class="icon-cog"></i> <?php echo __('Config'); ?></a> - </div> - </td> - <td> - <input type="checkbox" data-name="sortable"> - <a href="#" class="pull-right drop-column" title="<?php echo __('Delete'); - ?>"><i class="icon-trash"></i></a> - </td> - </tr> - </tbody> - <tbody class="if-not-inherited <?php if ($queue->inheritColumns()) echo 'hidden'; ?>"> - <tr class="header"> - <td colspan="3"></td> - </tr> - <tr> - <td colspan="3" id="append-column"> - <i class="icon-plus-sign"></i> - <select id="add-column" data-quick-add="queue-column"> - <option value="">— <?php echo __('Add a column'); ?> —</option> -<?php foreach (QueueColumn::objects() as $C) { ?> - <option value="<?php echo $C->id; ?>"><?php echo - Format::htmlchars($C->name); ?></option> -<?php } ?> - <option value="0" data-quick-add>— <?php echo __('Add New');?> —</option> - </select> - <button type="button" class="green button"> - <?php echo __('Add'); ?> - </button> - </td> - </tr> - </tbody> - </table> + <?php include STAFFINC_DIR . "templates/queue-columns.tmpl.php"; ?> </div> @@ -293,64 +223,3 @@ else { </p> </form> - -<script> -var addColumn = function(colid, info) { - if (!colid) return; - var copy = $('#column-template').clone(), - name_prefix = 'columns[' + colid + ']'; - info['column_id'] = colid; - copy.find('input[data-name]').each(function() { - var $this = $(this), - name = $this.data('name'); - - if (info[name] !== undefined) { - if ($this.is(':checkbox')) - $this.prop('checked', info[name]); - else - $this.val(info[name]); - } - $this.attr('name', name_prefix + '[' + name + ']'); - }); - copy.find('span').text(info['name']); - copy.attr('id', '').show().insertBefore($('#column-template')); - copy.removeClass('hidden'); - if (info['trans'] !== undefined) { - var input = copy.find('input[data-translate-tag]') - .attr('data-translate-tag', info['trans']); - if ($.fn.translatable) - input.translatable(); - // Else it will be made translatable when the JS library is loaded - } - copy.find('a.drop-column').click(function() { - $('<option>') - .attr('value', copy.find('input[data-name=column_id]').val()) - .text(info.name) - .insertBefore($('#add-column') - .find('[data-quick-add]') - ); - copy.fadeOut(function() { $(this).remove(); }); - return false; - }); - var selected = $('#add-column').find('option[value=' + colid + ']'); - selected.remove(); -}; - -$('#append-column').find('button').on('click', function() { - var selected = $('#add-column').find(':selected'), - id = parseInt(selected.val()); - if (!id) - return; - addColumn(id, {name: selected.text(), heading: selected.text(), width: 100, sortable: 1}); - return false; -}); - -<?php foreach ($queue->columns as $C) { - echo sprintf('addColumn(%d, {name: %s, heading: %s, width: %d, trans: %s, - sortable: %s});', - $C->column_id, JsonDataEncoder::encode($C->name), - JsonDataEncoder::encode($C->heading), $C->width, - JsonDataEncoder::encode($C->getTranslateTag('heading')), - $C->isSortable() ? 1 : 0); -} ?> -</script> diff --git a/include/staff/templates/advanced-search.tmpl.php b/include/staff/templates/advanced-search.tmpl.php index f0e3c65aab2d3bb4244c2eb72f148a43ad704bd3..33949c8291382174b12203537da588ae1121d86f 100644 --- a/include/staff/templates/advanced-search.tmpl.php +++ b/include/staff/templates/advanced-search.tmpl.php @@ -1,7 +1,7 @@ <?php $parent_id = $_REQUEST['parent_id'] ?: $search->parent_id; if ($parent_id - && (!($queue = CustomQueue::lookup($parent_id))) + && (!($parent = CustomQueue::lookup($parent_id))) ) { $parent_id = null; } @@ -10,7 +10,9 @@ if ($parent_id <h3 class="drag-handle"><?php echo __('Advanced Ticket Search');?></h3> <a class="close" href=""><i class="icon-remove-circle"></i></a> <hr/> + <form action="#tickets/search" method="post" name="search"> + <div class="flex row"> <div class="span6"> <select name="parent_id"> @@ -32,16 +34,22 @@ foreach (CustomQueue::queues()->order_by('sort', 'title') as $q) { ?> <div class="error"><?php echo Format::htmlchars($errors['name']); ?></div> </div> </div> - <hr/> + +<ul class="tabs"> + <li class="active"><a href="#criteria"><?php echo __('Criteria'); ?></a></li> + <li><a href="#columns"><?php echo __('Columns'); ?></a></li> +</ul> + +<div class="tab_content" id="criteria"> <div class="flex row"> <div class="span12"> -<?php if ($queue) { ?> +<?php if ($parent) { ?> <div class="faded" style="margin-bottom: 1em"> <div> <strong><?php echo __('Inherited Criteria'); ?></strong> </div> <div> - <?php echo nl2br(Format::htmlchars($queue->describeCriteria())); ?> + <?php echo nl2br(Format::htmlchars($parent->describeCriteria())); ?> </div> </div> <?php } ?> @@ -50,6 +58,14 @@ foreach (CustomQueue::queues()->order_by('sort', 'title') as $q) { ?> </div> </div> +</div> + +<div class="tab_content hidden" id="columns"> + <?php + $queue = $search; + include STAFFINC_DIR . "templates/queue-columns.tmpl.php"; ?> +</div> + <hr/> <div> <div class="buttons pull-right"> @@ -66,4 +82,30 @@ foreach (CustomQueue::queues()->order_by('sort', 'title') as $q) { ?> </button> </div> </div> + </form> + +<script> ++function() { + // Return a helper with preserved width of cells + var fixHelper = function(e, ui) { + ui.children().each(function() { + $(this).width($(this).width()); + }); + return ui; + }; + // Sortable tables for dynamic forms objects + $('.sortable-rows').sortable({ + 'helper': fixHelper, + 'cursor': 'move', + 'stop': function(e, ui) { + var attr = ui.item.parent('tbody').data('sort'), + offset = parseInt($('#sort-offset').val(), 10) || 0; + warnOnLeave(ui.item); + $('input[name^='+attr+']', ui.item.parent('tbody')).each(function(i, el) { + $(el).val(i + 1 + offset); + }); + } + }); +}(); +</script> diff --git a/include/staff/templates/queue-columns.tmpl.php b/include/staff/templates/queue-columns.tmpl.php new file mode 100644 index 0000000000000000000000000000000000000000..233a7c411defb2f853a22d3563502719efa4f262 --- /dev/null +++ b/include/staff/templates/queue-columns.tmpl.php @@ -0,0 +1,163 @@ +<table class="table"> +<?php +if ($queue->parent) { ?> + <tbody> + <tr> + <td colspan="3"> + <input type="checkbox" name="inherit-columns" <?php + if ($queue->inheritColumns()) echo 'checked="checked"'; ?> + onchange="javascript:$(this).closest('table').find('.if-not-inherited').toggle(!$(this).prop('checked'));" /> + <?php echo __('Inherit columns from the parent queue'); ?> + <br /><br /> + </td> + </tr> + </tbody> +<?php } + // Adhoc Advanced search does not have customizable columns, but saved + // ones do + elseif ($queue->__new__) { ?> + <tbody> + <tr> + <td colspan="3"> + <input type="checkbox" name="inherit-columns" <?php + if (count($queue->columns) == 0) echo 'checked="checked"'; + if ($queue instanceof SavedSearch) echo 'disabled="disabled"'; ?> + onchange="javascript:$(this).closest('table').find('.if-not-inherited').toggle(!$(this).prop('checked'));" /> + <?php echo __('Use standard columns'); ?> + <br /><br /> + </td> + </tr> + </tbody> +<?php } +$hidden_cols = $queue->inheritColumns() || count($queue->columns) === 0; +?> + <tbody class="if-not-inherited <?php if ($hidden_cols) echo 'hidden'; ?>"> + <tr class="header"> + <td nowrap><small><b><?php echo __('Heading and Width'); ?></b></small></td> + <td><small><b><?php echo __('Column Details'); ?></b></small></td> + <td><small><b><?php echo __('Sortable'); ?></b></small></td> + </tr> + </tbody> + <tbody class="sortable-rows if-not-inherited <?php if ($hidden_cols) echo 'hidden'; ?>"> + <tr id="column-template" class="hidden"> + <td nowrap> + <i class="faded-more icon-sort"></i> + <input type="hidden" data-name="column_id" /> + <input type="text" size="25" data-name="heading" + data-translate-tag="" /> + <input type="text" size="5" data-name="width" /> + </td> + <td> +<?php if (!$queue instanceof SavedSearch) { ?> + <div> + <a class="inline action-button" + href="#" onclick="javascript: + var colid = $(this).closest('tr').find('[data-name=column_id]').val(); + $.dialog('ajax.php/tickets/search/column/edit/' + colid, 201); + return false; + "><i class="icon-cog"></i> <?php echo __('Config'); ?></a> + </div> +<?php } + else { ?> + <input type="text" style="border:none;background:transparent" data-name="name" /> +<?php } ?> + </td> + <td> + <input type="checkbox" data-name="sortable"/> + <a href="#" class="pull-right drop-column" title="<?php echo __('Delete'); + ?>"><i class="icon-trash"></i></a> + </td> + </tr> + </tbody> + <tbody class="if-not-inherited <?php if ($hidden_cols) echo 'hidden'; ?>"> + <tr class="header"> + <td colspan="3"></td> + </tr> + <tr> + <td colspan="3" id="append-column"> + <i class="icon-plus-sign"></i> + <select id="add-column" data-quick-add="queue-column"> + <option value="">— <?php echo __('Add a column'); ?> —</option> +<?php foreach (QueueColumn::objects() as $C) { ?> + <option value="<?php echo $C->id; ?>"><?php echo + Format::htmlchars($C->name); ?></option> +<?php } ?> +<?php if (!$queue instanceof SavedSearch) { ?> + <option value="0" data-quick-add>— <?php echo __('Add New');?> —</option> +<?php } ?> + </select> + <button type="button" class="green button"> + <?php echo __('Add'); ?> + </button> + </td> + </tr> + </tbody> +</table> + +<script> ++function() { +var Q = setInterval(function() { + if ($('#append-column').length == 0) + return; + clearInterval(Q); + + var addColumn = function(colid, info) { + if (!colid) return; + var copy = $('#column-template').clone(), + name_prefix = 'columns[' + colid + ']'; + info['column_id'] = colid; + copy.find('input[data-name]').each(function() { + var $this = $(this), + name = $this.data('name'); + + if (info[name] !== undefined) { + if ($this.is(':checkbox')) + $this.prop('checked', info[name]); + else + $this.val(info[name]); + } + $this.attr('name', name_prefix + '[' + name + ']'); + }); + copy.find('span').text(info['name']); + copy.attr('id', '').show().insertBefore($('#column-template')); + copy.removeClass('hidden'); + if (info['trans'] !== undefined) { + var input = copy.find('input[data-translate-tag]') + .attr('data-translate-tag', info['trans']); + if ($.fn.translatable) + input.translatable(); + // Else it will be made translatable when the JS library is loaded + } + copy.find('a.drop-column').click(function() { + $('<option>') + .attr('value', copy.find('input[data-name=column_id]').val()) + .text(info.name) + .insertBefore($('#add-column') + .find('[data-quick-add]') + ); + copy.fadeOut(function() { $(this).remove(); }); + return false; + }); + var selected = $('#add-column').find('option[value=' + colid + ']'); + selected.remove(); + }; + + $('#append-column').find('button').on('click', function() { + var selected = $('#add-column').find(':selected'), + id = parseInt(selected.val()); + if (!id) + return; + addColumn(id, {name: selected.text(), heading: selected.text(), width: 100, sortable: 1}); + return false; + }); +<?php foreach ($queue->getColumns(true) as $C) { + echo sprintf('addColumn(%d, {name: %s, heading: %s, width: %d, trans: %s, + sortable: %s});', + $C->column_id, JsonDataEncoder::encode($C->name), + JsonDataEncoder::encode($C->heading), $C->width, + JsonDataEncoder::encode($C->getTranslateTag('heading')), + $C->isSortable() ? 1 : 0); +} ?> +}, 25); +}(); +</script> diff --git a/include/staff/templates/queue-tickets.tmpl.php b/include/staff/templates/queue-tickets.tmpl.php index 664a8d6e151fce4312b5af48c484f55bebc80f6a..50f94fab984f046d999ea614c2c36a48b02b1443 100644 --- a/include/staff/templates/queue-tickets.tmpl.php +++ b/include/staff/templates/queue-tickets.tmpl.php @@ -208,8 +208,12 @@ foreach ($tickets as $T) { } foreach ($columns as $C) { list($contents, $styles) = $C->render($T); - $style = $styles ? 'style="'.$styles.'"' : ''; - echo "<td $style><div $style>$contents</div></td>"; + if ($style = $styles ? 'style="'.$styles.'"' : '') { + echo "<td $style><div $style>$contents</div></td>"; + } + else { + echo "<td>$contents</td>"; + } } echo '</tr>'; } diff --git a/scp/tickets.php b/scp/tickets.php index f1b6f48b191dd96b173f66e554c5a7ad10893bd4..783a27830c8f411892dae17cb497bb04227a1afd 100644 --- a/scp/tickets.php +++ b/scp/tickets.php @@ -94,16 +94,16 @@ if (!$ticket) { && strpos($queue_id, 'adhoc') === 0 ) { list(,$key) = explode(',', $queue_id, 2); - // XXX: De-duplicate and simplify this code - $queue = new AdhocSearch(array( - 'id' => $queue_id, - 'root' => 'T', - )); // For queue=queue, use the most recent search if (!$key) { reset($_SESSION['advsearch']); $key = key($_SESSION['advsearch']); } + // XXX: De-duplicate and simplify this code + $queue = new AdhocSearch(array( + 'id' => "adhoc,$key", + 'root' => 'T', + )); $queue->config = $_SESSION['advsearch'][$key]; }