mirror of
https://github.com/silverstripe/silverstripe-cms
synced 2024-10-22 06:05:56 +00:00
4ec85a412f
The 'Back', 'Delete' and 'Save' buttons on the Admin panel don't appear if you go straight into a DataObject item, You needed to click 'Search' first, this added an extra item to the history array, have changed the condition for the number of items in this array before the buttons appear, now only 1 item needs to be in the Array
476 lines
14 KiB
JavaScript
476 lines
14 KiB
JavaScript
/**
|
|
* Javascript handlers for generic model admin.
|
|
*
|
|
* Most of the work being done here is intercepting clicks on form submits,
|
|
* and managing the loading and sequencing of data between the different panels of
|
|
* the CMS interface.
|
|
*
|
|
* @todo add live query to manage application of events to DOM refreshes
|
|
* @todo alias the $ function instead of literal jQuery
|
|
*/
|
|
(function($) {
|
|
$(document).ready(function() {
|
|
/**
|
|
* Generic ajax error handler
|
|
*/
|
|
$('form').live('ajaxError', function (XMLHttpRequest, textStatus, errorThrown) {
|
|
$('input', this).removeClass('loading');
|
|
statusMessage(ss.i18n._t('ModelAdmin.ERROR', 'Error'), 'bad');
|
|
});
|
|
|
|
// We're avoiding livequery initializers for now,
|
|
// to be replaced by jQuery.entwine.
|
|
Behaviour.register({
|
|
/**
|
|
* Add class ajaxActions class to the parent of Add button of AddForm
|
|
* so it float to the right
|
|
*/
|
|
'#Form_AddForm_action_doCreate': {
|
|
initialize: function() {
|
|
var parent = $(this).parent();
|
|
$("#right").append(parent);
|
|
|
|
parent.addClass('ajaxActions');
|
|
parent.attr('id','form_actions_right');
|
|
}
|
|
},
|
|
/*
|
|
* moves Forward button to the right and fixes it underneath result form.
|
|
*/
|
|
'#Form_ResultsForm_action_goForward': {
|
|
initialize: function() {
|
|
$("#form_actions_right").append($(this));
|
|
}
|
|
},
|
|
/*
|
|
* we need an special case for results form since #ModelAdminPanel has overflow:hidden
|
|
* it calculates the form height, gives it a padding and overflow auto, so we can scroll down.
|
|
*/
|
|
'#Form_ResultsForm': {
|
|
initialize: function(){
|
|
var newModelAdminPanelHeight = $("#right").height()-$(".ajaxActions").height();
|
|
$('#Form_ResultsForm').height(newModelAdminPanelHeight);
|
|
$('#Form_ResultsForm').css('overflow','auto');
|
|
}
|
|
}
|
|
});
|
|
|
|
/*
|
|
* Highlight buttons on click
|
|
*/
|
|
$('#form_actions_right input[type=submit], #left input[type=submit]').live('click', function() {
|
|
$(this).addClass('loading');
|
|
});
|
|
|
|
|
|
$('input[name=action_search]').live('click', function() {
|
|
$('#contentPanel').fn('closeRightPanel');
|
|
if($('#Form_AddForm_action_doCreate')){
|
|
$('div[class=ajaxActions]').remove();
|
|
}
|
|
});
|
|
|
|
$("#right").scroll( function () {
|
|
positionActionArea();
|
|
});
|
|
|
|
$(window).resize( function() {
|
|
positionActionArea();
|
|
});
|
|
|
|
|
|
/*
|
|
* Make the status message and ajax action button fixed
|
|
*/
|
|
function positionActionArea() {
|
|
var newModelAdminPanelHeight = $("#right").height()-$(".ajaxActions").height();
|
|
$('#ModelAdminPanel').height(newModelAdminPanelHeight);
|
|
$('#Form_ResultsForm').height(newModelAdminPanelHeight);
|
|
$('#ModelAdminPanel').css('padding-bottom','60px');
|
|
/*
|
|
if ( $.browser.msie && $.browser.version.indexOf("6.", 0)==0 ) {
|
|
newTopValue = $("#right").scrollTop()+$(window).height()-139;
|
|
$('.ajaxActions').css('top', newTopValue);
|
|
$('#statusMessage').css('top', newTopValue);
|
|
}
|
|
*/
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
// 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.
|
|
*/
|
|
__lastSearch = null;
|
|
|
|
/**
|
|
* Submits a search filter query and attaches event handlers
|
|
* to the response table, excluding the import form because
|
|
* file ($_FILES) submission doesn't work using AJAX
|
|
*
|
|
* Note: This is used for Form_CreateForm too
|
|
*
|
|
* @todo use jQuery.live to manage ResultTable click handlers
|
|
*/
|
|
$('#SearchForm_holder .tab form:not([id^=Form_ImportForm])').submit(function () {
|
|
var $form = $(this);
|
|
$('#contentPanel').fn('closeRightPanel');
|
|
// @todo TinyMCE coupling
|
|
tinymce_removeAll();
|
|
|
|
$('#ModelAdminPanel').fn('startHistory', $(this).attr('action'), $(this).formToArray());
|
|
$('#ModelAdminPanel').load($(this).attr('action'), $(this).formToArray(), standardStatusHandler(function(result) {
|
|
if(!this.future || !this.future.length) {
|
|
$('#Form_EditForm_action_goForward, #Form_ResultsForm_action_goForward').hide();
|
|
}
|
|
if(!this.history || this.history.length <= 1) {
|
|
$('#Form_EditForm_action_goBack, #Form_ResultsForm_action_goBack').hide();
|
|
}
|
|
|
|
$('#form_actions_right').remove();
|
|
Behaviour.apply();
|
|
|
|
if(window.onresize) window.onresize();
|
|
// 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
|
|
*/
|
|
$('#SearchForm_holder button[name=action_clearsearch]').click(function(e) {
|
|
$(this.form).resetForm();
|
|
return false;
|
|
});
|
|
|
|
/**
|
|
* Column selection in search form
|
|
*/
|
|
$('a.form_frontend_function.toggle_result_assembly').click(function(){
|
|
var toggleElement = $(this).next();
|
|
toggleElement.toggle();
|
|
return false;
|
|
});
|
|
|
|
$('a.form_frontend_function.tick_all_result_assembly').click(function(){
|
|
var resultAssembly = $(this).prevAll('div#ResultAssembly').find('ul li input');
|
|
resultAssembly.attr('checked', 'checked');
|
|
return false;
|
|
});
|
|
|
|
$('a.form_frontend_function.untick_all_result_assembly').click(function(){
|
|
var resultAssembly = $(this).prevAll('div#ResultAssembly').find('ul li input');
|
|
resultAssembly.removeAttr('checked');
|
|
return false;
|
|
});
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
// Results list
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
* Table record handler for search result record
|
|
* @todo: Shouldn't this be part of TableListField?
|
|
*/
|
|
$('#right #Form_ResultsForm tbody td a:not(.deletelink,.downloadlink)')
|
|
.live('click', function(){
|
|
$(this).parent().parent().addClass('loading');
|
|
var el = $(this);
|
|
$('#ModelAdminPanel').fn('addHistory', el.attr('href'));
|
|
$('#ModelAdminPanel').fn('loadForm', el.attr('href'));
|
|
return false;
|
|
});
|
|
/* this isn't being used currently; the real hover code is part of TableListField
|
|
.hover(
|
|
function(){
|
|
$(this).addClass('over').siblings().addClass('over')
|
|
},
|
|
function(){
|
|
$(this).removeClass('over').siblings().removeClass('over')
|
|
}
|
|
);
|
|
*/
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
// RHS detail form
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
* RHS panel Back button
|
|
*/
|
|
$('#Form_EditForm_action_goBack, #Form_ResultsForm_action_goBack').live('click', function() {
|
|
$('#ModelAdminPanel').fn('goBack');
|
|
return false;
|
|
});
|
|
|
|
/**
|
|
* RHS panel Back button
|
|
*/
|
|
$('#Form_ResultsForm_action_goForward').live('click', function() {
|
|
$('#ModelAdminPanel').fn('goForward');
|
|
return false;
|
|
});
|
|
|
|
/**
|
|
* RHS panel Save button
|
|
*/
|
|
$('#right input[name=action_doSave],#right input[name=action_doCreate]').live('click', function(){
|
|
var form = $('#right form');
|
|
var formAction = form.attr('action') + '?' + $(this).fieldSerialize();
|
|
|
|
// @todo TinyMCE coupling
|
|
if(typeof tinyMCE != 'undefined') tinyMCE.triggerSave();
|
|
|
|
// Post the data to save
|
|
$.post(formAction, form.formToArray(), function(result){
|
|
// @todo TinyMCE coupling
|
|
tinymce_removeAll();
|
|
|
|
$('#right #ModelAdminPanel').html(result);
|
|
|
|
if($('#right #ModelAdminPanel form').hasClass('validationerror')) {
|
|
statusMessage(ss.i18n._t('ModelAdmin.VALIDATIONERROR', 'Validation Error'), 'bad');
|
|
} else {
|
|
statusMessage(ss.i18n._t('ModelAdmin.SAVED', 'Saved'), 'good');
|
|
}
|
|
|
|
// TODO/SAM: It seems a bit of a hack to have to list all the little updaters here.
|
|
// Is jQuery.live a solution?
|
|
Behaviour.apply(); // refreshes ComplexTableField
|
|
if(window.onresize) window.onresize();
|
|
}, 'html');
|
|
|
|
return false;
|
|
});
|
|
|
|
/**
|
|
* RHS panel Delete button
|
|
*/
|
|
$('#right input[name=action_doDelete]').live('click', function(){
|
|
var confirmed = confirm(ss.i18n._t('ModelAdmin.REALLYDELETE', 'Really delete?'));
|
|
if(!confirmed) {
|
|
$(this).removeClass('loading')
|
|
return false;
|
|
}
|
|
|
|
var form = $('#right form');
|
|
var formAction = form.attr('action') + '?' + $(this).fieldSerialize();
|
|
|
|
// The POST actually handles the delete
|
|
$.post(formAction, form.formToArray(), function(result){
|
|
// On success, the panel is refreshed and a status message shown.
|
|
$('#right #ModelAdminPanel').html(result);
|
|
|
|
statusMessage(ss.i18n._t('ModelAdmin.DELETED', 'Successfully deleted'));
|
|
$('#form_actions_right').remove();
|
|
|
|
// To do - convert everything to jQuery so that this isn't needed
|
|
Behaviour.apply(); // refreshes ComplexTableField
|
|
});
|
|
|
|
return false;
|
|
});
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
// Import/Add form
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
* Add object button
|
|
*/
|
|
$('#Form_ManagedModelsSelect').submit(function(){
|
|
className = $('select option:selected', this).val();
|
|
requestPath = $(this).attr('action').replace('ManagedModelsSelect', className + '/add');
|
|
var $button = $(':submit', this);
|
|
$('#ModelAdminPanel').fn(
|
|
'loadForm',
|
|
requestPath,
|
|
function() {
|
|
$button.removeClass('loading');
|
|
$button = null;
|
|
}
|
|
);
|
|
$('#form_actions_right').remove();
|
|
return false;
|
|
});
|
|
|
|
/**
|
|
* Toggle import specifications
|
|
*/
|
|
$('.importSpec .details').hide();
|
|
$('.importSpec a.detailsLink').click(function() {
|
|
$('#' + $(this).attr('href').replace(/.*#/,'')).toggle();
|
|
return false;
|
|
});
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
// Helper functions
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
$('#contentPanel').fn({
|
|
/**
|
|
* Close TinyMCE image, link or flash panel.
|
|
* this function is called everytime a new search, back or add new DataObject are clicked
|
|
**/
|
|
closeRightPanel: function(){
|
|
if($('#contentPanel').is(':visible')) {
|
|
$('#contentPanel').hide();
|
|
$('#Form_EditorToolbarImageForm').hide();
|
|
$('#Form_EditorToolbarFlashForm').hide();
|
|
$('#Form_EditorToolbarLinkForm').hide();
|
|
}
|
|
}
|
|
|
|
})
|
|
|
|
$('#ModelAdminPanel').fn({
|
|
/**
|
|
* Load a detail editing form into the main edit panel
|
|
* @todo Convert everything to jQuery so that the built-in load method can be used with this instead
|
|
*/
|
|
loadForm: function(url, successCallback) {
|
|
// @todo TinyMCE coupling
|
|
tinymce_removeAll();
|
|
$('#contentPanel').fn('closeRightPanel');
|
|
$('#right #ModelAdminPanel').load(url, standardStatusHandler(function(result) {
|
|
if(typeof(successCallback) == 'function') successCallback.apply();
|
|
if(!this.future || !this.future.length) {
|
|
$('#Form_EditForm_action_goForward, #Form_ResultsForm_action_goForward').hide();
|
|
}
|
|
if(!this.history || this.history.length < 1) {
|
|
$('#Form_EditForm_action_goBack, #Form_ResultsForm_action_goBack').hide();
|
|
|
|
// we don't need save and delete button on result form
|
|
$('#Form_EditForm_action_doSave').hide();
|
|
$('#Form_EditForm_action_doDelete').hide();
|
|
}
|
|
|
|
Behaviour.apply(); // refreshes ComplexTableField
|
|
if(window.onresize) window.onresize();
|
|
}));
|
|
},
|
|
|
|
|
|
|
|
startHistory: function(url, data) {
|
|
this.history = [];
|
|
$(this).fn('addHistory', url, data);
|
|
},
|
|
|
|
/**
|
|
* Add an item to the history, to be accessed by goBack and goForward
|
|
*/
|
|
addHistory: function(url, data) {
|
|
// Combine data into URL
|
|
if(data) {
|
|
if(url.indexOf('?') == -1) url += '?' + $.param(data);
|
|
else url += '&' + $.param(data);
|
|
}
|
|
|
|
// Add to history
|
|
if(this.history == null) this.history = [];
|
|
this.history.push(url);
|
|
|
|
// Reset future
|
|
this.future = [];
|
|
},
|
|
|
|
goBack: function() {
|
|
if(this.history && this.history.length) {
|
|
if(this.future == null) this.future = [];
|
|
|
|
var currentPage = this.history.pop();
|
|
var previousPage = this.history[this.history.length-1];
|
|
|
|
this.future.push(currentPage);
|
|
$(this).fn('loadForm', previousPage);
|
|
}
|
|
},
|
|
|
|
goForward: function() {
|
|
if(this.future && this.future.length) {
|
|
if(this.future == null) this.future = [];
|
|
|
|
var nextPage = this.future.pop();
|
|
|
|
this.history.push(nextPage);
|
|
$(this).fn('loadForm', nextPage);
|
|
}
|
|
}
|
|
|
|
});
|
|
|
|
/**
|
|
* Standard SilverStripe status handler for ajax responses
|
|
* It will generate a status message out of the response, and only call the callback for successful responses
|
|
*
|
|
* To use:
|
|
* Instead of passing your callback function as:
|
|
* function(response) { ... }
|
|
*
|
|
* Pass it as this:
|
|
* standardStatusHandler(function(response) { ... })
|
|
*/
|
|
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");
|
|
$(this).each(callback, [response, status, xhr]);
|
|
} else {
|
|
errorMessage(xhr.statusText);
|
|
if(failureCallback) $(this).each(failureCallback, [response, status, xhr]);
|
|
}
|
|
}
|
|
}
|
|
|
|
})
|
|
})(jQuery);
|
|
|
|
/**
|
|
* @todo Terrible HACK, but thats the cms UI...
|
|
*/
|
|
function fixHeight_left() {
|
|
//fitToParent('LeftPane');
|
|
fitToParent('Search_holder',12);
|
|
fitToParent('ResultTable_holder',12);
|
|
}
|
|
|
|
function prepareAjaxActions(actions, formName, tabName) {
|
|
// @todo HACK Overwrites LeftAndMain.js version of this method to avoid double form actions
|
|
// (by new jQuery and legacy prototype)
|
|
return false;
|
|
}
|