mirror of
https://github.com/silverstripe/silverstripe-reports
synced 2024-10-22 11:05:53 +02:00
API CHANGE Removed ChangeTracker javascript class, superseded by jquery.changetracker
API CHANGE Removed autoSave() javascript logic in CMS, superseded by custom code in LeftAndMain.EditForm.js ENHANCEMENT Using jquery.changetracker in LeftAndMain.EditForm.js, and overhauled window.unload logic to automatically trigger ajax saving after a user confirmation MINOR Changed unload confirmation text in CMS logic to adapt to new behaviour git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/cms/trunk@92685 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
parent
5f8a164d21
commit
5aef49a0a7
@ -214,6 +214,7 @@ class LeftAndMain extends Controller {
|
|||||||
Requirements::javascript(SAPPHIRE_DIR . '/thirdparty/jquery-livequery/jquery.livequery.js');
|
Requirements::javascript(SAPPHIRE_DIR . '/thirdparty/jquery-livequery/jquery.livequery.js');
|
||||||
Requirements::javascript(SAPPHIRE_DIR . '/thirdparty/jquery-cookie/jquery.cookie.js');
|
Requirements::javascript(SAPPHIRE_DIR . '/thirdparty/jquery-cookie/jquery.cookie.js');
|
||||||
Requirements::javascript(SAPPHIRE_DIR . '/javascript/jquery-ondemand/jquery.ondemand.js');
|
Requirements::javascript(SAPPHIRE_DIR . '/javascript/jquery-ondemand/jquery.ondemand.js');
|
||||||
|
Requirements::javascript(CMS_DIR . '/javascript/jquery-changetracker/lib/jquery.changetracker.js');
|
||||||
Requirements::javascript(SAPPHIRE_DIR . '/javascript/prototype_improvements.js');
|
Requirements::javascript(SAPPHIRE_DIR . '/javascript/prototype_improvements.js');
|
||||||
Requirements::add_i18n_javascript(SAPPHIRE_DIR . '/javascript/lang');
|
Requirements::add_i18n_javascript(SAPPHIRE_DIR . '/javascript/lang');
|
||||||
Requirements::add_i18n_javascript(CMS_DIR . '/javascript/lang');
|
Requirements::add_i18n_javascript(CMS_DIR . '/javascript/lang');
|
||||||
@ -227,7 +228,6 @@ class LeftAndMain extends Controller {
|
|||||||
|
|
||||||
Requirements::javascript(CMS_DIR . '/javascript/LeftAndMain.js');
|
Requirements::javascript(CMS_DIR . '/javascript/LeftAndMain.js');
|
||||||
Requirements::javascript(CMS_DIR . '/javascript/LeftAndMain_left.js');
|
Requirements::javascript(CMS_DIR . '/javascript/LeftAndMain_left.js');
|
||||||
Requirements::javascript(CMS_DIR . '/javascript/LeftAndMain_right.js');
|
|
||||||
Requirements::javascript(CMS_DIR . '/javascript/LeftAndMain.EditForm.js');
|
Requirements::javascript(CMS_DIR . '/javascript/LeftAndMain.EditForm.js');
|
||||||
|
|
||||||
Requirements::javascript(CMS_DIR . '/javascript/SideTabs.js');
|
Requirements::javascript(CMS_DIR . '/javascript/SideTabs.js');
|
||||||
|
@ -124,6 +124,7 @@ var ss_MainLayout;
|
|||||||
*/
|
*/
|
||||||
$('#Form_EditForm').concrete('ss', function($){
|
$('#Form_EditForm').concrete('ss', function($){
|
||||||
return/** @lends ss.EditForm */{
|
return/** @lends ss.EditForm */{
|
||||||
|
/*
|
||||||
onmatch: function() {
|
onmatch: function() {
|
||||||
// Alert the user on change of page-type - this might have implications
|
// Alert the user on change of page-type - this might have implications
|
||||||
// on the available form fields etc.
|
// on the available form fields etc.
|
||||||
@ -132,7 +133,10 @@ var ss_MainLayout;
|
|||||||
alert('The page type will be updated after the page is saved');
|
alert('The page type will be updated after the page is saved');
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$._super();
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -436,11 +436,11 @@ TreeContextMenu = {
|
|||||||
},
|
},
|
||||||
'Duplicate page and children' : function(treeNode) {
|
'Duplicate page and children' : function(treeNode) {
|
||||||
// First save the page silently (without confirmation) and then duplicate the page.
|
// First save the page silently (without confirmation) and then duplicate the page.
|
||||||
autoSave(false, treeNode.duplicatePageWithChildren.bind(treeNode));
|
jQuery('#Form_EditForm').concrete('ss').ajaxSubmit(null, treeNode.duplicatePageWithChildren.bind(treeNode));
|
||||||
},
|
},
|
||||||
'Duplicate just this page' : function(treeNode) {
|
'Duplicate just this page' : function(treeNode) {
|
||||||
// First save the page silently (without confirmation) and then duplicate the page.
|
// First save the page silently (without confirmation) and then duplicate the page.
|
||||||
autoSave(false, treeNode.duplicatePage.bind(treeNode));
|
jQuery('#Form_EditForm').concrete('ss').ajaxSubmit(null, treeNode.duplicatePageWithChildren.bind(treeNode));
|
||||||
},
|
},
|
||||||
'Sort sub-pages' : function(treeNode) {
|
'Sort sub-pages' : function(treeNode) {
|
||||||
var children = treeNode.treeNodeHolder().childTreeNodes();
|
var children = treeNode.treeNodeHolder().childTreeNodes();
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
* and reloading itself through the ajax return values.
|
* and reloading itself through the ajax return values.
|
||||||
* Takes care of resizing tabsets within the layout container.
|
* Takes care of resizing tabsets within the layout container.
|
||||||
* @name ss.Form_EditForm
|
* @name ss.Form_EditForm
|
||||||
|
* @require jquery.changetracker
|
||||||
*/
|
*/
|
||||||
$('#Form_EditForm').concrete('ss',function($){
|
$('#Form_EditForm').concrete('ss',function($){
|
||||||
return/** @lends ss.Form_EditForm */{
|
return/** @lends ss.Form_EditForm */{
|
||||||
@ -15,11 +16,44 @@
|
|||||||
*/
|
*/
|
||||||
RemoveText: 'Removed',
|
RemoveText: 'Removed',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type Object
|
||||||
|
*/
|
||||||
|
ChangeTrackerOptions: {},
|
||||||
|
|
||||||
onmatch: function() {
|
onmatch: function() {
|
||||||
|
this._setupChangeTracker();
|
||||||
|
|
||||||
|
$._super();
|
||||||
|
},
|
||||||
|
|
||||||
|
_setupChangeTracker: function() {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
// Don't bind any events here, as we dont replace the
|
// Don't bind any events here, as we dont replace the
|
||||||
// full <form> tag by any ajax updates they won't automatically reapply
|
// full <form> tag by any ajax updates they won't automatically reapply
|
||||||
|
this.changetracker(this.ChangeTrackerOptions());
|
||||||
|
|
||||||
_super();
|
var autoSaveOnUnload = function(e) {
|
||||||
|
// @todo TinyMCE coupling
|
||||||
|
if(typeof tinyMCE != 'undefined') tinyMCE.triggerSave();
|
||||||
|
if(self.is('.changed') && confirm(ss.i18n._t('LeftAndMain.CONFIRMUNSAVED'))) {
|
||||||
|
// unloads can't be prevented, but we can delay it with a synchronous ajax request
|
||||||
|
self.ajaxSubmit(
|
||||||
|
self.find(':submit[name=action_save]'),
|
||||||
|
null,
|
||||||
|
{async: false}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// use custom IE 'onbeforeunload' event, as it destroys the DOM
|
||||||
|
// before going into 'unload'
|
||||||
|
if(typeof window.onbeforeunload != 'undefined') {
|
||||||
|
window.onbeforeunload = autoSaveOnUnload;
|
||||||
|
} else {
|
||||||
|
$(window).unload(autoSaveOnUnload);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -293,25 +293,6 @@
|
|||||||
|
|
||||||
var _AJAX_LOADING = false;
|
var _AJAX_LOADING = false;
|
||||||
|
|
||||||
Behaviour.register({
|
|
||||||
|
|
||||||
'#MainMenu li' : {
|
|
||||||
onclick : function(event) {
|
|
||||||
LeftAndMain_window_unload(); // Confirm if there are unsaved changes
|
|
||||||
window.location.href = this.getElementsByTagName('a')[0].href;
|
|
||||||
Event.stop(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
LeftAndMain_window_unload = function() {
|
|
||||||
window.exiting = true; // this is used by prototype
|
|
||||||
if(typeof autoSave == 'function') {
|
|
||||||
return autoSave(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Event.observe(window, 'beforeunload', LeftAndMain_window_unload);
|
// Event.observe(window, 'beforeunload', LeftAndMain_window_unload);
|
||||||
|
|
||||||
@ -498,105 +479,6 @@ StatusTitle.prototype = {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ChangeTracker is a class that can be applied to forms to support change tracking on forms.
|
|
||||||
*/
|
|
||||||
ChangeTracker = Class.create();
|
|
||||||
ChangeTracker.prototype = {
|
|
||||||
initialize: function() {
|
|
||||||
this.resetElements();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset all the 'changed field' data.
|
|
||||||
*/
|
|
||||||
resetElements: function(debug) {
|
|
||||||
var elements = Form.getElements(this);
|
|
||||||
var i, element;
|
|
||||||
for(i=0;element=elements[i];i++) {
|
|
||||||
// Initialise each element
|
|
||||||
if(element.resetChanged) {
|
|
||||||
element.resetChanged();
|
|
||||||
} else {
|
|
||||||
element.originalSerialized = Form.Element.serialize(element);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
field_changed: function() {
|
|
||||||
// Something a value will go from 'undefined' to ''. Ignore such changes
|
|
||||||
if((this.originalSerialized+'') == 'undefined') return Form.Element.serialize(this) ? true : false;
|
|
||||||
else return this.originalSerialized != Form.Element.serialize(this);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if something in the form has been changed
|
|
||||||
*/
|
|
||||||
isChanged: function() {
|
|
||||||
var elements = Form.getElements(this);
|
|
||||||
var i, element;
|
|
||||||
for(i=0;element=elements[i];i++) {
|
|
||||||
// NOTE: TinyMCE coupling
|
|
||||||
// Ignore mce-generated elements
|
|
||||||
if(element.className.substr(0,3) == 'mce') continue;
|
|
||||||
|
|
||||||
if(!element.isChanged) element.isChanged = this.field_changed;
|
|
||||||
if(!this.changeDetection_fieldsToIgnore[element.name] && element.isChanged()) {
|
|
||||||
//console.log('Changed:'+ element.id + '(' + this.originalSerialized +')->('+Form.Element.serialize(element)+')' );
|
|
||||||
//console.log(element)
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
|
|
||||||
changeDetection_fieldsToIgnore : {
|
|
||||||
'Sort' : true
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Serialize only the fields to change.
|
|
||||||
* You can specify the names of fields that must be included as arguments
|
|
||||||
*/
|
|
||||||
serializeChangedFields: function() {
|
|
||||||
var elements = Form.getElements(this);
|
|
||||||
var queryComponent, queryComponents = new Array();
|
|
||||||
var i, element;
|
|
||||||
|
|
||||||
var forceFields = {};
|
|
||||||
if(arguments) {for(var i=0;i<arguments.length;i++) forceFields[arguments[i]] = true;}
|
|
||||||
|
|
||||||
for(i=0;element=elements[i];i++) {
|
|
||||||
if(!element.name.match(/^action_(.+)$/i)) // For dropdown those 'action_xxx' fields.
|
|
||||||
{ if(!element.isChanged) element.isChanged = this.field_changed;
|
|
||||||
if(forceFields[element.name] || (element.isChanged()) || element.name.match(/\[.*\]/g) ) {
|
|
||||||
queryComponent = Form.Element.serialize(element);
|
|
||||||
if (queryComponent)
|
|
||||||
queryComponents.push(queryComponent);
|
|
||||||
} else {
|
|
||||||
// Used by the Sapphire code to preserve the form field value
|
|
||||||
|
|
||||||
if( element.name.match( '/\]$/' ) )
|
|
||||||
queryComponents.push(element.name.substring( 0, element.name.length - 1 ) + '_unchanged' + ']=1' );
|
|
||||||
else
|
|
||||||
queryComponents.push(element.name + '_unchanged=1');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//alert(queryComponents.join('&'));
|
|
||||||
return queryComponents.join('&');
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Serialize all the fields on the page
|
|
||||||
*/
|
|
||||||
serializeAllFields: function() {
|
|
||||||
return Form.serializeWithoutButtons(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function hideLoading() {
|
function hideLoading() {
|
||||||
if($('Loading')) $('Loading').style.display = 'none';
|
if($('Loading')) $('Loading').style.display = 'none';
|
||||||
Element.removeClassName(document.body, 'stillLoading');
|
Element.removeClassName(document.body, 'stillLoading');
|
||||||
|
@ -202,7 +202,7 @@ TreeNodeAPI.prototype = {
|
|||||||
if(this.getElementsByTagName('a')[0].href) {
|
if(this.getElementsByTagName('a')[0].href) {
|
||||||
_AJAX_LOADING = true;
|
_AJAX_LOADING = true;
|
||||||
if($('sitetree').notify('SelectionChanged', this)) {
|
if($('sitetree').notify('SelectionChanged', this)) {
|
||||||
autoSave(true, this.getPageFromServer.bind(this));
|
jQuery('#Form_EditForm').concrete('ss').ajaxSubmit(null, this.getPageFromServer.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1,61 +0,0 @@
|
|||||||
/**
|
|
||||||
* Handle auto-saving. Detects if changes have been made, and if so save everything on the page.
|
|
||||||
* If confirmation is true it will ask for confirmation.
|
|
||||||
*/
|
|
||||||
function autoSave(confirmation, callAfter) {
|
|
||||||
// Note: TinyMCE coupling
|
|
||||||
if(typeof tinyMCE != 'undefined') tinyMCE.triggerSave();
|
|
||||||
|
|
||||||
var __forms = []
|
|
||||||
if($('Form_EditForm')) __forms.push($('Form_EditForm'));
|
|
||||||
if($('Form_SubForm')) __forms.push($('Form_SubForm'));
|
|
||||||
if($('Form_MemberForm')) __forms.push($('Form_MemberForm'));
|
|
||||||
|
|
||||||
var __somethingHasChanged = false;
|
|
||||||
var __callAfter = callAfter;
|
|
||||||
|
|
||||||
__forms.each(function(form) {
|
|
||||||
if(form.isChanged && form.isChanged()) {
|
|
||||||
__somethingHasChanged = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if(__somethingHasChanged) {
|
|
||||||
// Note: discard and cancel options are no longer used since switching to confirm dialog.
|
|
||||||
// save is still used if confirmation = false
|
|
||||||
var options = {
|
|
||||||
save: function() {
|
|
||||||
statusMessage(ss.i18n._t('CMSMAIN.SAVING'), '', true);
|
|
||||||
var i;
|
|
||||||
for(i=0;i<__forms.length;i++) {
|
|
||||||
if(__forms[i].isChanged && __forms[i].isChanged()) {
|
|
||||||
if(i == 0) __forms[i].save(true, __callAfter);
|
|
||||||
else __forms[i].save(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
discard: function() {
|
|
||||||
__forms.each(function(form) { form.resetElements(false); });
|
|
||||||
if(__callAfter) __callAfter();
|
|
||||||
},
|
|
||||||
cancel: function() {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(confirmation ) {
|
|
||||||
if(confirm(ss.i18n._t('LeftAndMain.CONFIRMUNSAVED')))
|
|
||||||
{
|
|
||||||
// OK was pressed, call function for what was clicked on
|
|
||||||
if(__callAfter) __callAfter();
|
|
||||||
} else {
|
|
||||||
// Cancel was pressed, stay on the current page
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
options.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if(__callAfter) __callAfter();
|
|
||||||
}
|
|
||||||
}
|
|
@ -24,6 +24,6 @@ if(typeof(ss) == 'undefined' || typeof(ss.i18n) == 'undefined') {
|
|||||||
'ModelAdmin.DELETED': "Deleted",
|
'ModelAdmin.DELETED': "Deleted",
|
||||||
'ModelAdmin.VALIDATIONERROR': "Validation Error",
|
'ModelAdmin.VALIDATIONERROR': "Validation Error",
|
||||||
'LeftAndMain.PAGEWASDELETED': "This page was deleted. To edit a page, select it from the left.",
|
'LeftAndMain.PAGEWASDELETED': "This page was deleted. To edit a page, select it from the left.",
|
||||||
'LeftAndMain.CONFIRMUNSAVED': "Are you sure you want to navigate away from this page?\n\nWARNING: Your changes have not been saved.\n\nPress OK to continue, or Cancel to stay on the current page."
|
'LeftAndMain.CONFIRMUNSAVED': "You have unsaved changes. Are you sure you want to navigate away from this page?\n\nPress OK to save your changes automatically."
|
||||||
});
|
});
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user