silverstripe-cms/javascript/ModelAdmin.js
Ingo Schommer 0b7572abd5 MINOR Removed javascript debug call in ModelAdmin.js
ENHANCEMENT Calling tinymce callbacks for destroying previous instances and triggering saves in ModelAdmin.js. No full support for TinyMCE in ModelAdmin yet though.

git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/cms/trunk@79352 467b73ca-7a2a-4603-9d3b-597d59a354a9
2009-06-16 05:54:22 +00:00

407 lines
12 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').livequery('ajaxError', function (XMLHttpRequest, textStatus, errorThrown) {
$('input', this).removeClass('loading');
statusMessage(ss.i18n._t('ModelAdmin.ERROR', 'Error'), 'bad');
});
/**
* Add class ajaxActions class to the parent of Add button of AddForm
* so it float to the right
*/
$('#Form_AddForm_action_doCreate').livequery(function(){
$(this).parent().addClass('ajaxActions');
});
/*
* Highlight buttons on click
*/
$('input[type=submit]').livequery('click', function() {
$(this).addClass('loading');
});
$("#right").scroll( function () {
positionActionArea();
});
$(window).resize( function() {
positionActionArea();
});
/*
* Make the status message and ajax action button fixed
*/
function positionActionArea() {
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 livequery to manage ResultTable click handlers
*/
$('#SearchForm_holder .tab form:not(#Form_ImportForm)').submit(function () {
var $form = $(this);
// @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)')
.livequery('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').livequery('click', function() {
$('#ModelAdminPanel').fn('goBack');
return false;
});
/**
* RHS panel Back button
*/
$('#Form_ResultsForm_action_goForward').livequery('click', function() {
$('#ModelAdminPanel').fn('goForward');
return false;
});
/**
* RHS panel Save button
*/
$('#right input[name=action_doSave],#right input[name=action_doCreate]').livequery('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 livequery a solution?
Behaviour.apply(); // refreshes ComplexTableField
if(window.onresize) window.onresize();
}, 'html');
return false;
});
/**
* RHS panel Delete button
*/
$('#right input[name=action_doDelete]').livequery('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
//////////////////////////////////////////////////////////////////
$('#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();
$('#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();
}
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;
}