mirror of
https://github.com/silverstripe/silverstripe-reports
synced 2024-10-22 09:05:53 +00:00
Updated ModelAdmin.js to use $ instead of jQuery for executing jQuery items.
Added support for specifying a SearchClassSelector() method on ModelAdmin, which returns 'tabs' or 'dropdown', to enable a better UI for ModelAdmins that manage a large number of different classes. Updated ModelAdmin's javascript to provide more status indicator (loading icons, success/failure messages), using HTTP status codes and custom status text. git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/cms/trunk@62334 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
parent
ad6ed7f1a7
commit
dcb9e53ed0
@ -159,6 +159,18 @@ abstract class ModelAdmin extends LeftAndMain {
|
||||
return new $class($this, $model);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method can be overloaded to specify the UI by which the search class is chosen.
|
||||
*
|
||||
* It can create a tab strip or a dropdown. The dropdown is useful when there are a large number of classes.
|
||||
* By default, it will show a tabs for 1-3 classes, and a dropdown for 4 or more classes.
|
||||
*
|
||||
* @return String: 'tabs' or 'dropdown'
|
||||
*/
|
||||
public function SearchClassSelector() {
|
||||
return sizeof($this->getManagedModels()) > 3 ? 'dropdown' : 'tabs';
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to choose which record needs to be created.
|
||||
*
|
||||
@ -427,6 +439,7 @@ class ModelAdmin_CollectionController extends Controller {
|
||||
$model = singleton($this->modelClass);
|
||||
|
||||
$source = $model->summaryFields();
|
||||
$value = array();
|
||||
if($source) foreach ($source as $fieldName => $label){
|
||||
$value[] = $fieldName;
|
||||
}
|
||||
@ -474,8 +487,17 @@ class ModelAdmin_CollectionController extends Controller {
|
||||
* @return string
|
||||
*/
|
||||
function search($request, $form) {
|
||||
// Get the results form to be rendered
|
||||
$resultsForm = $this->ResultsForm($form->getData());
|
||||
return $resultsForm->forTemplate();
|
||||
// Before rendering, let's get the total number of results returned
|
||||
$tableField = $resultsForm->Fields()->fieldByName($this->modelClass);
|
||||
$numResults = $tableField->TotalCount();
|
||||
|
||||
if($numResults) {
|
||||
return new HTTPResponse($resultsForm->forTemplate(), 200, "Your search found $numResults matching items");
|
||||
} else {
|
||||
return new HTTPResponse($resultsForm->forTemplate(), 404, "Your search didn't return any matching items");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -557,7 +579,7 @@ class ModelAdmin_CollectionController extends Controller {
|
||||
* @return unknown
|
||||
*/
|
||||
function add($request) {
|
||||
return $this->AddForm()->forAjaxTemplate();
|
||||
return new HTTPResponse($this->AddForm()->forAjaxTemplate(), 200, "Fill out this form to add a $this->modelClass to the database.");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -626,7 +648,7 @@ class ModelAdmin_RecordController extends Controller {
|
||||
function edit($request) {
|
||||
if ($this->currentRecord) {
|
||||
if(Director::is_ajax()) {
|
||||
return new HTTPResponse($this->EditForm()->forAjaxTemplate(), 200, "Page loaded");
|
||||
return new HTTPResponse($this->EditForm()->forAjaxTemplate(), 200, "Loaded '" . $this->currentRecord->Title . "' for editing.");
|
||||
} else {
|
||||
// This is really quite ugly; to fix will require a change in the way that customise() works. :-(
|
||||
return $this->parentController->parentController->customise(array(
|
||||
|
@ -31,6 +31,12 @@ body.ModelAdmin #SearchForm_holder {
|
||||
margin-bottom:1em;
|
||||
}
|
||||
|
||||
body.ModelAdmin #ModelClassSelector {
|
||||
border-bottom: 1px #AAA solid;
|
||||
padding-bottom: 0.5em;
|
||||
}
|
||||
|
||||
|
||||
body.ModelAdmin #SearchForm_holder div.ResultAssemblyBlock{
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
@ -75,6 +75,11 @@ li.action button {
|
||||
li.action button:hover {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
input.action.loading, input.action.loading:hover {
|
||||
padding-left: 22px;
|
||||
background: url(../images/network-save.gif) 3px 2px no-repeat;
|
||||
}
|
||||
|
||||
input.delete:hover,
|
||||
button.delete:hover,
|
||||
|
@ -8,15 +8,39 @@
|
||||
* @todo add live query to manage application of events to DOM refreshes
|
||||
* @todo alias the $ function instead of literal jQuery
|
||||
*/
|
||||
jQuery(document).ready(function() {
|
||||
(function($) {
|
||||
$(document).ready(function() {
|
||||
/**
|
||||
* Attach tabs plugin to the set of search filter and edit forms
|
||||
*/
|
||||
jQuery('ul.tabstrip').tabs();
|
||||
$('ul.tabstrip').tabs();
|
||||
|
||||
/*
|
||||
* Highlight buttons on click
|
||||
*/
|
||||
$('input[type=submit]').click(function() {
|
||||
$(this).addClass('loading');
|
||||
});
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// Search form
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* If a dropdown is used to choose between the classes, it is handled by this code
|
||||
*/
|
||||
$('#ModelClassSelector select')
|
||||
// Set up an onchange function to show the applicable form and hide all others
|
||||
.change(function() {
|
||||
var $selector = $(this);
|
||||
$('option', this).each(function() {
|
||||
var $form = $('#'+$(this).val());
|
||||
if($selector.val() == $(this).val()) $form.show();
|
||||
else $form.hide();
|
||||
});
|
||||
})
|
||||
// Initialise the form by calling this onchange event straight away
|
||||
.change();
|
||||
|
||||
/**
|
||||
* Stores a jQuery reference to the last submitted search form.
|
||||
@ -29,45 +53,47 @@ jQuery(document).ready(function() {
|
||||
*
|
||||
* @todo use livequery to manage ResultTable click handlers
|
||||
*/
|
||||
jQuery('#SearchForm_holder .tab form').submit(function(){
|
||||
__lastSearch = jQuery(this);
|
||||
|
||||
form = jQuery(this);
|
||||
data = formData(form);
|
||||
jQuery.get(form.attr('action'), data, function(result){
|
||||
jQuery('#right #ModelAdminPanel').html(result);
|
||||
jQuery('#form_actions_right').remove();
|
||||
Behaviour.apply();
|
||||
});
|
||||
|
||||
return false;
|
||||
$('#SearchForm_holder .tab form').submit(function () {
|
||||
var $form = $(this);
|
||||
$('#ModelAdminPanel').load($(this).attr('action'), $(this).formToArray(), standardStatusHandler(function(result) {
|
||||
__lastSearch = $form;
|
||||
$('#form_actions_right').remove();
|
||||
Behaviour.apply();
|
||||
// Remove the loading indicators from the buttons
|
||||
$('input[type=submit]', $form).removeClass('loading');
|
||||
},
|
||||
// Failure handler - we should still remove loading indicator
|
||||
function () {
|
||||
$('input[type=submit]', $form).removeClass('loading');
|
||||
}));
|
||||
return false;
|
||||
});
|
||||
|
||||
/**
|
||||
* Clear search button
|
||||
*/
|
||||
jQuery('#SearchForm_holder button[name=action_clearsearch]').click(function(e) {
|
||||
jQuery(this.form).clearForm();
|
||||
$('#SearchForm_holder button[name=action_clearsearch]').click(function(e) {
|
||||
$(this.form).clearForm();
|
||||
return false;
|
||||
});
|
||||
|
||||
/**
|
||||
* Column selection in search form
|
||||
*/
|
||||
jQuery('a.form_frontend_function.toggle_result_assembly').click(function(){
|
||||
var toggleElement = jQuery(this).next();
|
||||
$('a.form_frontend_function.toggle_result_assembly').click(function(){
|
||||
var toggleElement = $(this).next();
|
||||
toggleElement.toggle();
|
||||
return false;
|
||||
});
|
||||
|
||||
jQuery('a.form_frontend_function.tick_all_result_assembly').click(function(){
|
||||
var resultAssembly = jQuery('div#ResultAssembly ul li input');
|
||||
$('a.form_frontend_function.tick_all_result_assembly').click(function(){
|
||||
var resultAssembly = $('div#ResultAssembly ul li input');
|
||||
resultAssembly.attr('checked', 'checked');
|
||||
return false;
|
||||
});
|
||||
|
||||
jQuery('a.form_frontend_function.untick_all_result_assembly').click(function(){
|
||||
var resultAssembly = jQuery('div#ResultAssembly ul li input');
|
||||
$('a.form_frontend_function.untick_all_result_assembly').click(function(){
|
||||
var resultAssembly = $('div#ResultAssembly ul li input');
|
||||
resultAssembly.removeAttr('checked');
|
||||
return false;
|
||||
});
|
||||
@ -79,18 +105,19 @@ jQuery(document).ready(function() {
|
||||
/**
|
||||
* Table record handler for search result record
|
||||
*/
|
||||
jQuery('#right #Form_ResultsForm tbody td a')
|
||||
$('#right #Form_ResultsForm tbody td a')
|
||||
.livequery('click', function(){
|
||||
var el = jQuery(this);
|
||||
$(this).parent().parent().addClass('loading');
|
||||
var el = $(this);
|
||||
showRecord(el.attr('href'));
|
||||
return false;
|
||||
})
|
||||
.hover(
|
||||
function(){
|
||||
jQuery(this).addClass('over').siblings().addClass('over')
|
||||
$(this).addClass('over').siblings().addClass('over')
|
||||
},
|
||||
function(){
|
||||
jQuery(this).removeClass('over').siblings().removeClass('over')
|
||||
$(this).removeClass('over').siblings().removeClass('over')
|
||||
}
|
||||
);
|
||||
|
||||
@ -101,7 +128,9 @@ jQuery(document).ready(function() {
|
||||
/**
|
||||
* RHS panel Back button
|
||||
*/
|
||||
jQuery('#Form_EditForm_action_goBack').livequery('click', function() {
|
||||
$('#Form_EditForm_action_goBack').livequery('click', function() {
|
||||
$(this).addClass('loading');
|
||||
|
||||
if(__lastSearch) __lastSearch.trigger('submit');
|
||||
return false;
|
||||
});
|
||||
@ -109,20 +138,22 @@ jQuery(document).ready(function() {
|
||||
/**
|
||||
* RHS panel Save button
|
||||
*/
|
||||
jQuery('#right #form_actions_right input[name=action_doSave]').livequery('click', function(){
|
||||
var form = jQuery('#right form');
|
||||
var formAction = form.attr('action') + '?' + jQuery(this).fieldSerialize();
|
||||
$('#right #form_actions_right input[name=action_doSave]').livequery('click', function(){
|
||||
$(this).addClass('loading');
|
||||
|
||||
var form = $('#right form');
|
||||
var formAction = form.attr('action') + '?' + $(this).fieldSerialize();
|
||||
|
||||
// Post the data to save
|
||||
jQuery.post(formAction, formData(form), function(result){
|
||||
jQuery('#right #ModelAdminPanel').html(result);
|
||||
$.post(formAction, formData(form), function(result){
|
||||
$('#right #ModelAdminPanel').html(result);
|
||||
|
||||
statusMessage("Saved");
|
||||
|
||||
// TODO/SAM: It seems a bit of a hack to have to list all the little updaters here.
|
||||
// Is livequery a solution?
|
||||
Behaviour.apply(); // refreshes ComplexTableField
|
||||
jQuery('#right ul.tabstrip').tabs();
|
||||
$('#right ul.tabstrip').tabs();
|
||||
});
|
||||
|
||||
return false;
|
||||
@ -131,24 +162,26 @@ jQuery(document).ready(function() {
|
||||
/**
|
||||
* RHS panel Delete button
|
||||
*/
|
||||
jQuery('#right #form_actions_right input[name=action_doDelete]').livequery('click', function(){
|
||||
$('#right #form_actions_right input[name=action_doDelete]').livequery('click', function(){
|
||||
var confirmed = confirm("Do you really want to delete?");
|
||||
if(!confirmed) return false;
|
||||
|
||||
var form = jQuery('#right form');
|
||||
var formAction = form.attr('action') + '?' + jQuery(this).fieldSerialize();
|
||||
$(this).addClass('loading');
|
||||
var form = $('#right form');
|
||||
var formAction = form.attr('action') + '?' + $(this).fieldSerialize();
|
||||
|
||||
// The POST actually handles the delete
|
||||
jQuery.post(formAction, formData(form), function(result){
|
||||
$.post(formAction, formData(form), function(result){
|
||||
// On success, the panel is refreshed and a status message shown.
|
||||
jQuery('#right #ModelAdminPanel').html(result);
|
||||
$('#right #ModelAdminPanel').html(result);
|
||||
|
||||
statusMessage("Deleted");
|
||||
$('#form_actions_right').remove();
|
||||
|
||||
// TODO/SAM: It seems a bit of a hack to have to list all the little updaters here.
|
||||
// Is livequery a solution?
|
||||
Behaviour.apply(); // refreshes ComplexTableField
|
||||
jQuery('#right ul.tabstrip').tabs();
|
||||
$('#right ul.tabstrip').tabs();
|
||||
});
|
||||
|
||||
return false;
|
||||
@ -162,9 +195,9 @@ jQuery(document).ready(function() {
|
||||
/**
|
||||
* Add object button
|
||||
*/
|
||||
jQuery('#Form_ManagedModelsSelect').submit(function(){
|
||||
className = jQuery('select option:selected', this).val();
|
||||
requestPath = jQuery(this).attr('action').replace('ManagedModelsSelect', className + '/add');
|
||||
$('#Form_ManagedModelsSelect').submit(function(){
|
||||
className = $('select option:selected', this).val();
|
||||
requestPath = $(this).attr('action').replace('ManagedModelsSelect', className + '/add');
|
||||
showRecord(requestPath);
|
||||
return false;
|
||||
});
|
||||
@ -172,9 +205,9 @@ jQuery(document).ready(function() {
|
||||
/**
|
||||
* Toggle import specifications
|
||||
*/
|
||||
jQuery('#Form_ImportForm_holder .spec .details').hide();
|
||||
jQuery('#Form_ImportForm_holder .spec a.detailsLink').click(function() {
|
||||
jQuery('#' + jQuery(this).attr('href').replace(/.*#/,'')).toggle();
|
||||
$('#Form_ImportForm_holder .spec .details').hide();
|
||||
$('#Form_ImportForm_holder .spec a.detailsLink').click(function() {
|
||||
$('#' + $(this).attr('href').replace(/.*#/,'')).toggle();
|
||||
return false;
|
||||
});
|
||||
|
||||
@ -187,10 +220,10 @@ jQuery(document).ready(function() {
|
||||
* @todo Should this be turned into a method on the #Form_EditForm using effen or something?
|
||||
*/
|
||||
function showRecord(uri) {
|
||||
jQuery('#right #ModelAdminPanel').load(uri, standardStatusHandler(function(result) {
|
||||
jQuery('#SearchForm_holder').tabs();
|
||||
$('#right #ModelAdminPanel').load(uri, standardStatusHandler(function(result) {
|
||||
$('#SearchForm_holder').tabs();
|
||||
Behaviour.apply(); // refreshes ComplexTableField
|
||||
jQuery('#right ul.tabstrip').tabs();
|
||||
$('#right ul.tabstrip').tabs();
|
||||
}));
|
||||
}
|
||||
|
||||
@ -200,8 +233,8 @@ jQuery(document).ready(function() {
|
||||
*/
|
||||
function formData(scope) {
|
||||
var data = {};
|
||||
jQuery('*[name]', scope).each(function(){
|
||||
var t = jQuery(this);
|
||||
$('*[name]', scope).each(function(){
|
||||
var t = $(this);
|
||||
if(t.attr('type') != 'checkbox' || t.attr('checked') == true) {
|
||||
data[t.attr('name')] = t.val();
|
||||
}
|
||||
@ -220,18 +253,26 @@ jQuery(document).ready(function() {
|
||||
* Pass it as this:
|
||||
* standardStatusHandler(function(response) { ... })
|
||||
*/
|
||||
function standardStatusHandler(callback) {
|
||||
function standardStatusHandler(callback, failureCallback) {
|
||||
return function(response, status, xhr) {
|
||||
// If the response is takne from $.ajax's complete handler, then swap the variables around
|
||||
if(response.status) {
|
||||
xhr = response;
|
||||
response = xhr.responseText;
|
||||
}
|
||||
|
||||
if(status == 'success') {
|
||||
statusMessage(xhr.statusText, "good");
|
||||
callback(response, status, xhr);
|
||||
$(this).each(callback, [response, status, xhr]);
|
||||
} else {
|
||||
statusMessage(xhr.statusText, "bad");
|
||||
if(failureCallback) $(this).each(failureCallback, [response, status, xhr]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
})
|
||||
})(jQuery);
|
||||
|
||||
/**
|
||||
* @todo Terrible HACK, but thats the cms UI...
|
||||
|
@ -1,15 +1,29 @@
|
||||
<div id="LeftPane">
|
||||
<h2><% _t('SEARCHLISTINGS','Search Listings') %></h2>
|
||||
<div id="SearchForm_holder" class="leftbottom">
|
||||
<% if SearchClassSelector = tabs %>
|
||||
<ul class="tabstrip">
|
||||
<% control SearchForms %>
|
||||
<li class="first"><a href="#{$Form.Name}_$ClassName">$Title</a></li>
|
||||
<li class="$FirstLast"><a href="#{$Form.Name}_$ClassName">$Title</a></li>
|
||||
<% end_control %>
|
||||
</ul>
|
||||
<% end_if %>
|
||||
|
||||
<% if SearchClassSelector = dropdown %>
|
||||
<p id="ModelClassSelector">
|
||||
Search for:
|
||||
<select>
|
||||
<% control SearchForms %>
|
||||
<option value="{$Form.Name}_$ClassName">$Title</option>
|
||||
<% end_control %>
|
||||
</select>
|
||||
</p>
|
||||
<% end_if %>
|
||||
|
||||
<% control SearchForms %>
|
||||
<div class="tab" id="{$Form.Name}_$ClassName">
|
||||
$Form
|
||||
</div>
|
||||
<div class="tab" id="{$Form.Name}_$ClassName">
|
||||
$Form
|
||||
</div>
|
||||
<% end_control %>
|
||||
</div>
|
||||
<h2><% _t('ADDLISTING','Add Listing') %></h2>
|
||||
|
Loading…
x
Reference in New Issue
Block a user