mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-02 22:28:37 +02:00
BUGFIX Fixed form change tracking in the CMS, integrated it into menu changes. Reduced TinyMCE coupling.
This commit is contained in:
parent
a6e2316766
commit
482324b6ae
@ -70,7 +70,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Alert when unsaved changes are present
|
// Alert when unsaved changes are present
|
||||||
if(form._checkChangeTracker(true) == false) return false;
|
if(!form.confirmUnsavedChanges()) return false;
|
||||||
|
|
||||||
// hide existing form - shown again through _loadResponse()
|
// hide existing form - shown again through _loadResponse()
|
||||||
form.addClass('loading');
|
form.addClass('loading');
|
||||||
@ -138,14 +138,12 @@
|
|||||||
// default to first button if none given - simulates browser behaviour
|
// default to first button if none given - simulates browser behaviour
|
||||||
if(!button) button = this.find('.Actions :submit:first');
|
if(!button) button = this.find('.Actions :submit:first');
|
||||||
|
|
||||||
|
form.trigger('beforesave');
|
||||||
this.trigger('submitform', {form: form, button: button});
|
this.trigger('submitform', {form: form, button: button});
|
||||||
|
|
||||||
// set button to "submitting" state
|
// set button to "submitting" state
|
||||||
$(button).addClass('loading');
|
$(button).addClass('loading');
|
||||||
|
|
||||||
// @todo TinyMCE coupling
|
|
||||||
if(typeof tinyMCE != 'undefined') tinyMCE.triggerSave();
|
|
||||||
|
|
||||||
// validate if required
|
// validate if required
|
||||||
if(!form.validate()) {
|
if(!form.validate()) {
|
||||||
// TODO Automatically switch to the tab/position of the first error
|
// TODO Automatically switch to the tab/position of the first error
|
||||||
@ -252,7 +250,7 @@
|
|||||||
removeForm: function(form, placeholderHtml) {
|
removeForm: function(form, placeholderHtml) {
|
||||||
if(!placeholderHtml) placeholderHtml = this.getPlaceholderHtml();
|
if(!placeholderHtml) placeholderHtml = this.getPlaceholderHtml();
|
||||||
// Alert when unsaved changes are present
|
// Alert when unsaved changes are present
|
||||||
if(form._checkChangeTracker(true) == false) return;
|
if(!form.confirmUnsavedChanges()) return;
|
||||||
this.trigger('removeform');
|
this.trigger('removeform');
|
||||||
this.html(placeholderHtml);
|
this.html(placeholderHtml);
|
||||||
// TODO This should be using the plugin API
|
// TODO This should be using the plugin API
|
||||||
|
@ -113,34 +113,20 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function: _checkChangeTracker
|
* Function: confirmUnsavedChanges
|
||||||
*
|
*
|
||||||
* Checks the jquery.changetracker plugin status for this form.
|
* Checks the jquery.changetracker plugin status for this form,
|
||||||
* Usually bound to window.onbeforeunload.
|
* and asks the user for confirmation via a browser dialog if changes are detected.
|
||||||
*
|
* Doesn't cancel any unload or form removal events, you'll need to implement this based on the return
|
||||||
* Parameters:
|
* value of this message.
|
||||||
* {boolean} isUnloadEvent - ..
|
|
||||||
*
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
* (String) Either a string with a confirmation message, or the result of a confirm() dialog,
|
* (Boolean) FALSE if the user wants to abort with changes present, TRUE if no changes are detected
|
||||||
* based on the isUnloadEvent parameter.
|
* or the user wants to discard them.
|
||||||
*/
|
*/
|
||||||
_checkChangeTracker: function(isUnloadEvent) {
|
confirmUnsavedChanges: function() {
|
||||||
var self = this;
|
this.trigger('beforesave');
|
||||||
|
return (this.is('.changed')) ? confirm(ss.i18n._t('LeftAndMain.CONFIRMUNSAVED')) : true;
|
||||||
// @todo TinyMCE coupling
|
|
||||||
if(typeof tinyMCE != 'undefined') tinyMCE.triggerSave();
|
|
||||||
|
|
||||||
// check for form changes
|
|
||||||
if(self.is('.changed')) {
|
|
||||||
// returned string will trigger a confirm() dialog,
|
|
||||||
// but only if the method is triggered by an event
|
|
||||||
if(isUnloadEvent) {
|
|
||||||
return confirm(ss.i18n._t('LeftAndMain.CONFIRMUNSAVED'));
|
|
||||||
} else {
|
|
||||||
return ss.i18n._t('LeftAndMain.CONFIRMUNSAVEDSHORT');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -205,6 +191,13 @@
|
|||||||
* Constructor: onmatch
|
* Constructor: onmatch
|
||||||
*/
|
*/
|
||||||
onmatch : function() {
|
onmatch : function() {
|
||||||
|
var self = this;
|
||||||
|
this.closest('form').bind('beforesave', function() {
|
||||||
|
tinyMCE.triggerSave();
|
||||||
|
// TinyMCE assigns value attr directly, which doesn't trigger change event
|
||||||
|
self.trigger('change');
|
||||||
|
});
|
||||||
|
|
||||||
// Only works after TinyMCE.init() has been invoked, see $(window).bind() call below for details.
|
// Only works after TinyMCE.init() has been invoked, see $(window).bind() call below for details.
|
||||||
this.redraw();
|
this.redraw();
|
||||||
|
|
||||||
|
@ -22,6 +22,9 @@
|
|||||||
* </ul>
|
* </ul>
|
||||||
* </li>
|
* </li>
|
||||||
* </ul>
|
* </ul>
|
||||||
|
*
|
||||||
|
* Custom Events:
|
||||||
|
* - 'select': Fires when a menu item is selected (on any level).
|
||||||
*/
|
*/
|
||||||
$('.cms-menu-list').entwine({
|
$('.cms-menu-list').entwine({
|
||||||
onmatch: function() {
|
onmatch: function() {
|
||||||
@ -109,9 +112,7 @@
|
|||||||
if(e.which > 1 || this.is(':external')) return;
|
if(e.which > 1 || this.is(':external')) return;
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
// Expand this, and collapse all other items
|
|
||||||
var item = this.getMenuItem();
|
var item = this.getMenuItem();
|
||||||
item.select();
|
|
||||||
|
|
||||||
var url = this.attr('href');
|
var url = this.attr('href');
|
||||||
if(this.is(':internal')) url = $('base').attr('href') + url;
|
if(this.is(':internal')) url = $('base').attr('href') + url;
|
||||||
@ -119,13 +120,13 @@
|
|||||||
var children = item.find('li');
|
var children = item.find('li');
|
||||||
if(children.length) {
|
if(children.length) {
|
||||||
children.first().find('a').click();
|
children.first().find('a').click();
|
||||||
} else if(window.History.enabled) {
|
|
||||||
// Active menu item is set based on X-Controller ajax header,
|
|
||||||
// which matches one class on the menu
|
|
||||||
window.History.pushState({}, '', url);
|
|
||||||
} else {
|
} else {
|
||||||
window.location = url;
|
// Load URL, but give the loading logic an opportunity to veto the action
|
||||||
|
// (e.g. because of unsaved changes)
|
||||||
|
if(!$('.cms-container').loadPanel(url)) return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
item.select();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -112,6 +112,15 @@
|
|||||||
*/
|
*/
|
||||||
loadPanel: function(url, title, data) {
|
loadPanel: function(url, title, data) {
|
||||||
var data = data || {}, selector = data.selector || '.cms-content', contentEl = $(selector);
|
var data = data || {}, selector = data.selector || '.cms-content', contentEl = $(selector);
|
||||||
|
// Check change tracking (can't use events as we need a way to cancel the current state change)
|
||||||
|
var trackedEls = contentEl.find(':data(changetracker)').add(contentEl.filter(':data(changetracker)'));
|
||||||
|
if(trackedEls.length) {
|
||||||
|
var abort = false;
|
||||||
|
trackedEls.each(function() {
|
||||||
|
if(!$(this).confirmUnsavedChanges()) abort = true;
|
||||||
|
});
|
||||||
|
if(abort) return;
|
||||||
|
}
|
||||||
|
|
||||||
if(window.History.enabled) {
|
if(window.History.enabled) {
|
||||||
// Active menu item is set based on X-Controller ajax header,
|
// Active menu item is set based on X-Controller ajax header,
|
||||||
|
@ -68,6 +68,8 @@
|
|||||||
.each(function() {
|
.each(function() {
|
||||||
$(this).data('changetracker.origVal', $(this).val());
|
$(this).data('changetracker.origVal', $(this).val());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.data('changetracker', true);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user