mirror of
https://github.com/silverstripe/silverstripe-cms
synced 2024-10-22 08:05:56 +02:00
ENHANCEMENT Initial 'concrete' implementation of CMS forms incl. ajax saving, validation placeholders and session-pinging
MINOR Removed 'innerLayout' from CMSMain.js javascript git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/cms/trunk@92599 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
parent
1b312ae81b
commit
df7713f894
@ -1,66 +1,68 @@
|
||||
var outerLayout;
|
||||
var innerLayout;
|
||||
|
||||
jQuery(document).ready(function () {
|
||||
|
||||
// layout containing the tree, CMS menu, the main form etc.
|
||||
outerLayout = jQuery('body').layout({
|
||||
defaults: {
|
||||
// TODO Reactivate once we have localized values
|
||||
togglerTip_open: '',
|
||||
togglerTip_closed: '',
|
||||
resizerTip: '',
|
||||
sliderTip: ''
|
||||
(function($) {
|
||||
$('body.CMSMain').concrete({ss:{cmsMain:{
|
||||
mainLayout: null,
|
||||
|
||||
onmatch: function() {
|
||||
this.mainLayout = this.ss().cmsMain()._setupLayout();
|
||||
},
|
||||
// contains CMSMenu
|
||||
north: {
|
||||
slidable: false,
|
||||
resizable: false,
|
||||
size: 35,
|
||||
togglerLength_open: 0
|
||||
},
|
||||
// "Page view", "profile" and "logout" links
|
||||
south: {
|
||||
slidable: false,
|
||||
resizable: false,
|
||||
size: 20,
|
||||
togglerLength_open: 0
|
||||
},
|
||||
// "Insert link" etc.
|
||||
east: {
|
||||
initClosed: true,
|
||||
fxName: "none"
|
||||
},
|
||||
// Tree, page version history
|
||||
west: {
|
||||
size: 250,
|
||||
onresize: function () { jQuery("#treepanes").accordion("resize"); },
|
||||
onopen: function () { jQuery("#treepanes").accordion("resize"); },
|
||||
fxName: "none"
|
||||
},
|
||||
// Page forms
|
||||
center: {
|
||||
onresize: "innerLayout.resizeAll"
|
||||
|
||||
/**
|
||||
* Initialize jQuery layout manager with the following panes:
|
||||
* - east: Tree, Page Version History, Site Reports
|
||||
* - center: Form
|
||||
* - west: "Insert Image", "Insert Link", "Insert Flash" panes
|
||||
* - north: CMS area menu bar
|
||||
* - south: "Page view", "profile" and "logout" links
|
||||
*/
|
||||
_setupLayout: function() {
|
||||
// layout containing the tree, CMS menu, the main form etc.
|
||||
var layout = $('body').layout({
|
||||
defaults: {
|
||||
// TODO Reactivate once we have localized values
|
||||
togglerTip_open: '',
|
||||
togglerTip_closed: '',
|
||||
resizerTip: '',
|
||||
sliderTip: ''
|
||||
},
|
||||
north: {
|
||||
slidable: false,
|
||||
resizable: false,
|
||||
size: 35,
|
||||
togglerLength_open: 0
|
||||
},
|
||||
south: {
|
||||
slidable: false,
|
||||
resizable: false,
|
||||
size: 20,
|
||||
togglerLength_open: 0
|
||||
},
|
||||
east: {
|
||||
initClosed: true,
|
||||
fxName: "none"
|
||||
},
|
||||
west: {
|
||||
size: 250,
|
||||
onresize: function () { $("#treepanes").accordion("resize"); },
|
||||
onopen: function () { $("#treepanes").accordion("resize"); },
|
||||
fxName: "none"
|
||||
},
|
||||
center: {}
|
||||
});
|
||||
|
||||
// Adjust tree accordion etc. in left panel to work correctly
|
||||
// with jQuery.layout (see http://layout.jquery-dev.net/tips.html#Widget_Accordion)
|
||||
this.find("#treepanes").accordion({
|
||||
fillSpace: true,
|
||||
animated: false
|
||||
});
|
||||
|
||||
return layout;
|
||||
}
|
||||
});
|
||||
}}});
|
||||
|
||||
// Layout for the form and its buttons
|
||||
innerLayout = jQuery('#right').layout({
|
||||
center: {},
|
||||
south: {
|
||||
slidable: false,
|
||||
resizable: false,
|
||||
size: 30,
|
||||
togglerLength_open: 0
|
||||
}
|
||||
$('#Form_EditForm').concrete({
|
||||
|
||||
})
|
||||
|
||||
// Adjust tree accordion etc. in left panel to work correctly
|
||||
// with jQuery.layout (see http://layout.jquery-dev.net/tips.html#Widget_Accordion)
|
||||
jQuery("#treepanes").accordion({
|
||||
fillSpace: true,
|
||||
animated: false
|
||||
});
|
||||
|
||||
});
|
||||
})(jQuery);
|
@ -1,3 +1,225 @@
|
||||
(function($) {
|
||||
|
||||
/**
|
||||
* Main LeftAndMain interface with some control
|
||||
* panel and an edit form.
|
||||
*
|
||||
* Events:
|
||||
* - beforeSave
|
||||
* - afterSave
|
||||
* - beforeValidate
|
||||
* - afterValidate
|
||||
*/
|
||||
$('.LeftAndMain').concrete({ss:{leftAndMain:{
|
||||
onmatch: function() {
|
||||
this.ss().leftAndMain()._setupPinging();
|
||||
this.ss().leftAndMain()._setupButtons();
|
||||
},
|
||||
|
||||
_setupPinging: function() {
|
||||
var pingIntervalSeconds = 5*60;
|
||||
|
||||
// setup pinging for login expiry
|
||||
setInterval(function() {
|
||||
$.get("Security/ping");
|
||||
}, pingIntervalSeconds * 1000);
|
||||
},
|
||||
|
||||
/**
|
||||
* Make all buttons "hoverable" with jQuery theming.
|
||||
*/
|
||||
_setupButtons: function() {
|
||||
// Initialize buttons
|
||||
this.find(':submit, button').livequery(function() {
|
||||
jQuery(this).addClass(
|
||||
'ui-state-default ' +
|
||||
'ui-corner-all'
|
||||
)
|
||||
.hover(
|
||||
function() {
|
||||
$(this).addClass('ui-state-hover');
|
||||
},
|
||||
function() {
|
||||
$(this).removeClass('ui-state-hover');
|
||||
}
|
||||
)
|
||||
.focus(function() {
|
||||
$(this).addClass('ui-state-focus');
|
||||
})
|
||||
.blur(function() {
|
||||
$(this).removeClass('ui-state-focus');
|
||||
});
|
||||
});
|
||||
}
|
||||
}}});
|
||||
|
||||
/**
|
||||
* Base edit form, provides ajaxified saving
|
||||
* and reloading itself through the ajax return values.
|
||||
* Takes care of resizing tabsets within the layout container.
|
||||
*/
|
||||
$('#Form_EditForm').concrete({ss:{
|
||||
onmatch: function() {
|
||||
var $this = this;
|
||||
// artificially delay the resize event 200ms
|
||||
// to avoid overlapping height changes in different onresize() methods
|
||||
$(window).resize(function () {
|
||||
var timerID = "timerLayout_"+this.id;
|
||||
if (window[timerID]) clearTimeout(window[timerID]);
|
||||
window[timerID] = setTimeout(function() {$this.ss()._resizeChildren();}, 200);
|
||||
}).trigger('resize');
|
||||
|
||||
// trigger resize whenever new tabs are shown
|
||||
// @todo This is called multiple times when tabs are loaded
|
||||
this.find('.ss-tabset').bind('tabsshow', function() {$this.ss()._resizeChildren();});
|
||||
},
|
||||
|
||||
/**
|
||||
* Suppress submission unless it is handled through save()
|
||||
*/
|
||||
onsubmit: function(e) {
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param DOMElement button The pressed button (optiona)
|
||||
*/
|
||||
ajaxSubmit: function(button) {
|
||||
// default to first button if none given - simulates browser behaviour
|
||||
if(!button) button = this.find(':submit:first');
|
||||
|
||||
var $form = this;
|
||||
|
||||
this.trigger('beforeSubmit', [button]);
|
||||
|
||||
// set button to "submitting" state
|
||||
$(button).addClass('loading');
|
||||
|
||||
// @todo TinyMCE coupling
|
||||
if(typeof tinyMCE != 'undefined') tinyMCE.triggerSave();
|
||||
|
||||
// validate if required
|
||||
if(!this.ss().validate()) {
|
||||
this.trigger('validationError', [button]);
|
||||
|
||||
// TODO Automatically switch to the tab/position of the first error
|
||||
statusMessage("Validation failed.", "bad");
|
||||
|
||||
if($('Form_EditForm_action_save') && $('Form_EditForm_action_save').stopLoading) $('Form_EditForm_action_save').stopLoading();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// get all data from the form
|
||||
var data = this.serializeArray();
|
||||
// add button action
|
||||
data.push({name: $(button).attr('name'), value:'1'});
|
||||
$.post(
|
||||
this.attr('action'),
|
||||
data,
|
||||
function(result) {
|
||||
$(button).removeClass('loading');
|
||||
|
||||
$form.trigger('afterSubmit', [result]);
|
||||
|
||||
$form.ss().loadNewPage();
|
||||
},
|
||||
// @todo Currently all responses are assumed to be evaluated
|
||||
'script'
|
||||
);
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Hook in (optional) validation routines.
|
||||
* Currently clientside validation is not supported out of the box in the CMS.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
validate: function() {
|
||||
this.trigger('beforeValidate');
|
||||
var isValid = true;
|
||||
this.trigger('afterValidate', [isValid]);
|
||||
|
||||
return isValid;
|
||||
},
|
||||
|
||||
loadNewPage: function(result) {
|
||||
// TinyMCE coupling
|
||||
if(typeof tinymce_removeAll != 'undefined') tinymce_removeAll();
|
||||
|
||||
// Rewrite # links
|
||||
result = result.replace(/(<a[^>]+href *= *")#/g, '$1' + window.location.href.replace(/#.*$/,'') + '#');
|
||||
|
||||
// Rewrite iframe links (for IE)
|
||||
result = result.replace(/(<iframe[^>]*src=")([^"]+)("[^>]*>)/g, '$1' + $('base').attr('href') + '$2$3');
|
||||
|
||||
// Prepare iframes for removal, otherwise we get loading bugs
|
||||
this.find('iframe').each(function() {
|
||||
this.contentWindow.location.href = 'about:blank';
|
||||
this.remove();
|
||||
})
|
||||
|
||||
this.html(result);
|
||||
|
||||
if(this.hasClass('validationerror')) {
|
||||
statusMessage(ss.i18n._t('ModelAdmin.VALIDATIONERROR', 'Validation Error'), 'bad');
|
||||
} else {
|
||||
statusMessage(ss.i18n._t('ModelAdmin.SAVED', 'Saved'), 'good');
|
||||
}
|
||||
|
||||
Behaviour.apply(); // refreshes ComplexTableField
|
||||
|
||||
// If there's a title field and it's got a "new XX" value, focus/select that first
|
||||
// This is really a little too CMS-specific (as opposed to LeftAndMain), but the cleanup can happen after jQuery refactoring
|
||||
if($('input#Form_EditForm_Title') && $('input#Form_EditForm_Title').value.match(/^new/i)) {
|
||||
$('input#Form_EditForm_Title').select();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Resize elements in center panel
|
||||
* to fit the boundary box provided by the layout manager
|
||||
*/
|
||||
_resizeChildren: function() {
|
||||
this.fitHeightToParent();
|
||||
$('fieldset', this).fitHeightToParent();
|
||||
// Order of resizing is important: Outer to inner
|
||||
// TODO Only supports two levels of tabs at the moment
|
||||
$('fieldset > .ss-tabset', this).fitHeightToParent();
|
||||
$('fieldset > .ss-tabset > .tab', this).fitHeightToParent();
|
||||
$('fieldset > .ss-tabset > .tab > .ss-tabset', this).fitHeightToParent();
|
||||
$('fieldset > .ss-tabset > .tab > .ss-tabset > .tab', this).fitHeightToParent();
|
||||
}
|
||||
}});
|
||||
|
||||
$('#Form_EditForm .Actions :submit').concrete({ss:{
|
||||
onclick: function(e) {
|
||||
$(this[0].form).ss().ajaxSubmit(this);
|
||||
return false;
|
||||
}
|
||||
}});
|
||||
})(jQuery);
|
||||
|
||||
jQuery(document).ready(function() {
|
||||
// @todo remove
|
||||
jQuery.concrete.triggerMatching();
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
var _AJAX_LOADING = false;
|
||||
|
||||
Behaviour.register({
|
||||
@ -442,9 +664,7 @@ function hideIndicator(id) {
|
||||
Effect.Fade(id, {duration: 0.3});
|
||||
}
|
||||
|
||||
setInterval(function() {
|
||||
new Ajax.Request("Security/ping");
|
||||
}, 180*1000);
|
||||
|
||||
|
||||
/**
|
||||
* Find and enable TinyMCE on all htmleditor fields
|
||||
|
Loading…
Reference in New Issue
Block a user