diff --git a/include/ajax.search.php b/include/ajax.search.php index 7e0452dd296d27fbf8a7ffc3d27ed9cec9824ab8..0ef01784bde6a313007dcffbcc13b279e2bb03a7 100644 --- a/include/ajax.search.php +++ b/include/ajax.search.php @@ -32,10 +32,19 @@ class SearchAjaxAPI extends AjaxController { 'root' => 'T', )); $search->config = $_SESSION['advsearch']; - $form = $search->getForm(); - $matches = $search->getSupportedMatches(); + $this->_tryAgain($search, $search->getForm()); + } - include STAFFINC_DIR . 'templates/advanced-search.tmpl.php'; + function editSearch($id) { + global $thisstaff; + + $search = SavedSearch::lookup($id); + if (!$thisstaff) + Http::response(403, 'Agent login is required'); + elseif (!$search || !$search->checkAccess($thisstaff)) + Http::response(404, 'No such saved search'); + + $this->_tryAgain($search, $search->getForm()); } function addField($name) { @@ -66,62 +75,68 @@ class SearchAjaxAPI extends AjaxController { } function doSearch() { - global $thisstaff; - $search = SavedSearch::create(array('root' => 'T')); - $form = $search->getForm($_POST); - if (!$form->isValid()) { - $matches = $search->getSupportedMatches(); - include STAFFINC_DIR . 'templates/advanced-search.tmpl.php'; + if (false === $this->_setupSearch($search, $form)) { return; } - $_SESSION['advsearch'] = $search->isolateCriteria($form->getClean()); Http::response(200, $this->encode(array( 'redirect' => 'tickets.php?queue=adhoc', ))); } + function _hasErrors(SavedSearch $search, $form) { + if (!$form->isValid()) { + $this->_tryAgain($search, $form); + return true; + } + } + + function _setupSearch(SavedSearch $search, $form, $key='advsearch') { + $form = $search->getForm($vars); + if ($this->_hasErrors($search, $form)) + return false; + + $_SESSION[$key] = $search->isolateCriteria($form->getClean()); + } + + function _tryAgain($search, $form, $errors=array()) { + $matches = $search->getSupportedMatches(); + include STAFFINC_DIR . 'templates/advanced-search.tmpl.php'; + } + function saveSearch($id) { global $thisstaff; $search = SavedSearch::lookup($id); - if (!$search || !$search->checkAccess($thisstaff)) - Http::response(404, 'No such saved search'); - elseif (!$thisstaff) + if (!$thisstaff) Http::response(403, 'Agent login is required'); + elseif (!$search || !$search->checkAccess($thisstaff)) + Http::response(404, 'No such saved search'); - return self::_saveSearch($search); + if (false === $this->_saveSearch($search)) + return; + + Http::response(200, $this->encode(array( + 'redirect' => 'tickets.php?queue='.Format::htmlchars($search->id), + ))); } - function _saveSearch($search) { - $data = array(); - foreach ($_POST['form'] as $id=>$info) { - $name = $info['name']; - if (substr($name, -2) == '[]') - $data[substr($name, 0, -2)][] = $info['value']; - else - $data[$name] = $info['value']; - } - $form = $search->getForm($data); - $form->setSource($data); - if (!$data || !$form->isValid()) { - Http::response(422, 'Validation errors exist on criteria'); + function _saveSearch(SavedSearch $search) { + $form = $search->getForm($_POST); + $errors = array(); + if (!$search->update($_POST, $form, $errors) + || !$search->save() + ) { + return $this->_tryAgain($search, $form, $errors); } - $search->config = JsonDataEncoder::encode($form->getState()); - if (isset($_POST['name'])) - $search->title = Format::htmlchars($_POST['name']); - elseif ($search->__new__) - Http::response(400, 'A name is required'); - if (!$search->save()) { - Http::response(500, 'Unable to update search. Internal error occurred'); + if (false === $this->_setupSearch($search, $form)) { + return false; } - Http::response(201, $this->encode(array( - 'id' => $search->id, - 'title' => $search->title, - ))); + + return true; } function createSearch() { @@ -130,28 +145,14 @@ class SearchAjaxAPI extends AjaxController { if (!$thisstaff) Http::response(403, 'Agent login is required'); - $search = SavedSearch::create(); + $search = SavedSearch::create(array('root' => 'T')); $search->staff_id = $thisstaff->getId(); - return self::_saveSearch($search); - } - - function loadSearch($id) { - global $thisstaff; - - if (!$thisstaff) { - Http::response(403, 'Agent login is required'); - } - elseif (!($search = SavedSearch::lookup($id))) { - Http::response(404, 'No such saved search'); - } - - if ($state = JsonDataParser::parse($search->config)) { - $form = $search->loadFromState($state); - $form->loadState($state); - } - $matches = SavedSearch::getSupportedTicketMatches(); + if (false === $this->_saveSearch($search)) + return; - include STAFFINC_DIR . 'templates/advanced-search.tmpl.php'; + Http::response(200, $this->encode(array( + 'redirect' => 'tickets.php?queue='.Format::htmlchars($search->id), + ))); } function deleteSearch($id) { @@ -225,7 +226,7 @@ class SearchAjaxAPI extends AjaxController { Http::response(400, sprintf('%s: No such searchable field'), Format::htmlchars($_GET['field'])); } - + list($label, $field) = $fields[$_GET['field']]; // Ensure `name` is preserved $field_name = $_GET['field']; diff --git a/include/class.forms.php b/include/class.forms.php index a5057f3a5ec0906ca0fde20ad1f8f454eba21250..34c162a14c33945f94598b75afdb57ddd31a5bdd 100644 --- a/include/class.forms.php +++ b/include/class.forms.php @@ -3164,6 +3164,8 @@ class InlineFormField extends FormField { $form = $this->get('form'); if (is_array($form)) { $form = new SimpleForm($form, $data ?: $this->value ?: $this->getSource()); + // Ensure unique, but predictable form and field IDs + $form->setId(sprintf('%u', crc32($this->get('name')) >> 1)); } return $form; } diff --git a/include/class.orm.php b/include/class.orm.php index 5fcf7359cb258185ba12052403ed6f2ebf48af4b..1c3ba561798665864e700e79ad9b902b7efac243 100644 --- a/include/class.orm.php +++ b/include/class.orm.php @@ -114,8 +114,17 @@ class ModelMeta implements ArrayAccess { } } + /** + * Merge this class's meta-data into the recieved child meta-data. + * When a model extends another model, the meta data for the two models + * is merged to form the child's meta data. Returns the merged, child + * meta-data. + */ function extend(ModelMeta $child, $meta) { $this->subclasses[$child->model] = $child; + // Merge 'joins' settings (instead of replacing) + if (isset($this->meta['joins'])) + $meta['joins'] += $this->meta['joins']; return $meta + $this->meta + self::$base; } diff --git a/include/class.queue.php b/include/class.queue.php index 66781c5e00da4348222110f9533cd22d131a96f2..5952d9933668504fa585f773b90566e99680589d 100644 --- a/include/class.queue.php +++ b/include/class.queue.php @@ -23,21 +23,10 @@ class CustomQueue extends SavedSearch { 'columns' => array( 'reverse' => 'QueueColumn.queue', ), - 'staff' => array( - 'constraint' => array( - 'staff_id' => 'Staff.staff_id', - ) - ), - 'parent' => array( - 'constraint' => array( - 'parent_id' => 'CustomQueue.id', - ), - 'null' => true, - ), 'children' => array( 'reverse' => 'CustomQueue.parent', - ) - ), + ), + ) ); static function queues() { @@ -96,21 +85,6 @@ class CustomQueue extends SavedSearch { )); } - function buildPath() { - if (!$this->id) - return; - - $path = $this->parent ? $this->parent->getPath() : ''; - return $path . "/{$this->id}"; - } - - function getFullName() { - $base = $this->getName(); - if ($this->parent) - $base = sprintf("%s / %s", $this->parent->getFullName(), $base); - return $base; - } - function inheritCriteria() { return $this->flags & self::FLAG_INHERIT_CRITERIA; } @@ -171,22 +145,11 @@ class CustomQueue extends SavedSearch { } function update($vars, &$errors=array()) { - // TODO: Move this to SavedSearch::update() and adjust - // AjaxSearch::_saveSearch() - $form = $this->getForm($vars); - if (!$vars || !$form->isValid()) { - $errors['criteria'] = __('Validation errors exist on criteria'); - } - else { - $this->config = JsonDataEncoder::encode( - $this->isolateCriteria($form->getClean())); - } + if (!parent::update($vars, false, $errors)) + return false; // Set basic queue information - $this->title = $vars['name']; - $this->parent_id = $vars['parent_id']; $this->filter = $vars['filter']; - $this->path = $this->buildPath(); $this->setFlag(self::FLAG_INHERIT_CRITERIA, isset($vars['inherit'])); // Update queue columns (but without save) diff --git a/include/class.search.php b/include/class.search.php index dd913b3d31714bc9eec59691c1b59728f1a78c41..93322cc7248b08eabe7b801c01d76383bdfd5757 100644 --- a/include/class.search.php +++ b/include/class.search.php @@ -657,11 +657,23 @@ MysqlSearchBackend::register(); * updated - (date:auto_update) time of last update */ class SavedSearch extends VerySimpleModel { - static $meta = array( 'table' => QUEUE_TABLE, 'pk' => array('id'), 'ordering' => array('sort'), + 'joins' => array( + 'staff' => array( + 'constraint' => array( + 'staff_id' => 'Staff.staff_id', + ) + ), + 'parent' => array( + 'constraint' => array( + 'parent_id' => 'CustomQueue.id', + ), + 'null' => true, + ), + ), ); const FLAG_PUBLIC = 0x0001; // Shows up in e'eryone's saved searches @@ -717,6 +729,14 @@ class SavedSearch extends VerySimpleModel { return $this->criteria ?: array(); } + /** + * Fetch an AdvancedSearchForm instance for use in displaying or + * configuring this search in the user interface. + * + * Parameters: + * $search - <array> Request parameters ($_POST) used to update the + * search beyond the current configuration of the search criteria + */ function getForm($source=null) { $searchable = $this->getCurrentSearchFields($source); $fields = array( @@ -769,6 +789,19 @@ class SavedSearch extends VerySimpleModel { return $form; } + /** + * Fetch a bucket of fields for a custom search. The fields should be + * added to a form before display. One searchable field may encompass 10 + * or more actual fields because fields are expanded to support multiple + * search methods along with the fields for each search method. This + * method returns all the FormField instances for all the searchable + * model fields currently in use. + * + * Parameters: + * $source - <array> data from a request. $source['fields'] is expected + * to contain a list extra fields by ORM path, of newly added + * fields not yet saved in this object's getCriteria(). + */ function getCurrentSearchFields($source=array()) { static $basic = array( 'Ticket' => array( @@ -802,6 +835,12 @@ class SavedSearch extends VerySimpleModel { return $core; } + /** + * Fetch all supported ORM fields searchable by this search object. The + * returned list represents searchable fields, keyed by the ORM path. + * Use ::getCurrentSearchFields() or ::getSearchField() to retrieve for + * use in the user interface. + */ function getSupportedMatches() { return static::getSearchableFields($this->getRoot()); } @@ -867,12 +906,6 @@ class SavedSearch extends VerySimpleModel { } } - // Cache the base fields early so that if recursive calls looks for - // this base model, the base fields can be returned without - // requiring recursion. - if ($cache) - $cache[$base] = $fields; - if ($recurse) { $exclude[$base] = 1; foreach ($base::getMeta('joins') as $path=>$j) { @@ -890,11 +923,20 @@ class SavedSearch extends VerySimpleModel { } } - if ($cache) - $cache[$base] = $fields; return $fields; } + /** + * Fetch the FormField instances used when for configuring a searchable + * field in the user interface. This is the glue between a field + * representing a searchable model field and the configuration of that + * search in the user interface. + * + * Parameters: + * $F - <array<string, FormField>> the label and the FormField instance + * representing the configurable search + * $name - <string> ORM path for the search + */ static function getSearchField($F, $name) { list($label, $field) = $F; @@ -1161,10 +1203,29 @@ class SavedSearch extends VerySimpleModel { && $thisstaff->hasPerm(SearchBackend::PERM_EVERYTHING); } + function buildPath() { + if (!$this->id) + return; + + $path = $this->parent ? $this->parent->getPath() : ''; + return $path . "/{$this->id}"; + } + + function getFullName() { + $base = $this->getName(); + if ($this->parent) + $base = sprintf("%s / %s", $this->parent->getFullName(), $base); + return $base; + } + function isAQueue() { return $this->hasFlag(self::FLAG_QUEUE); } + function isPrivate() { + return !$this->isAQueue() && !$this->hasFlag(self::FLAG_PUBLIC); + } + protected function hasFlag($flag) { return $this->flags & $flag !== 0; } @@ -1190,6 +1251,31 @@ class SavedSearch extends VerySimpleModel { $this->updated = SqlFunction::NOW(); return parent::save($refetch || $this->dirty); } + + function update($vars, $form=false, &$errors=array()) { + // TODO: Move this to SavedSearch::update() and adjust + // AjaxSearch::_saveSearch() + $form = $form ?: $this->getForm($vars); + if (!$vars || !$form->isValid()) { + $errors['criteria'] = __('Validation errors exist on criteria'); + } + else { + $this->config = JsonDataEncoder::encode( + $this->isolateCriteria($form->getClean())); + } + + // Set basic search information + if (!$vars['name']) + $errors['name'] = __('A title is required'); + + $this->title = $vars['name']; + $this->parent_id = @$vars['parent_id'] ?: 0; + $this->path = $this->buildPath(); + // Personal queues _always_ inherit from their parent + $this->setFlag(self::FLAG_INHERIT_CRITERIA, $this->parent_id > 0); + + return count($errors) === 0; + } } class AdhocSearch diff --git a/include/staff/templates/advanced-search.tmpl.php b/include/staff/templates/advanced-search.tmpl.php index 201cb66b0af583203453613a784ad76059bf8ae6..454ef70d100529dfc10a966c5e16fee69a0d2143 100644 --- a/include/staff/templates/advanced-search.tmpl.php +++ b/include/staff/templates/advanced-search.tmpl.php @@ -1,126 +1,60 @@ +<?php +$parent_id = $_REQUEST['parent_id'] ?: $search->parent_id; +if ($parent_id + && (!($queue = CustomQueue::lookup($parent_id))) +) { + $parent_id = null; +} +?> <div id="advanced-search" class="advanced-search"> <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="row"> -<div class="span6"> - <input type="hidden" name="a" value="search"> - <?php include STAFFINC_DIR . 'templates/advanced-search-criteria.tmpl.php'; ?> -</div> -<div class="span6" style="border-left:1px solid #888;position:relative;padding-bottom:26px;"> -<div style="margin-bottom: 0.5em;"><b style="font-size: 110%;"><?php echo __('Saved Searches'); ?></b></div> -<hr> -<div id="saved-searches" class="accordian" style="max-height:200px;overflow-y:auto;"> -<?php foreach (SavedSearch::forStaff($thisstaff) as $S) { ?> - <dt class="saved-search"> - <a href="#" class="load-search"><?php echo $S->title; ?> - <i class="icon-chevron-down pull-right"></i> - </a> - </dt> - <dd> - <span> - <button type="button" onclick="javascript:$(this).closest('form').attr({ -'method': 'get', 'action': '#tickets/search/<?php echo $S->id; ?>'}).trigger('submit');"><i class="icon-chevron-left"></i> <?php echo __('Load'); ?></button> - <button type="button" onclick="javascript: -var that = this; -$.ajax({ - url: 'ajax.php/tickets/search/<?php echo $S->id; ?>', - type: 'POST', - data: {'form': $(this).closest('.dialog').find('form[name=search]').serializeArray()}, - dataType: 'json', - success: function(json) { - if (!json.id) - return; - $(that).closest('dd').effect('highlight'); - } -}); -return false; -"><i class="icon-save"></i> <?php echo __('Update'); ?></button> - </span> - <span class="pull-right"> - <button type="button" title="<?php echo __('Delete'); ?>" onclick="javascript: - if (!confirm(__('You sure?'))) return false; - var that = this; - $.ajax({ - 'url': 'ajax.php/tickets/search/<?php echo $S->id; ?>', - 'type': 'delete', - 'dataType': 'json', - 'success': function(json) { - if (json.success) { - $(that).closest('dd').prev('dt').slideUp().next('dd').slideUp(); - } - } - }); - return false; -"><i class="icon-trash"></i></button> - </span> - </dd> -<?php } ?> -</div> -<div style="position:absolute;bottom:0"> -<hr> - <form method="post"> - <div class="attached input"> - <input name="title" type="text" size="27" placeholder="<?php - echo __('Enter a title for the search'); ?>"/> - <a class="attached button" href="#tickets/search/create" onclick="javascript: -$.ajax({ - url: 'ajax.php/' + $(this).attr('href').substr(1), - type: 'POST', - data: {'name': $(this).closest('form').find('[name=title]').val(), - 'form': $(this).closest('.dialog').find('form[name=search]').serializeArray()}, - dataType: 'json', - success: function(json) { - if (!json.id) - return; - $('<dt>') - .append($('<a>').text(' ' + json.title) - .prepend($('<i>').addClass('icon-chevron-left')) - ).appendTo($('#saved-searches')); - } -}); -return false; -"><i class="icon-save"></i></a> + <div class="flex row"> + <div class="span6"> + <select name="parent_id"> + <option value="0" <?php + if (!$parent_id) echo 'selected="selected"'; + ?>><?php echo '—'.__("My Searches").'—'; ?></option> + <?php foreach (CustomQueue::queues() + ->filter(array('parent_id' => 0)) + as $q) { ?> + <option value="<?php echo $q->id; ?>" + <?php if ($parent_id == $q->id) echo 'selected="selected"'; ?> + ><?php echo $q->getFullName(); ?></option> +<?php } ?> + </select> + </div><div class="span6"> + <input name="name" type="text" size="30" + value="<?php echo Format::htmlchars($search->getName()); ?>" + placeholder="<?php + echo __('Enter a title for the search queue'); ?>"/> + <div class="error"><?php echo Format::htmlchars($errors['name']); ?></div> </div> -</div> -</div> -</div> - -<hr/> -<div> - <div id="search-hint" class="pull-left"> + </div> + <hr/> + <div class="flex row"> + <div class="span12"> + <input type="hidden" name="a" value="search"> + <?php include STAFFINC_DIR . 'templates/advanced-search-criteria.tmpl.php'; ?> </div> + </div> + + <hr/> + <div> <div class="buttons pull-right"> - <button class="button" type="submit" id="do_search"><i class="icon-search"></i> - <?php echo __('Search'); ?></button> + <button class="button" type="submit" name="submit" value="search" + id="do_search"><i class="icon-search"></i> + <?php echo __('Search'); ?></button> + <button class="green button" type="submit" name="submit" value="save" + onclick="javascript: + var form = $(this).closest('form'); + form.attr('action', form.attr('action') + '/' + <?php echo + $search->id ?: "'create'"; ?>);" + ><i class="icon-save"></i> + <?php echo __('Save'); ?> + </button> </div> -</div> - + </div> </form> - -<style type="text/css"> -#advanced-search .span6 .select2 { - max-width: 300px !important; -} -</style> - -<script type="text/javascript"> -$(function() { - $('#advanced-search [data-dropdown]').dropdown(); - - var I = setInterval(function() { - var A = $('#saved-searches.accordian'); - if (!A.length) return; - clearInterval(I); - - var allPanels = $('dd', A).hide(); - $('dt > a', A).click(function() { - $('dt', A).removeClass('active'); - allPanels.slideUp(); - $(this).parent().addClass('active').next().slideDown(); - return false; - }); - }, 200); -}); -</script> diff --git a/include/staff/templates/queue-navigation.tmpl.php b/include/staff/templates/queue-navigation.tmpl.php index 0e78f83301f64c373a2f9a04a88fe05db0edf420..c736e3759862a6783f9ef582eb9d9d0dd0bd4009 100644 --- a/include/staff/templates/queue-navigation.tmpl.php +++ b/include/staff/templates/queue-navigation.tmpl.php @@ -4,30 +4,31 @@ // $q - <CustomQueue> object for this navigation entry // $selected - <bool> true if this queue is currently active // $child_selected - <bool> true if the selected queue is a descendent -$queue = $q; -$selected = $_REQUEST['queue'] == $queue->getId(); +$this_queue = $q; +$selected = $_REQUEST['queue'] == $this_queue->getId(); ?> <li class="item <?php if ($child_selected) echo 'child active'; elseif ($selected) echo 'active'; ?>"> - <a href="<?php echo $queue->getHref(); ?>"><i class="icon-sort-down pull-right"></i><?php echo $queue->getName(); ?></a> + <a href="<?php echo $this_queue->getHref(); ?>"><i class="icon-sort-down pull-right"></i><?php echo $this_queue->getName(); ?></a> <div class="customQ-dropdown"> <ul class="scroll-height"> <!-- Start Dropdown and child queues --> - <?php foreach ($queue->getPublicChildren() as $q) { + <?php foreach ($this_queue->getPublicChildren() as $q) { include 'queue-subnavigation.tmpl.php'; } ?> <!-- Dropdown Titles --> <li> <h4><?php echo __('Personal Queues'); ?></h4> </li> - <?php foreach ($queue->getMyChildren() as $q) { + <?php foreach ($this_queue->getMyChildren() as $q) { include 'queue-subnavigation.tmpl.php'; } ?> </ul> <!-- Add Queue button sticky at the bottom --> <div class="add-queue"> <a class="flush-right full-width" onclick="javascript: - $.dialog('ajax.php/tickets/search', 201);"> + var pid = <?php echo $this_queue->getId() ?: 0; ?>; + $.dialog('ajax.php/tickets/search?parent_id='+pid, 201);"> <div class="add pull-right"><i class="green icon-plus-sign"></i></div> <span><?php echo __('Add personal queue'); ?></span> </a> diff --git a/include/staff/templates/queue-savedsearches-nav.tmpl.php b/include/staff/templates/queue-savedsearches-nav.tmpl.php index 38a367b183da7587392b4d0957e1ae3f5df979b2..d4f5d2f1fafa69dbb8c3e6f063f9241ac42da7f5 100644 --- a/include/staff/templates/queue-savedsearches-nav.tmpl.php +++ b/include/staff/templates/queue-savedsearches-nav.tmpl.php @@ -6,12 +6,13 @@ // $adhoc - not FALSE if an adhoc advanced search exists ?> <li class="item <?php if ($child_selected) echo 'child active'; ?>"> - <a><i class="icon-sort-down pull-right"></i><?php echo __('Search'); + <a href="tickets.php?queue=adhoc"><i class="icon-sort-down pull-right"></i><?php echo __('Search'); ?></a> <div class="customQ-dropdown"> <ul class="scroll-height"> <!-- Start Dropdown and child queues --> <?php foreach ($searches->findAll(array( + 'parent_id' => 0, 'flags__hasbit' => SavedSearch::FLAG_PUBLIC, )) as $q) { include 'queue-subnavigation.tmpl.php'; @@ -22,6 +23,7 @@ </li> <?php foreach ($searches->findAll(array( 'staff_id' => $thisstaff->getId(), + 'parent_id' => 0, Q::not(array( 'flags__hasbit' => SavedSearch::FLAG_PUBLIC )) diff --git a/include/staff/templates/queue-subnavigation.tmpl.php b/include/staff/templates/queue-subnavigation.tmpl.php index 9bd90855f654529795edbc5ab25cd5d4ed658069..29962c02e0878e0ff5d3c4b9cef4b2a83a2f6b74 100644 --- a/include/staff/templates/queue-subnavigation.tmpl.php +++ b/include/staff/templates/queue-subnavigation.tmpl.php @@ -26,7 +26,10 @@ global $thisstaff; </li> <?php } ?> <li> - <a href="queues.php?id=<?php echo $q->getId(); ?>"> + <a href="<?php + echo $queue->isPrivate() + ? sprintf('#" data-dialog="ajax.php/tickets/search/%d', $queue->getId()) + : sprintf('queues.php?id=%d', $queue->getId()); ?>"> <i class="icon-fixed-width icon-pencil"></i> <?php echo __('Edit'); ?></a> </li> diff --git a/scp/ajax.php b/scp/ajax.php index 1351b9fbc58c606076286c55bbc71cd8127be9a9..5bf9f155df950debcaa6e05709ca15393693b840 100644 --- a/scp/ajax.php +++ b/scp/ajax.php @@ -169,8 +169,7 @@ $dispatcher = patterns('', url('^search', patterns('ajax.search.php:SearchAjaxAPI', url_get('^$', 'getAdvancedSearchDialog'), url_post('^$', 'doSearch'), - url_get('^quick$', 'doQuickSearch'), - url_get('^/(?P<id>\d+)$', 'loadSearch'), + url_get('^/(?P<id>\d+)$', 'editSearch'), url_post('^/(?P<id>\d+)$', 'saveSearch'), url_delete('^/(?P<id>\d+)$', 'deleteSearch'), url_post('^/create$', 'createSearch'), diff --git a/scp/css/scp.css b/scp/css/scp.css index bcb53c5b73acae51eb881523722734a8dd40436e..8913828cd911578f6f3d5a67025b4f7e7a14436f 100644 --- a/scp/css/scp.css +++ b/scp/css/scp.css @@ -2266,13 +2266,43 @@ fieldset { .row { display: table-row; + width: 100%; } -.row .span6 { - display: table-cell; - width: 48%; +.row > [class~=" span"], +.row > [class^="span"] { padding: 5px 10px; vertical-align: top; + display: table-cell; +} +.row > [class~=" span"] > select, +.row > [class^="span"] > select, +.row > [class~=" span"] > input, +.row > [class^="span"] > input { + width: 100%; + max-width: 100%; +} +.row .span3 { + width: 23%; + width: calc(25% - 5px); +} +.row .span6 { + width: 48%; + width: calc(50% - 5px); +} +.row .span9 { + width: 73%; + width: calc(75% - 5px); +} +.row .span12 { + width: 100%; +} +.flex.row { + display: initial; +} +.flex.row > [class~=" span"], +.flex.row > [class^="span"] { + display: inline-block; } .search-dropdown {