mirror of
https://github.com/silverstripe/silverstripe-cms
synced 2024-10-22 08:05:56 +02:00
1b6741e08d
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/cms/branches/2.4@105505 467b73ca-7a2a-4603-9d3b-597d59a354a9
475 lines
14 KiB
JavaScript
475 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;
|
|
} |