Skip to content
Snippets Groups Projects
Commit 4e683303 authored by Benjamin Mack's avatar Benjamin Mack Committed by Christian Kuhn
Browse files

[TASK] Cleanup EXT:viewpage JavaScript

The Extension viewpage (Web => View)
is still using a mixture of ExtJS and jQuery.

In order to use the logic from the new
Storage API (which replaces the ExtJS Part
for this module) the whole JavaScript
was rewritten in RequireJS.

The shipped jquery-ui JavaScript file
is not necessary anymore, as it is
loaded from the contrib/ directory
as a AMD module (new version).

Resolves: #64103
Releases: master
Change-Id: Ic0cc1dd0eb56b0440a5d8c78c40ac2120aa0f215
Reviewed-on: http://review.typo3.org/35767


Reviewed-by: default avatarWouter Wolters <typo3@wouterwolters.nl>
Tested-by: default avatarWouter Wolters <typo3@wouterwolters.nl>
Reviewed-by: default avatarChristian Kuhn <lolli@schwarzbu.ch>
Tested-by: default avatarChristian Kuhn <lolli@schwarzbu.ch>
parent b0e57cee
Branches
Tags
No related merge requests found
...@@ -53,20 +53,18 @@ define('TYPO3/CMS/Backend/Storage', ['jquery'], function ($) { ...@@ -53,20 +53,18 @@ define('TYPO3/CMS/Backend/Storage', ['jquery'], function ($) {
if (this._data === false) { if (this._data === false) {
var value; var value;
this._loadFromServer().done(function() { this._loadFromServer().done(function() {
value = Storage.Persistent._data[key]; value = Storage.Persistent._getRecursiveDataByDeepKey(Storage.Persistent._data, key.split('.'));
}); });
return value; return value;
} else { } else {
return this._data[key]; return this._getRecursiveDataByDeepKey(this._data, key.split('.'));
} }
}; };
Storage.Persistent.set = function(key, value) { Storage.Persistent.set = function(key, value) {
if (this._data === false) { if (this._data !== false) {
Storage.Persistent._storeOnServer(key, value); this._data = this._setRecursiveDataByDeepKey(this._data, key.split('.'), value);
} else {
this._data[key] = value;
this._storeOnServer(key, value);
} }
return this._storeOnServer(key, value);
}; };
Storage.Persistent.clear = function() { Storage.Persistent.clear = function() {
$.ajax(TYPO3.settings.ajaxUrls['UserSettings::process'], {data: {'action': 'clear'}}); $.ajax(TYPO3.settings.ajaxUrls['UserSettings::process'], {data: {'action': 'clear'}});
...@@ -109,7 +107,48 @@ define('TYPO3/CMS/Backend/Storage', ['jquery'], function ($) { ...@@ -109,7 +107,48 @@ define('TYPO3/CMS/Backend/Storage', ['jquery'], function ($) {
return $.ajax(TYPO3.settings.ajaxUrls['UserSettings::process'], {data: {'action': 'set', key: key, value: value}}).done(function(data) { return $.ajax(TYPO3.settings.ajaxUrls['UserSettings::process'], {data: {'action': 'set', key: key, value: value}}).done(function(data) {
Storage.Persistent._data = data; Storage.Persistent._data = data;
}); });
} };
/**
* helper function used to set a value which could have been a flat object key data["my.foo.bar"] to
* data[my][foo][bar]
* is called recursively by itself
*
* @param data the data to be uased as base
* @param keyParts the keyParts for the subtree
* @param value the value to be set
* @returns the data object
* @private
*/
Storage.Persistent._setRecursiveDataByDeepKey = function(data, keyParts, value) {
if (keyParts.length === 1) {
data = data || {};
data[keyParts[0]] = value;
} else {
var firstKey = keyParts.shift();
data[firstKey] = this._setRecursiveDataByDeepKey(data[firstKey] || {}, keyParts, value);
}
return data;
};
/**
* helper function used to set a value which could have been a flat object key data["my.foo.bar"] to
* data[my][foo][bar]
* is called recursively by itself
*
* @param data the data to be uased as base
* @param keyParts the keyParts for the subtree
* @returns {*}
* @private
*/
Storage.Persistent._getRecursiveDataByDeepKey = function(data, keyParts) {
if (keyParts.length === 1) {
return (data || {})[keyParts[0]];
} else {
var firstKey = keyParts.shift();
return this._getRecursiveDataByDeepKey(data[firstKey] || {}, keyParts);
}
};
/** /**
* return the Storage object, and attach it to the global TYPO3 object on the global frame * return the Storage object, and attach it to the global TYPO3 object on the global frame
......
...@@ -24,15 +24,14 @@ use TYPO3\CMS\Backend\Utility\BackendUtility; ...@@ -24,15 +24,14 @@ use TYPO3\CMS\Backend\Utility\BackendUtility;
*/ */
class ViewModuleController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController { class ViewModuleController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController {
public function __construct() { /**
parent::__construct(); * Gets called before each action
*
* @return void
*/
public function initializeAction() {
$GLOBALS['LANG']->includeLLFile('EXT:viewpage/Resources/Private/Language/locallang.xlf'); $GLOBALS['LANG']->includeLLFile('EXT:viewpage/Resources/Private/Language/locallang.xlf');
$this->pageRenderer = $GLOBALS['TBE_TEMPLATE']->getPageRenderer(); $GLOBALS['TBE_TEMPLATE']->getPageRenderer()->addInlineLanguageLabelFile('EXT:viewpage/Resources/Private/Language/locallang.xlf');
$this->pageRenderer->addInlineSettingArray('web_view', array(
'States' => $GLOBALS['BE_USER']->uc['moduleData']['web_view']['States'],
));
$this->pageRenderer->addInlineLanguageLabelFile('EXT:viewpage/Resources/Private/Language/locallang.xlf');
} }
/** /**
...@@ -41,12 +40,8 @@ class ViewModuleController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionContr ...@@ -41,12 +40,8 @@ class ViewModuleController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionContr
* @return void * @return void
*/ */
public function showAction() { public function showAction() {
$this->view->assignMultiple( $this->view->assign('widths', $this->getPreviewFrameWidths());
array( $this->view->assign('url', $this->getTargetUrl());
'widths' => $this->getPreviewFrameWidths(),
'url' => $this->getTargetUrl()
)
);
} }
/** /**
...@@ -142,12 +137,8 @@ class ViewModuleController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionContr ...@@ -142,12 +137,8 @@ class ViewModuleController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionContr
protected function getPreviewFrameWidths() { protected function getPreviewFrameWidths() {
$pageId = (int)\TYPO3\CMS\Core\Utility\GeneralUtility::_GP('id'); $pageId = (int)\TYPO3\CMS\Core\Utility\GeneralUtility::_GP('id');
$modTSconfig = BackendUtility::getModTSconfig($pageId, 'mod.web_view'); $modTSconfig = BackendUtility::getModTSconfig($pageId, 'mod.web_view');
$data = json_encode(array(
'width' => '100%',
'height' => "100%"
));
$widths = array( $widths = array(
$data => $GLOBALS['LANG']->getLL('autoSize') '100%|100%' => $GLOBALS['LANG']->getLL('autoSize')
); );
if (is_array($modTSconfig['properties']['previewFrameWidths.'])) { if (is_array($modTSconfig['properties']['previewFrameWidths.'])) {
foreach ($modTSconfig['properties']['previewFrameWidths.'] as $item => $conf ){ foreach ($modTSconfig['properties']['previewFrameWidths.'] as $item => $conf ){
...@@ -168,7 +159,8 @@ class ViewModuleController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionContr ...@@ -168,7 +159,8 @@ class ViewModuleController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionContr
} else { } else {
$label .= $GLOBALS['LANG']->sL(trim($conf['label'])); $label .= $GLOBALS['LANG']->sL(trim($conf['label']));
} }
$widths[json_encode($data)] = $label; $value = ($data['width'] ?: '100%') . '|' . ($data['height'] ?: '100%');
$widths[$value] = $label;
} }
} }
return $widths; return $widths;
......
<f:be.container <f:be.container
loadJQuery="TRUE"
includeJsFiles="{
0:'{f:uri.resource(path:\'JavaScript/jquery-ui-1.10.3.custom.min.js\')}',
1:'{f:uri.resource(path:\'JavaScript/ExtDirect.StateProvider.js\', extensionName:\'backend\')}',
2:'{f:uri.resource(path:\'JavaScript/common.js\')}'
}"
includeCssFiles="{ includeCssFiles="{
0:'{f:uri.resource(path:\'Css/ui-lightness/jquery-ui-1.10.3.custom.min.css\')}', 0:'{f:uri.resource(path:\'Css/ui-lightness/jquery-ui-1.10.3.custom.min.css\')}',
1:'{f:uri.resource(path:\'Css/main.css\')}' 1:'{f:uri.resource(path:\'Css/main.css\')}'
}" }"
> includeRequireJsModules="{
0:'TYPO3/CMS/Viewpage/Main'
}">
<div class="typo3-fullDoc"> <div class="typo3-fullDoc">
<div id="typo3-docheader"> <div id="typo3-docheader">
<div class="typo3-docheader-functions"> <div class="typo3-docheader-functions">
...@@ -39,4 +35,4 @@ ...@@ -39,4 +35,4 @@
</div> </div>
</div> </div>
</div> </div>
</f:be.container> </f:be.container>
\ No newline at end of file
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
/**
* Main logic for resizing the view of the frame
*/
define(['jquery', 'jquery-ui/resizable'], function($) {
// fetch the storage from the outer frame
var Storage = top.TYPO3.Storage;
var ViewPage = {
resizableContainerIdentifier: '#resizeable',
widthSelectorIdentifier: '#width',
storagePrefix: 'moduleData.web_view.States.'
};
ViewPage.initialize = function() {
var me = this;
me.$resizableContainer = $(me.resizableContainerIdentifier);
me.$widthSelector = $(me.widthSelectorIdentifier);
// Add event to width selector so the container is resized
$(document).on('change', me.widthSelectorIdentifier, function() {
var value = me.$widthSelector.val();
console.debug(value);
if (value) {
value = value.split('|');
me.$resizableContainer.animate({
width: value[0],
height: value[1] || '100%'
});
Storage.Persistent.set(me.storagePrefix + 'widthSelectorValue', value[0] + '|' + (value[1] || '100%'));
}
});
// Restore custom selector
var storedCustomWidth = Storage.Persistent.get(me.storagePrefix + 'widthSelectorCustomValue');
// Check for the " symbol is done in order to avoid problems with the old (non-jQuery) syntax which might be stored inside
// the UC from previous versions, can be removed with TYPO3 CMS9 again
if (storedCustomWidth && storedCustomWidth.indexOf('"') === -1) {
// add custom selector if stored value is not there
if (me.$widthSelector.find('option[value="' + storedCustomWidth + '"]').length === 0) {
me.addCustomWidthOption(storedCustomWidth);
}
}
// Re-select stored value
var storedWidth = Storage.Persistent.get(me.storagePrefix + 'widthSelectorValue');
// Check for the " symbol is done in order to avoid problems with the old (non-jQuery) syntax which might be stored inside
// the UC from previous versions, can be removed with TYPO3 CMS9 again
if (storedWidth && storedWidth.indexOf('"') == -1) {
me.$widthSelector.val(storedWidth).trigger('change');
}
// Initialize the jQuery UI Resizable plugin
me.$resizableContainer.resizable({
handles: 'e, se, s'
});
// Create and select custom option
me.$resizableContainer.on('resizestart', function(evt, ui) {
// Check custom option is there, if not, add it
if (me.$widthSelector.find('#customOption').length === 0) {
me.addCustomWidthOption('100%|100%');
}
// Select the custom option
me.$widthSelector.find('#customOption').prop('selected', true);
// Add iframe overlay to prevent loosing the mouse focus to the iframe while resizing fast
$(this).append('<div id="iframeCover" style="zindex:99;position:absolute;width:100%;top:0px;left:0px;height:100%;"></div>');
});
me.$resizableContainer.on('resize', function(evt, ui) {
// Update custom option
var value = ui.size.width + '|' + ui.size.height;
var label = me.getOptionLabel(value);
me.$widthSelector.find('#customOption').text(label).val(value);
});
me.$resizableContainer.on('resizestop', function(evt, ui) {
Storage.Persistent.set(me.storagePrefix + 'widthSelectorCustomValue', me.$widthSelector.val()).done(function() {
Storage.Persistent.set(me.storagePrefix + 'widthSelectorValue', me.$widthSelector.val());
});
// Remove iframe overlay
$('#iframeCover').remove();
});
};
ViewPage.addCustomWidthOption = function(value) {
ViewPage.$widthSelector.prepend('<option id="customOption" value="' + value + '">' + ViewPage.getOptionLabel(value) + '</option>');
};
ViewPage.getOptionLabel = function(data) {
data = data.split('|');
return data[0] + 'px ' + (data[1] ? '× ' + data[1] + 'px ' : '') + TYPO3.lang['customWidth'];
};
return function() {
$(document).ready(function() {
ViewPage.initialize();
});
}();
});
// IIFE for faster access to $ and save $ use
(function ($, Ext) {
// make sure $ and ExtDirect is loaded
var extReady = false;
var $Ready = false;
$(document).ready(function ($) {
$Ready = true;
librariesReady();
});
Ext.onReady(function () {
extReady = true;
librariesReady();
});
var librariesReady = function () {
if (!$Ready || !extReady) {
return
}
var resizableContainer = $('#resizeable');
var widthSelector = $('#width');
//save states in BE_USER->uc
Ext.state.Manager.setProvider(new TYPO3.state.ExtDirectProvider({
key: 'moduleData.web_view.States',
autoRead: false
}));
// load states
if (Ext.isObject(TYPO3.settings.web_view.States)) {
Ext.state.Manager.getProvider().initState(TYPO3.settings.web_view.States);
}
// Add event to width selector
widthSelector.on('change', function () {
var jsonObject = JSON.parse(widthSelector.val());
var height = jsonObject['height'] ? jsonObject['height'] : '100%';
resizableContainer.animate({
'width': jsonObject['width'],
'height': height
});
Ext.state.Manager.set('widthSelectorValue', widthSelector.val());
});
// use stored states
// restore custom selector
var storedCustomWidth = Ext.state.Manager.get('widthSelectorCustomValue', false);
if (storedCustomWidth) {
// add custom selector if stored value is not there
if (widthSelector.find('option[value="' + storedCustomWidth + '"]').length === 0) {
addCustomWidthOption(storedCustomWidth);
}
}
// select stored value
var storedWidth = Ext.state.Manager.get('widthSelectorValue', false);
if (storedWidth) {
// select it
widthSelector.val(storedWidth).change();
}
// $ UI Resizable plugin
// initialize
resizableContainer.resizable({
handles: 'e, se, s'
});
// create and select custom option
resizableContainer.on('resizestart', function (event, ui) {
// check custom option is there and add
if (widthSelector.find('#custom').length === 0) {
addCustomWidthOption('{}');
}
// select it
widthSelector.find('#custom').prop('selected', true);
// add iframe overlay to prevent loosing the mouse focus to the iframe while resizing fast
$(this).append('<div id="iframeCover" style="zindex:99;position:absolute;width:100%;top:0px;left:0px;height:100%;"></div>');
});
resizableContainer.on('resize', function (event, ui) {
// update custom option
var value = JSON.stringify({
width: ui.size.width,
height: ui.size.height
});
var label = getOptionLabel(value);
widthSelector.find('#custom').text(label).val(value);
});
resizableContainer.on('resizestop', function (event, ui) {
Ext.state.Manager.set('widthSelectorCustomValue', widthSelector.val());
// TODO: remove setTimeout workaround after bug #51998 in
// TYPO3\CMS\Backend\InterfaceState\ExtDirect\DataProvider->setState() was fixed
setTimeout(function () {
Ext.state.Manager.set('widthSelectorValue', widthSelector.val())
},
1000);
// remove iframe overlay
$('#iframeCover').remove();
});
function addCustomWidthOption(value) {
label = getOptionLabel(value);
var customOption = "<option id='custom' value='" + value + "'>" + label + "</option>";
widthSelector.prepend(customOption);
}
function getOptionLabel(data) {
var jsonObject = JSON.parse(data);
var height = jsonObject['height'] ? ' × ' + jsonObject['height'] + 'px ' : '';
return jsonObject['width'] + 'px ' + height + TYPO3.lang['customWidth'];
}
};
}(jQuery, Ext));
\ No newline at end of file
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment