silverstripe-cms/javascript/LeftAndMain_right.js
Ingo Schommer 74fad6a1d0 Merging refactored Translatable from trunk, and related changes to CMSMain
------------------------------------------------------------------------
r69959 | ischommer | 2009-01-11 01:15:30 +1300 (Sun, 11 Jan 2009) | 18 lines

Merged, debugged and enhanced Translatable patches from branches/translatable at r64523, r64523, 64523, thanks wakeless!
API CHANGE Changed Translatable schema from auxilliary tables (SiteTree_lang, SiteTree_lang_Live) to automatically filtered records on the original table (SiteTree, SiteTree_Live), using $Lang and $OriginalID properties. Incompatible update to old schema, migration script is in the works.
API CHANGE Removed Translatable::get_one(), Translatable::write()
ENHANCEMENT Simplified Translatable tree generation by using getSiteTreeFor() in CMSMain->createtranslation()
ENHANCEMENT Added AllChildrenIncludingDeleted(), augmentNumChildrenCountQuery(),  augmentAllChildrenIncludingDeleted(), augmentStageChildren() to Translatable class to allow for more stable tree generation.
ENHANCEMENT Moved definition of Translatable schema from augmentDatabase() to Translatable->extraStatics()
ENHANCEMENT Changes to the CMS language selection refresh the whole admin interface instead of the tree only. This way we can add a URL parameter ?lang=<lang> to /admin, which makes the specific language bookmarkable and reloadable. Changes to LangSelector.js
ENHANCEMENT Added fallback to ModelAsController->getNestedController() to fetch page with matching URLSegment but different language in case no page is found in the current language.
ENHANCEMENT Added helper methods to Translatable: getTranslation(), hasTranslation(), isTranslation(), findOriginalIDs()
ENHANCEMENT Getters and setters for Translatable->getOriginalPage() etc.
ENHANCEMENT Hooking Translatable into ModelAsController and ContentController initialization in order to call choose_site_lang()
ENHANCEMENT Simplified Translatable->augmentSQL(), augmentWrite() by not using auxilliary tables
ENHANCEMENT Showing clickable links for Translations in Translatable->updateCMSFields()
BUGFIX Modifying Hierarchy/SiteTree Children getters to accept optional "context" which can be used to set a language explicitly through the $Lang property, rather than implicitly reyling on the static Translatable::current_lang()
BUGFIX Fixed TranslatableTest to work with new datamodel
BUGFIX Temporarily disabled cookie/session selection in Translatable::choose_site_lang() until we have a good test suite for the side effects.
MINOR Added "untranslated" CSS styles to tree nodes and marking them as inactive/grey

------------------------------------------------------------------------
r70307 | ischommer | 2009-01-16 17:16:19 +1300 (Fri, 16 Jan 2009) | 2 lines

ENHANCEMENT Simplifying creation logic of new languages in CMS by reloading complete interface, rather than refreshing partial interface, language dropdown etc.
API CHANGE Removed CMSMain->switchlanguage()
------------------------------------------------------------------------
r70308 | ischommer | 2009-01-16 17:17:37 +1300 (Fri, 16 Jan 2009) | 2 lines

ENHANCEMENT Moved language selector in CMS above tree for better visibility, added padding and adjusted dropdown width
ENHANCEMENT Removed "Translating mode" status message above edit form - should be clear by the language dropdown above the CMS tree now
------------------------------------------------------------------------
r70322 | ischommer | 2009-01-19 13:09:55 +1300 (Mon, 19 Jan 2009) | 1 line

BUGFIX Ensuring that new pages can't be created when in translation mode by disabling the "create..." tree action
------------------------------------------------------------------------
r70323 | ischommer | 2009-01-19 13:11:08 +1300 (Mon, 19 Jan 2009) | 1 line

BUGFIX Fixed expanded/unexpanded flags on new tree items - was showing expanded styling (plus icon) with newly created pages
------------------------------------------------------------------------
r70324 | ischommer | 2009-01-19 13:26:02 +1300 (Mon, 19 Jan 2009) | 1 line

BUGFIX Making sure that LeftAndMain->CurrentPage() respects language settings - was returning pages in different language from session after switching between languages in cms
------------------------------------------------------------------------
r71297 | sharvey | 2009-02-03 18:12:42 +1300 (Tue, 03 Feb 2009) | 1 line

BUGFIX Only show the LangSelector dropdown if there's multiple languages available on the site
------------------------------------------------------------------------
r73343 | ischommer | 2009-03-19 06:14:02 +1300 (Thu, 19 Mar 2009) | 1 line

BUGFIX Changed CSS selector for TranslationTab javascript behaviour to be less specific
------------------------------------------------------------------------
r73344 | ischommer | 2009-03-19 06:14:59 +1300 (Thu, 19 Mar 2009) | 1 line

BUGFIX Checking for existence of original before trying to get translation in LeftAndMain->currentPage()
------------------------------------------------------------------------
r73345 | ischommer | 2009-03-19 06:18:52 +1300 (Thu, 19 Mar 2009) | 3 lines

ENHANCEMENT Showing all available languages in language selector above sitetree in CMS - you can now create new pages in completely new languages without any relation to an "original"
ENHANCEMENT Added CMSMain->IsTranslatableEnabled
API CHANGE Removed CMSMain->switchlanguage() - createTranslation() is sufficient for new, ajax refreshing of CMS state got way too complicated for switching languages, we now just reload the entire CMS with a different ?lang GET parameter
------------------------------------------------------------------------
r73469 | ischommer | 2009-03-20 21:49:27 +1300 (Fri, 20 Mar 2009) | 1 line

ENHANCEMENT Adjusted CMSMain and LeftAndMain to use locales instead of short lang codes when reading and writing translations. See r73468 for details on the underlying Translatable datamodel change
------------------------------------------------------------------------
r74071 | ischommer | 2009-04-04 10:24:59 +1300 (Sat, 04 Apr 2009) | 1 line

BUGFIX Fixed Form_EditForm_Locale reference in LeftAndMain_right.js (used to be Form_EditForm_Lang)
------------------------------------------------------------------------
r74072 | ischommer | 2009-04-04 10:26:51 +1300 (Sat, 04 Apr 2009) | 1 line

MINOR Using Translatable::choose_site_locale() instead of choose_site_lang() in LeftAndMain->init()
------------------------------------------------------------------------
r74951 | ischommer | 2009-04-22 16:23:56 +1200 (Wed, 22 Apr 2009) | 1 line

BUGFIX Fixed CMSMainTest->testThatGetCMSFieldsWorksOnEveryPageType() - was comparing a string $class with instanceof() instead of comparing the actually created instance
------------------------------------------------------------------------



git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/cms/branches/2.3@74988 467b73ca-7a2a-4603-9d3b-597d59a354a9
2011-02-02 17:48:13 +13:00

469 lines
14 KiB
JavaScript
Executable File

CMSForm = Class.extend('ChangeTracker').extend('Observable');
CMSForm.prototype = {
initialize : function(fn) {
this.ChangeTracker.initialize();
this.formName = fn;
this.prepareForm();
},
/**
* Trigger normal save event, helpful e.g. when enter key is pressed in
* single line input fields.
*/
onsubmit: function(e) {
this.save();
Event.stop(e);
return false;
},
/**
* Processing called whenever a page is loaded in the right - including the initial one
*/
prepareForm : function() {
ajaxActionsAtTop(this.id, 'form_actions_' + this.formName, this.formName);
},
/**
* Load actions from a string containing the HTML content
*/
loadActionsFromString : function(actionHTML) {
var actionHolder = $('form_actions_' + this.formName);
actionHolder.innerHTML = actionHTML;
prepareAjaxActions(actionHolder, this.id, this.formName);
},
/**
* Close the form down without any corrective action, after its been deleted.
*/
closeIfSetTo: function(id) {
if(this.elements.ID && this.elements.ID.value == id) {
// Note: TinyMCE coupling
tinymce_removeAll();
this.innerHTML = "<p>" + ss.i18n._t('LeftAndMain.PAGEWASDELETED') + "</p>";
}
},
/**
* Reload lose the form if the current page is open.
*/
reloadIfSetTo: function(id) {
if(this.elements.ID && this.elements.ID.value == id) {
this.getPageFromServer(id);
}
},
close: function() {
this.innerHTML = "<p>&#160;</p>";
var actions;
if(actions = $('form_actions_' + this.formName)) {
actions.parentNode.removeChild(actions);
}
},
updateStatus: function( newStatus ) {
if( $('Form_EditForm_Status') )
$('Form_EditForm_Status').innerHTML = "STATUS: " + newStatus;
},
/**
* Load a new page into the right-hand form.
*
* @param formContent string
* @param response object (optional)
* @param evalResponse boolean (optional)
*/
loadNewPage : function(formContent, response, evalResponse) {
//alert('here: ' + formContent);
var rightHTML = formContent;
// Rewrite # links
rightHTML = rightHTML.replace(/(<a[^>]+href *= *")#/g, '$1' + window.location.href.replace(/#.*$/,'') + '#');
// Rewrite iframe links (for IE)
rightHTML = rightHTML.replace(/(<iframe[^>]*src=")([^"]+)("[^>]*>)/g, '$1' + baseHref() + '$2$3');
// Note: TinyMCE coupling
tinymce_removeAll();
// Prepare iframes for removal, otherwise we get loading bugs
var i, allIframes = this.getElementsByTagName('iframe');
if(allIframes) for(i=0;i<allIframes.length;i++) {
allIframes[i].contentWindow.location.href = 'about:blank';
allIframes[i].parentNode.removeChild(allIframes[i]);
}
if(response && evalResponse) {
Ajax.Evaluator(response);
} else {
this.innerHTML = rightHTML;
}
// Get the form attributes from embedded fields
var attr;
for(attr in {'action':true ,'method':true,'enctype':true,'name':true}) {
if(this.elements['_form_' + attr]) {
this[attr] = this.elements['_form_' + attr].value;
this.elements['_form_' + attr].parentNode.removeChild(this.elements['_form_' + attr]);
}
}
allIframes = this.getElementsByTagName('iframe');
if(allIframes) for(i=0;i<allIframes.length;i++) {
try {
allIframes[i].contentWindow.location.href = allIframes[i].src;
} catch(er) { alert('Error in LeftAndMain_right.js CMSForm.loadNewPage: ' + er.message); }
}
_TAB_DIVS_ON_PAGE = [];
try {
var tabs = document.getElementsBySelector('#' + this.id + ' ul.tabstrip');
} catch(er) { /*alert('a: '+ er.message + '\n' + er.line);*/ }
try {
for(var i=0;i<tabs.length;i++) if(tabs[i].tagName) initTabstrip(tabs[i]);
} catch(er) { /*alert('b: '+ er.message + '\n' + er.line);*/ }
// We assume that an evaluated response is generated by FormResponse
// which takes care of calling these method it
if (!evalResponse) {
if (this.prepareForm) this.prepareForm();
Behaviour.apply(this);
}
if(this.resetElements) this.resetElements();
window.ontabschanged();
// 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();
}
},
/**
* Save the contens of the form, by submitting it and resetting is changed checker
* on success.
*
* @param publish boolean (optional) whether to publish in addition to saving
*/
save: function(ifChanged, callAfter, action, publish) {console.log(this.action);
_AJAX_LOADING = true;
// Note: TinyMCE coupling
if(typeof tinyMCE != 'undefined') tinyMCE.triggerSave();
if(!action) action = "save";
var __callAfter = callAfter;
var __form = this;
if(__form.notify && __form.elements.ID != undefined) __form.notify('BeforeSave', __form.elements.ID.value);
// validate if required
if(this.validate && !this.validate()) {
// 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;
}
var success = function(response) {
Ajax.Evaluator(response);
__form.resetElements();
if(__callAfter) __callAfter();
if(__form.notify && __form.elements.ID != undefined) __form.notify('PageSaved', __form.elements.ID.value);
if($('Form_EditForm_action_save') && $('Form_EditForm_action_save').stopLoading) $('Form_EditForm_action_save').stopLoading();
_AJAX_LOADING = false;
}
if(ifChanged) {
var data = this.serializeChangedFields('ID') + '&ajax=1&action_' + action + '=1';
} else {
var data = this.serializeAllFields() + '&ajax=1&action_' + action + '=1';
}
if(publish)
{
data += '&publish=1';
}
statusMessage(ss.i18n._t('CMSMAIN.SAVING'), null, true);
new Ajax.Request(this.action, {
method : this.method,
postBody: data,
onSuccess : success,
onFailure : function(response) {
errorMessage('Error saving content', response);
if($('Form_EditForm_action_save') && $('Form_EditForm_action_save').stopLoading) $('Form_EditForm_action_save').stopLoading();
_AJAX_LOADING = false;
}
});
},
loadPage_url : 'admin/getpage'
}
CMSRightForm = Class.extend('CMSForm');
CMSRightForm.prototype = {
intialize: function() {
this.CMSForm.initialize('right');
},
/**
* Load the given URL (with &ajax=1) into this form
*/
loadURLFromServer : function(url) {
var urlParts = url.match( /ID=(\d+)/ );
var id = urlParts ? urlParts[1] : null;
if( !url.match( /^https?:\/\/.*/ ) )
url = document.getElementsByTagName('base')[0].href + url;
new Ajax.Request( url + '&ajax=1', {
asynchronous : true,
onSuccess : function( response ) {
$('Form_EditForm').successfullyReceivedPage(response,id);
},
onFailure : function(response) {
alert(response.responseText);
errorMessage('error loading page',response);
}
});
},
successfullyReceivedPage : function(response,pageID) {
var loadingNode = $('sitetree').loadingNode;
if( loadingNode && pageID && parseInt( $('sitetree').getIdxOf( loadingNode ) ) != pageID ) {
return;
}
// must wait until the javascript has finished
document.body.style.cursor = 'wait';
this.loadNewPage(response.responseText);
var subform;
if(subform = $('Form_MemberForm')) subform.close();
if(subform = $('Form_SubForm')) subform.close();
if(this.elements.ID) {
this.notify('PageLoaded', this.elements.ID.value);
}
if(this.receivingID) {
// Treenode might not exist if that part of the tree is closed
var treeNode = loadingNode ? loadingNode : $('sitetree').getTreeNodeByIdx(this.receivingID);
if(treeNode) {
$('sitetree').setCurrentByIdx(treeNode.getIdx());
treeNode.removeNodeClass('loading');
}
statusMessage('');
}
// must wait until the javascript has finished
document.body.style.cursor = 'default';
},
didntReceivePage : function(response) {
errorMessage('error loading page', response);
$('sitetree').getTreeNodeByIdx(this.elements.ID.value).removeNodeClass('loading');
},
/**
* Request a page from the server via Ajax
*/
getPageFromServer : function(id, treeNode) {
// if(id && id.match(/^[A-Za-z0-9_]+$/)) {
if(id && (id == 'root' || parseInt(id) == id || (id.substr && id.substr(0,3) == 'new') )) {
this.receivingID = id;
// Treenode might not exist if that part of the tree is closed
if(!treeNode) treeNode = $('sitetree').getTreeNodeByIdx(id);
if(treeNode) {
$('sitetree').loadingNode = treeNode;
treeNode.addNodeClass('loading');
url = treeNode.aTag.href + (treeNode.aTag.href.indexOf('?')==-1?'?':'&') + 'ajax=1';
}
if(SiteTreeHandlers.loadPage_url) {
var sep = (SiteTreeHandlers.loadPage_url.indexOf('?') == -1) ? '?' : '&';
url = SiteTreeHandlers.loadPage_url + sep + 'ID=' + id;
}
// used to set language in CMSMain->init()
var lang = $('LangSelector') ? $F('LangSelector') : null;
if(lang) {
url += '&locale='+lang;
}
statusMessage("loading...");
this.loadURLFromServer(url);
} else {
throw("getPageFromServer: Bad page ID: " + id);
}
}
/**
* Set the status field
*/
/*setStatus: function(newStatus) {
var statusLabel = document.getElementsBySelector('label.pageStatusMessage')[0];
if(statusLabel) statusLabel.innerHTML = "STATUS: " + newStatus;
}*/
}
CMSForm.applyTo('#Form_SubForm');
CMSRightForm.applyTo('#Form_EditForm', 'right');
function action_save_right() {
_AJAX_LOADING = true;
$('Form_EditForm_action_save').value = ss.i18n._t('CMSMAIN.SAVING');
$('Form_EditForm_action_save').className = 'action loading';
$('Form_EditForm_action_save').stopLoading = function() {
if($('Form_EditForm_action_save') && $('Form_EditForm_action_save').className.indexOf('loading') != -1) {
$('Form_EditForm_action_save').value = 'Save';
Element.removeClassName($('Form_EditForm_action_save'), 'loading');
}
}
$('Form_EditForm').save(false);
}
/**
* 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();
}
}
StageLink = Class.create();
StageLink.prototype = {
initialize: function(getVars, urlField) {
this.getVars = getVars;
this.urlField = urlField;
var boundNewPage = this.newPage.bind(this);
$('Form_EditForm').observeMethod('PageLoaded', boundNewPage);
$('Form_EditForm').observeMethod('PageSaved', boundNewPage);
$('Form_EditForm').observeMethod('PagePublished', boundNewPage);
$('Form_EditForm').observeMethod('PageUnpublished', boundNewPage);
this.newPage();
},
newPage : function() {
var linkField = $('Form_EditForm').elements[this.urlField];
var linkVal = linkField ? linkField.value : null;
if(linkVal) {
if(this.id != 'viewArchivedSite') this.style.display = '';
this.href = linkVal + this.getVars;
} else {
if(this.id != 'viewArchivedSite') this.style.display = 'none';
}
if($('Form_EditForm_Locale')) {
this.href += "&locale=" + $('Form_EditForm_Locale').value;
}
},
onclick : function() {
var w = window.open(this.href, windowName('site'));
w.focus();
return false;
},
baseURL : function() {
return document.getElementsByTagName('base')[0].href;
}
}
StageLink.applyTo('#viewStageSite', '?stage=Stage', 'StageURLSegment');
StageLink.applyTo('#viewLiveSite', '?stage=Live', 'LiveURLSegment');
StageLink.applyTo('#viewArchivedSite', '', 'URLSegment');
window.name = windowName('cms');
/**
* Return a unique window name that contains the URL
*/
function windowName(suffix) {
var base = document.getElementsByTagName('base')[0].href.replace('~','').replace('http://','').replace(/\//g,'_').replace(/\./g,'_');
return base + suffix;
}
/**
* Remove all the currently active TinyMCE editors.
* Note: everything that calls this has an inappropriate coupling to TinyMCE.
* Perhaps an observer pattern could be used, where TinyMCE listens to a onBeforeCMSPageLoad
* event?
*/
function tinymce_removeAll() {
if((typeof tinymce != 'undefined') && tinymce.EditorManager) {
var id;
for(id in tinymce.EditorManager.editors) {
tinymce.EditorManager.editors[id].remove();
}
tinymce.EditorManager.editors = {};
}
}