From 567ad7296d95797b908451d586a731f1563d1816 Mon Sep 17 00:00:00 2001 From: Nattfarinn Date: Thu, 20 Oct 2016 09:57:01 +0200 Subject: [PATCH 1/2] EZS-1003: Wrong Urls used for siteaccesses - backend --- ApplicationConfig/Providers/MultiDomain.php | 27 ++++ ApplicationConfig/Providers/SiteAccesses.php | 9 +- Controller/StudioUIController.php | 204 ++++++++++++++++++--------- Resources/config/routing.yml | 13 ++ Resources/config/services.yml | 24 +++- Resources/views/multidomain.script.twig | 50 +++++++ SiteAccess/ReverseMatcher.php | 118 ++++++++++++++++ Twig/StudioUIExtension.php | 36 ++++- 8 files changed, 410 insertions(+), 71 deletions(-) create mode 100644 ApplicationConfig/Providers/MultiDomain.php create mode 100644 Resources/views/multidomain.script.twig create mode 100644 SiteAccess/ReverseMatcher.php diff --git a/ApplicationConfig/Providers/MultiDomain.php b/ApplicationConfig/Providers/MultiDomain.php new file mode 100644 index 0000000..f7ac3f5 --- /dev/null +++ b/ApplicationConfig/Providers/MultiDomain.php @@ -0,0 +1,27 @@ +reverseMatcher = $reverseMatcher; + } + + public function getConfig() + { + return $this->reverseMatcher->isMultiDomain(); + } +} diff --git a/ApplicationConfig/Providers/SiteAccesses.php b/ApplicationConfig/Providers/SiteAccesses.php index fc5a94e..073d540 100644 --- a/ApplicationConfig/Providers/SiteAccesses.php +++ b/ApplicationConfig/Providers/SiteAccesses.php @@ -6,23 +6,29 @@ namespace EzSystems\StudioUIBundle\ApplicationConfig\Providers; use eZ\Publish\Core\MVC\ConfigResolverInterface; +use EzSystems\StudioUIBundle\SiteAccess\ReverseMatcher; class SiteAccesses { /** @var ConfigResolverInterface */ private $configResolver; + /** @var ReverseMatcher */ + private $reverseMatcher; + /** @var array */ private $siteAccessList; /** * @param ConfigResolverInterface $configResolver * @param array $siteAccessList + * @param ReverseMatcher $reverseMatcher */ - public function __construct(ConfigResolverInterface $configResolver, array $siteAccessList) + public function __construct(ConfigResolverInterface $configResolver, array $siteAccessList, ReverseMatcher $reverseMatcher) { $this->configResolver = $configResolver; $this->siteAccessList = $siteAccessList; + $this->reverseMatcher = $reverseMatcher; } public function getConfig() @@ -33,6 +39,7 @@ class SiteAccesses if ($this->configResolver->hasParameter('languages', null, $siteAccess)) { $siteAccesses[$siteAccess]['languages'] = $this->configResolver->getParameter('languages', null, $siteAccess); } + $siteAccesses[$siteAccess]['urlRoot'] = $this->reverseMatcher->getUrlRoot($siteAccess); } return $siteAccesses; diff --git a/Controller/StudioUIController.php b/Controller/StudioUIController.php index bbc3521..c97810e 100644 --- a/Controller/StudioUIController.php +++ b/Controller/StudioUIController.php @@ -11,9 +11,12 @@ use eZ\Publish\API\Repository\LocationService; use eZ\Publish\API\Repository\ContentTypeService; use eZ\Bundle\EzPublishCoreBundle\Controller; use eZ\Publish\API\Repository\UserService; +use eZ\Publish\API\Repository\Values\Content\Location; use eZ\Publish\API\Repository\Values\Content\URLAlias; use eZ\Publish\API\Repository\Values\Content\VersionInfo; +use eZ\Publish\API\Repository\Values\ContentType\ContentType; use eZ\Publish\Core\REST\Server\Values; +use EzSystems\StudioUIBundle\SiteAccess\ReverseMatcher; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\JsonResponse; use eZ\Publish\Core\Base\Exceptions\NotFoundException; @@ -32,6 +35,7 @@ class StudioUIController extends Controller private $contentService; private $userService; private $router; + private $reverseMatcher; private $logger; public function __construct( @@ -41,6 +45,7 @@ class StudioUIController extends Controller ContentService $contentService, UserService $userService, RouterInterface $router, + ReverseMatcher $reverseMatcher, Logger $logger = null) { $this->urlAliasService = $urlAliasService; @@ -49,6 +54,7 @@ class StudioUIController extends Controller $this->contentService = $contentService; $this->userService = $userService; $this->router = $router; + $this->reverseMatcher = $reverseMatcher; $this->logger = $logger; } @@ -60,14 +66,14 @@ class StudioUIController extends Controller throw new BadRequestHttpException('The request is not AJAX request'); } - $siteaccessName = $request->query->has('siteaccessName') - ? $request->query->get('siteaccessName') + $siteAccessName = $request->query->has('siteAccessName') + ? $request->query->get('siteAccessName') : $this->container->get('ezpublish.siteaccess')->name; $languages = $this->getConfigResolver()->getParameter( 'languages', 'ezsettings', - $siteaccessName + $siteAccessName ); $language = array_shift($languages); @@ -131,6 +137,82 @@ class StudioUIController extends Controller return $jsonResponse; } + public function getUrlRootAction(Request $request) + { + $jsonResponse = new JsonResponse(); + + try { + $siteAccessName = $request->get('siteAccessName'); + + $jsonResponse->setData([ + 'urlRoot' => $this->reverseMatcher->getUrlRoot($siteAccessName), + ]); + } catch (\Exception $e) { + $jsonResponse->setStatusCode(Response::HTTP_BAD_REQUEST); + $jsonResponse->setData([ + 'message' => $e->getMessage(), + ]); + } + + return $jsonResponse; + } + + public function getFriendlyUrlAction(Request $request) + { + $jsonResponse = new JsonResponse(); + + try { + $siteAccessName = $request->get('siteAccessName'); + $locationPath = $request->get('locationPath'); + $custom = !($request->query->has('custom') && $request->query->get('custom') === 'false'); + + $locationPathParts = explode('/', $locationPath); + $locationId = array_pop($locationPathParts); + + $location = $this->locationService->loadLocation($locationId); + $rootLocation = $this->getSiteAccessRootLocation($siteAccessName); + + $rootUrlAlias = array_shift($this->getLocationAliases($rootLocation, $custom, $siteAccessName)); + $urlAlias = array_shift($this->getLocationAliases($location, $custom, $siteAccessName)); + + $urlRoot = $this->reverseMatcher->getUrlRoot($siteAccessName); + $urlPath = $urlAlias->path; + + if (strpos($location->pathString, $rootLocation->pathString) === 0) { + $urlPath = '/' . ltrim(substr($urlPath, strlen($rootUrlAlias->path)), '/'); + } + + $jsonResponse->setData([ + 'friendlyUrl' => $urlRoot . $urlPath, + ]); + } catch (\Exception $e) { + $jsonResponse->setStatusCode(Response::HTTP_BAD_REQUEST); + $jsonResponse->setData([ + 'message' => $e->getMessage(), + ]); + + throw $e; + } + + return $jsonResponse; + } + + /** + * @param string $siteAccessName + * + * @return \eZ\Publish\API\Repository\Values\Content\Location + */ + protected function getSiteAccessRootLocation($siteAccessName) + { + $rootLocationId = $this->getConfigResolver()->getParameter( + 'content.tree_root.location_id', + 'ezsettings', + $siteAccessName + ); + + return $this->locationService->loadLocation($rootLocationId); + } + /** * Checks whether a given page has a page field type. * @@ -147,24 +229,14 @@ class StudioUIController extends Controller } try { - $response = array( - 'contentId' => 0, - 'hasLandingPageFieldType' => false, - ); - - $url = $this->removeSiteaccessFromUrl($request->get('url')); + $siteAccessName = $request->get('siteAccessName'); + $url = $request->get('url'); - $rootLocationId = $this->getConfigResolver()->getParameter( - 'content.tree_root.location_id', - 'ezsettings', - $this->container->get('ezpublish.siteaccess')->name - ); + $location = $this->getSiteAccessRootLocation($siteAccessName); - if ($url === '/') { - $location = $this->locationService->loadLocation($rootLocationId); - } else { + if ($url !== '/') { $generator = $this->container->get('ezpublish.urlalias_generator'); - $rootPrefix = $generator->getPathPrefixByRootLocationId($rootLocationId); + $rootPrefix = $generator->getPathPrefixByRootLocationId($location->id); $locationInfo = $this->urlAliasService->lookup($rootPrefix . $url); $location = $this->locationService->loadLocation($locationInfo->destination); @@ -172,14 +244,14 @@ class StudioUIController extends Controller $contentType = $this->contentTypeService->loadContentType($location->getContentInfo()->contentTypeId); - $response['contentId'] = $this->generateUrl('ezpublish_rest_loadContent', array('contentId' => $location->getContentInfo()->id)); - $response['locationId'] = $this->generateUrl('ezpublish_rest_loadLocation', array('locationPath' => $location->id)); + $contentId = $this->generateUrl('ezpublish_rest_loadContent', array('contentId' => $location->getContentInfo()->id)); + $locationId = $this->generateUrl('ezpublish_rest_loadLocation', array('locationPath' => $location->id)); - foreach ($contentType->fieldDefinitions as $field) { - if ($field->fieldTypeIdentifier === self::PAGE_FIELD_TYPE_IDENTIFIER) { - $response['hasLandingPageFieldType'] = true; - } - } + $response = [ + 'contentId' => $contentId, + 'locationId' => $locationId, + 'hasLandingPageFieldType' => $this->hasLandingPageFieldType($contentType), + ]; $jsonResponse->setData($response); } catch (NotFoundException $error) { @@ -195,12 +267,28 @@ class StudioUIController extends Controller } /** + * @param ContentType $contentType + * + * @return bool + */ + protected function hasLandingPageFieldType(ContentType $contentType) + { + foreach ($contentType->fieldDefinitions as $field) { + if ($field->fieldTypeIdentifier === self::PAGE_FIELD_TYPE_IDENTIFIER) { + return true; + } + } + + return false; + } + + /** * Gets a list of siteaccesses from the config. * * @param \Symfony\Component\HttpFoundation\Request $request * @return \Symfony\Component\HttpFoundation\JsonResponse */ - public function siteaccessesAction(Request $request) + public function siteAccessesAction(Request $request) { $jsonResponse = new JsonResponse(); @@ -209,16 +297,16 @@ class StudioUIController extends Controller } try { - $siteaccessList = $this->container->getParameter('ezpublish.siteaccess.list'); + $siteAccessList = $this->container->getParameter('ezpublish.siteaccess.list'); - $siteaccesses = array(); - foreach ($siteaccessList as $siteaccess) { - if ($this->getConfigResolver()->hasParameter('languages', null, $siteaccess)) { - $siteaccesses[$siteaccess]['languages'] = $this->getConfigResolver()->getParameter('languages', null, $siteaccess); + $siteAccesses = array(); + foreach ($siteAccessList as $siteAccessName) { + if ($this->getConfigResolver()->hasParameter('languages', null, $siteAccessName)) { + $siteAccesses[$siteAccessName]['languages'] = $this->getConfigResolver()->getParameter('languages', null, $siteAccessName); } } - $jsonResponse->setData(array('siteaccesses' => $siteaccesses)); + $jsonResponse->setData(array('siteaccesses' => $siteAccesses)); } catch (NotFoundException $error) { if (!empty($this->logger)) { $this->logger->error($error->getMessage()); @@ -248,17 +336,12 @@ class StudioUIController extends Controller } $urlAlias = $this->urlAliasService->load($urlAliasId); + $siteAccessName = $request->get('siteAccessName'); - $rootLocationId = $this->getConfigResolver()->getParameter( - 'content.tree_root.location_id', - 'ezsettings', - $this->container->get('ezpublish.siteaccess')->name - ); - - if ($rootLocationId != 2) { - $location = $this->container->get('ezpublish.api.service.location')->loadLocation($rootLocationId); + $rootLocation = $this->getSiteAccessRootLocation($siteAccessName); - $rootUrlAliases = $this->urlAliasService->listLocationAliases($location, false); + if ($rootLocation->parentLocationId != 1) { + $rootUrlAliases = $this->urlAliasService->listLocationAliases($rootLocation, false); foreach ($rootUrlAliases as $rootUrlAlias) { if (strpos($urlAlias->path, $rootUrlAlias->path) === 0) { @@ -305,42 +388,33 @@ class StudioUIController extends Controller array_pop($locationPathParts) ); - $custom = $request->query->has('custom') && $request->query->get('custom') === 'false' ? false : true; - $siteaccessName = $request->query->has('siteaccessName') - ? $request->query->get('siteaccessName') + $custom = !($request->query->has('custom') && $request->query->get('custom') === 'false'); + + $siteAccessName = $request->query->has('siteAccessName') + ? $request->query->get('siteAccessName') : $this->container->get('ezpublish.siteaccess')->name; + $aliases = $this->getLocationAliases($location, $custom, $siteAccessName); + + return new Values\URLAliasRefList($aliases, $request->getPathInfo()); + } + + protected function getLocationAliases(Location $location, $custom, $siteAccessName) + { $languages = $this->getConfigResolver()->getParameter( 'languages', 'ezsettings', - $siteaccessName + $siteAccessName ); - $preferedLanguage = array_shift($languages); + $preferredLanguage = array_shift($languages); - $aliases = $this->urlAliasService->listLocationAliases($location, $custom, $preferedLanguage); + $aliases = $this->urlAliasService->listLocationAliases($location, $custom, $preferredLanguage); if (empty($aliases)) { $aliases = $this->urlAliasService->listLocationAliases($location, $custom); } - return new Values\URLAliasRefList($aliases, $request->getPathInfo()); - } - - /** - * Removes a siteaccess string from the url. - * - * @param string $url - * @return string - */ - protected function removeSiteaccessFromUrl($url) - { - foreach ($this->container->getParameter('ezpublish.siteaccess.list') as $value) { - if (substr($url, 1, strlen($value) + 1) === $value . '/') { - $url = substr($url, strlen($value) + 1); - } - } - - return $url; + return $aliases; } } diff --git a/Resources/config/routing.yml b/Resources/config/routing.yml index 3a1a73b..f831952 100644 --- a/Resources/config/routing.yml +++ b/Resources/config/routing.yml @@ -3,6 +3,11 @@ studioui_haspagefield: defaults: { _controller: ezstudioui.studio:urlAliasInfoAction } methods: [GET] +studioui_geturlroot: + pattern: /studio/geturlroot + defaults: { _controller: ezstudioui.studio:getUrlRootAction } + methods: [GET] + studioui_loadurlalias: path: /studio/urlalias/{urlAliasId} defaults: { _controller: ez_studioui.studio:loadURLAlias } @@ -25,6 +30,14 @@ studioui_layout_preview: template: eZStudioUIBundle:Static:layout.html.twig methods: [GET] +studioui_getfriendlyurl: + path: /studio/content/locations/{locationPath}/friendlyurl + defaults: + _controller: ez_studioui.studio:getFriendlyUrlAction + methods: [GET] + requirements: + locationPath: "[0-9/]+" + # Override: @EzPublishRestBundle/Resources/config/routing.yml:ezpublish_rest_listLocationURLAliases ezpublish_rest_listLocationURLAliases: path: /api/ezp/v2/content/locations/{locationPath}/urlaliases diff --git a/Resources/config/services.yml b/Resources/config/services.yml index c6d6eaa..5f521c1 100644 --- a/Resources/config/services.yml +++ b/Resources/config/services.yml @@ -1,7 +1,9 @@ parameters: ezstudioui.controller.studio.class: EzSystems\StudioUIBundle\Controller\StudioUIController ezstudioui.provider.site_accesses.class: EzSystems\StudioUIBundle\ApplicationConfig\Providers\SiteAccesses + ezstudioui.provider.multidomain.class: EzSystems\StudioUIBundle\ApplicationConfig\Providers\MultiDomain ezstudioui.twig_extension.class: EzSystems\StudioUIBundle\Twig\StudioUIExtension + ezstudioui.reverse_matcher.class: EzSystems\StudioUIBundle\SiteAccess\ReverseMatcher services: ezstudioui.studio: @@ -14,6 +16,7 @@ services: - @ezpublish.api.service.content - @ezpublish.api.service.user - @router + - @ezstudioui.reverse_matcher - @?logger tags: - { name: monolog.logger, channel: studioUI } @@ -23,16 +26,35 @@ services: arguments: - '@ezpublish.config.resolver' - '%ezpublish.siteaccess.list%' + - '@ezstudioui.reverse_matcher' tags: - name: ezsystems.platformui.application_config_provider key: 'studioSiteaccesses' + ezstudioui.provider.multidomain: + class: %ezstudioui.provider.multidomain.class% + arguments: + - '@ezstudioui.reverse_matcher' + tags: + - + name: ezsystems.platformui.application_config_provider + key: 'isMultiDomain' + ezstudioui.twig_extension: class: %ezstudioui.twig_extension.class% arguments: - '@ezpublish.config.resolver' - - %ezpublish.content_view.viewbase_layout% + - '%ezpublish.content_view.viewbase_layout%' + - '@ezstudioui.reverse_matcher' public: false tags: - { name: twig.extension } + + ezstudioui.reverse_matcher: + class: '%ezstudioui.reverse_matcher.class%' + arguments: + - "@ezpublish.siteaccess.matcher_builder" + - "%ezpublish.siteaccess.match_config%" + - "%ezpublish.siteaccess.list%" + - "@request_stack" diff --git a/Resources/views/multidomain.script.twig b/Resources/views/multidomain.script.twig new file mode 100644 index 0000000..92b4adf --- /dev/null +++ b/Resources/views/multidomain.script.twig @@ -0,0 +1,50 @@ + diff --git a/SiteAccess/ReverseMatcher.php b/SiteAccess/ReverseMatcher.php new file mode 100644 index 0000000..71bb51a --- /dev/null +++ b/SiteAccess/ReverseMatcher.php @@ -0,0 +1,118 @@ +matcherBuilder = $matcherBuilder; + $this->siteAccessesConfiguration = $siteAccessesConfiguration; + $this->siteAccessList = $siteAccessList; + $this->requestStack = $requestStack; + } + + /** + * Returns the VersatoleMatcher object containing request corresponding to the reverse match. + * This request object can then be used to build a link to the "reverse matched" SiteAccess. + * + * @param string $siteAccessName + * + * @see reverseMatch() + * + * @return VersatileMatcher + */ + public function getMatcher($siteAccessName) + { + if (!in_array($siteAccessName, $this->siteAccessList)) { + throw new InvalidSiteAccessException($siteAccessName, $this->siteAccessList, get_class($this)); + } + + foreach ($this->siteAccessesConfiguration as $matchingClass => $matchingConfiguration) { + $matcher = $this->matcherBuilder->buildMatcher($matchingClass, $matchingConfiguration, new SimplifiedRequest()); + + if ($matcher instanceof VersatileMatcher) { + return $matcher->reverseMatch($siteAccessName); + } + } + + throw new InvalidConfigurationException('Cannot reverse match SiteAccess; at least one VersatileMatcher configuration is required.'); + } + + public function getUrlParts($siteAccessName) + { + $matcher = $this->getMatcher($siteAccessName); + $request = $matcher->getRequest(); + $masterRequest = $this->requestStack->getMasterRequest(); + + return [ + 'scheme' => $request->scheme ?: 'http', + 'host' => $request->host ?: $masterRequest->getHost(), + 'port' => $request->port ?: $masterRequest->getPort(), + 'uri' => $request->pathinfo, + ]; + } + + public function getSiteAccessDomains() + { + $domains = []; + + foreach ($this->siteAccessList as $siteAccessName) { + $parts = $this->getUrlParts($siteAccessName); + + $domains[] = sprintf('%s://%s%s', + $parts['scheme'], + $parts['host'], + $parts['port'] !== 80 ? ":{$parts['port']}" : '' + ); + } + + return $domains; + } + + public function getUrlRoot($siteAccessName) + { + $parts = $this->getUrlParts($siteAccessName); + + return sprintf('%s://%s%s%s', + $parts['scheme'], + $parts['host'], + $parts['port'] !== 80 ? ":{$parts['port']}" : '', + $parts['uri'] + ); + } + + /** + * @return bool + */ + public function isMultiDomain() + { + $hosts = []; + + foreach ($this->siteAccessList as $siteAccessName) { + $hosts[] = $this->getUrlParts($siteAccessName)['host']; + } + + return count(array_unique($hosts)) > 1; + } +} diff --git a/Twig/StudioUIExtension.php b/Twig/StudioUIExtension.php index 9103547..2796e7e 100644 --- a/Twig/StudioUIExtension.php +++ b/Twig/StudioUIExtension.php @@ -6,8 +6,10 @@ namespace EzSystems\StudioUIBundle\Twig; use eZ\Publish\Core\MVC\ConfigResolverInterface; +use EzSystems\StudioUIBundle\SiteAccess\ReverseMatcher; use Twig_Extension; use Twig_SimpleFunction; +use Twig_Environment; class StudioUIExtension extends Twig_Extension { @@ -17,14 +19,18 @@ class StudioUIExtension extends Twig_Extension /** @var string */ private $defaultTemplate; + /** @var ReverseMatcher */ + private $reverseMatcher; + /** * @param \eZ\Publish\Core\MVC\ConfigResolverInterface $configResolver * @param string $defaultTemplate */ - public function __construct(ConfigResolverInterface $configResolver, $defaultTemplate) + public function __construct(ConfigResolverInterface $configResolver, $defaultTemplate, ReverseMatcher $reverseMatcher) { $this->configResolver = $configResolver; $this->defaultTemplate = $defaultTemplate; + $this->reverseMatcher = $reverseMatcher; } /** @@ -32,12 +38,20 @@ class StudioUIExtension extends Twig_Extension */ public function getFunctions() { - return array( + return [ new Twig_SimpleFunction( 'base_template', - array($this, 'getBaseTemplate') + [$this, 'getBaseTemplate'] ), - ); + new Twig_SimpleFunction( + 'multidomain_access', + [$this, 'renderMultidomainAccessScript'], + [ + 'needs_environment' => true, + 'is_safe' => ['html'], + ] + ), + ]; } /** @@ -55,6 +69,20 @@ class StudioUIExtension extends Twig_Extension } /** + * Renders script for multidomains iframe access. + * + * @return string + */ + public function renderMultidomainAccessScript(Twig_Environment $environment) + { + return $environment->render( + 'eZStudioUIBundle::multidomain.script.twig', [ + 'domains' => $this->reverseMatcher->getSiteAccessDomains(), + ] + ); + } + + /** * {@inheritdoc} */ public function getName() -- 2.6.4 (Apple Git-63) From ad1357760681a0f1474029e265e059615f65a7e9 Mon Sep 17 00:00:00 2001 From: Dariusz Szut Date: Mon, 7 Nov 2016 16:20:54 +0100 Subject: [PATCH 2/2] EZS-1003: Wrong Urls used for siteaccesses - frontend --- Resources/config/yui.yml | 9 + Resources/public/css/theme/views/general.css | 4 + Resources/public/css/theme/views/topactionbar.css | 4 + .../public/js/apps/plugins/ezs-browserplugin.js | 13 +- Resources/public/js/views/ezs-appview.js | 80 +++++-- Resources/public/js/views/ezs-browserview.js | 126 ++++++++--- .../public/js/views/ezs-multidomainbrowserview.js | 234 +++++++++++++++++++++ Resources/public/js/views/ezs-topactionbarview.js | 14 +- .../navigation/ezs-dynamicnavigationitemview.js | 19 +- .../js/views/services/ezs-browserviewservice.js | 30 +-- .../ezs-dynamiclandingpageeditorviewservice.js | 99 ++++++++- .../plugins/ezs-contentcreateredirectplugin.js | 14 +- .../plugins/ezs-studionavigationhubplugin.js | 58 +++-- .../public/js/views/timeline/ezs-timelineview.js | 43 ++-- Resources/views/multidomain.script.twig | 17 +- Tests/js/views/assets/ezs-appview-tests.js | 2 +- Tests/js/views/assets/ezs-browserview-tests.js | 37 ++-- .../assets/ezs-dynamicnavigationitemview-tests.js | 51 ++--- .../assets/ezs-browserviewservice-tests.js | 13 +- .../ezs-contentcreateredirectplugin-tests.js | 5 + .../assets/ezs-studionavigationhubplugin-tests.js | 141 +++++-------- 21 files changed, 745 insertions(+), 268 deletions(-) create mode 100644 Resources/public/js/views/ezs-multidomainbrowserview.js diff --git a/Resources/config/yui.yml b/Resources/config/yui.yml index 8cca299..49c64ed 100644 --- a/Resources/config/yui.yml +++ b/Resources/config/yui.yml @@ -139,6 +139,15 @@ system: browserview-ez-template: type: 'template' path: %ezstudioui.public_dir%/templates/appview.hbt + ezs-multidomainbrowserview: + requires: + - 'ezs-browserview' + - 'multidomainbrowserview-ez-template' + dependencyOf: ['ez-platformuiapp'] + path: %ezstudioui.public_dir%/js/views/ezs-multidomainbrowserview.js + multidomainbrowserview-ez-template: + type: 'template' + path: %ezstudioui.public_dir%/templates/appview.hbt ezs-browserviewservice: requires: - 'ez-viewservice' diff --git a/Resources/public/css/theme/views/general.css b/Resources/public/css/theme/views/general.css index 252cd2a..974710b 100644 --- a/Resources/public/css/theme/views/general.css +++ b/Resources/public/css/theme/views/general.css @@ -12,6 +12,10 @@ background: rgba(0, 0, 0, .6); } +.ezs-overlay.is-transparent { + background: transparent; +} + .ezs-workspace { transition: background .3s cubic-bezier(.25,.8,.25,1); transform: translate3d(0, 0, 0); diff --git a/Resources/public/css/theme/views/topactionbar.css b/Resources/public/css/theme/views/topactionbar.css index b5003c3..287c3c4 100644 --- a/Resources/public/css/theme/views/topactionbar.css +++ b/Resources/public/css/theme/views/topactionbar.css @@ -19,6 +19,10 @@ background: rgba(0, 0, 0, .6); } +.ez-view-topactionbarview .ezs-toolbar__overlay.is-transparent { + background: transparent; +} + @media (min-width: 1280px) { .ez-view-topactionbarview [data-item-placeholder]:after { content: ''; diff --git a/Resources/public/js/apps/plugins/ezs-browserplugin.js b/Resources/public/js/apps/plugins/ezs-browserplugin.js index db698db..e3bdcf5 100644 --- a/Resources/public/js/apps/plugins/ezs-browserplugin.js +++ b/Resources/public/js/apps/plugins/ezs-browserplugin.js @@ -45,7 +45,10 @@ YUI.add('ezs-browserplugin', function (Y) { _extendRouting: function () { var app = this.get('host'), appRoutes = app.get('routes'), - appContainer = app.get('container'); + appContainer = app.get('container'), + isMultiDomain = app.get('config.isMultiDomain'), + browserViewName = isMultiDomain ? 'multiDomainBrowserView' : 'browserView', + browserViewType = isMultiDomain ? Y.eZS.MultiDomainBrowserView : Y.eZS.BrowserView; if (!appContainer.one(SELECTOR_TOOLBAR)) { appContainer.one(SELECTOR_MAINVIEWS).prepend(Y.Node.create('
').addClass(CLASS_TOOLBAR)); @@ -64,15 +67,15 @@ YUI.add('ezs-browserplugin', function (Y) { hideClass: CLASS_TOOLBAR_HIDDEN }; - app.views.browserView = { - type: Y.eZS.BrowserView, + app.views[browserViewName] = { + type: browserViewType, parent: 'dashboardView' }; app.route({ name: 'studioBrowser', path: '/studio/insite', - view: 'browserView', + view: browserViewName, sideViews: { 'navigationHub': true, 'studioToolbar': true, @@ -86,7 +89,7 @@ YUI.add('ezs-browserplugin', function (Y) { app.route({ name: 'studioPreview', path: '/studio/insite/:previewContentUrl', - view: 'browserView', + view: browserViewName, sideViews: { 'navigationHub': true, 'studioToolbar': true, diff --git a/Resources/public/js/views/ezs-appview.js b/Resources/public/js/views/ezs-appview.js index 23dc055..1e86f87 100644 --- a/Resources/public/js/views/ezs-appview.js +++ b/Resources/public/js/views/ezs-appview.js @@ -13,6 +13,7 @@ YUI.add('ezs-appview', function (Y) { var ATTR_DEVICE = 'data-device', CLASS_VISIBLE = 'is-visible', + CLASS_TRANSPARENT = 'is-transparent', CLASS_SCROLL_DISABLED = 'ezs-is-scroll-disabled', SELECTOR_APP_PREVIEW = '.ezs-appview__workspace__preview', SELECTOR_APP_TIMELINE = '.ezs-appview__workspace__timeline', @@ -68,8 +69,8 @@ YUI.add('ezs-appview', function (Y) { this.set('previewWindow', iframe); - this._iframeLoadedHandler = iframe.on('load', this._eventHandlerLoad, this); - this._updateIframeHeightHandler = iframe.on('load', this._tryUpdateIframeHeight, this); + this._attachIframeLoadEventHandlers(iframe); + this._windowResizeHandler = Y.on('windowresize', Y.bind(this._tryUpdateIframeHeight, this)); /** @@ -90,6 +91,18 @@ YUI.add('ezs-appview', function (Y) { }, /** + * Adds event listener to iframe on load. + * + * @protected + * @method _attachIframeLoadEventHandlers + * @param iframe {Y.Node} the iframe node + */ + _attachIframeLoadEventHandlers: function (iframe) { + this._iframeLoadedHandler = iframe.on('load', this._eventHandlerLoad, this); + this._updateIframeHeightHandler = iframe.on('load', this._tryUpdateIframeHeight, this); + }, + + /** * Toggles the overlay on the view * * @protected @@ -99,14 +112,19 @@ YUI.add('ezs-appview', function (Y) { */ _toggleOverlay: function (event, visible) { var methodName = visible ? 'addClass' : 'removeClass', + isTransparent = event && event.hasOwnProperty('isTransparent') ? event.isTransparent : false, + trasnparentMethodName = isTransparent ? 'addClass' : 'removeClass', overlay = this.get('container').one(SELECTOR_OVERLAY); if (overlay) { overlay[methodName](CLASS_VISIBLE); + overlay[trasnparentMethodName](CLASS_TRANSPARENT); - this.get('actionbar').toggleOverlay(visible); + this.get('actionbar').toggleOverlay(visible, isTransparent); - Y.one('body')[methodName](CLASS_SCROLL_DISABLED); + if (!isTransparent) { + Y.one('body')[methodName](CLASS_SCROLL_DISABLED); + } } }, @@ -229,13 +247,9 @@ YUI.add('ezs-appview', function (Y) { */ _updateIframeHeight: function () { var iframeNode = this.get('previewWindow').getDOMNode(), - iframeBody = iframeNode.contentDocument.body, - bodyOverfow = iframeBody.style.overflow, isLoadingScreenDisabled = this.get('loadingScreenDisabledOnIframeHeightChange'); - iframeBody.style.overflow = 'hidden'; - iframeNode.style.height = iframeBody.offsetHeight + PX; - iframeBody.style.overflow = bodyOverfow; + iframeNode.style.height = this._getIframeBodyHeight() + PX; this._transformTimeline(); this._updateSidebarPosition(); @@ -243,6 +257,38 @@ YUI.add('ezs-appview', function (Y) { if (!isLoadingScreenDisabled) { this._hideLoadingScreen(); } + + this._updateLoadingScreenState(); + }, + + /** + * Updates the loading screen state. + * The default implementation does nothing except return the view itself. + * + * @protected + * @method _updateLoadingScreenState + * @return {eZS.AppView} the view itself + */ + _updateLoadingScreenState: function () { + return this; + }, + + /** + * Gets the iframe body height. + * + * @protected + * @method _getIframeBodyHeight + */ + _getIframeBodyHeight: function () { + var iframeBody = this.get('previewWindow').getDOMNode().contentDocument.body, + bodyOverfow = iframeBody.style.overflow, + bodyHeight; + + iframeBody.style.overflow = 'hidden'; + bodyHeight = iframeBody.offsetHeight; + iframeBody.style.overflow = bodyOverfow; + + return bodyHeight; }, /** @@ -255,10 +301,6 @@ YUI.add('ezs-appview', function (Y) { * @return {eZS.AppView} the view itself */ _eventHandlerLoad: function (event) { - var iframeWindow = this.get('previewWindow').getDOMNode().contentWindow; - - iframeWindow.onpagehide = Y.bind(this._cleanInformationPanel, this); - return this; }, @@ -322,7 +364,6 @@ YUI.add('ezs-appview', function (Y) { this._showLoadingScreen(); - iframe.getDOMNode().contentWindow.onpagehide = null; iframe.detach('load', this._eventHandlerLoad, this); timeline.removeTarget(this); @@ -339,9 +380,16 @@ YUI.add('ezs-appview', function (Y) { window.clearTimeout(this._updateIframeHeightTimeout); - this._updateIframeHeightHandler.detach(); + if (this._updateIframeHeightHandler) { + this._updateIframeHeightHandler.detach(); + } + + if (this._iframeLoadedHandler) { + this._iframeLoadedHandler.detach(); + } + this._windowResizeHandler.detach(); - this._iframeLoadedHandler.detach(); + } }, { ATTRS: { diff --git a/Resources/public/js/views/ezs-browserview.js b/Resources/public/js/views/ezs-browserview.js index 683c87e..c313adf 100644 --- a/Resources/public/js/views/ezs-browserview.js +++ b/Resources/public/js/views/ezs-browserview.js @@ -15,6 +15,7 @@ YUI.add('ezs-browserview', function (Y) { ATTR_ZONE = 'data-studio-zone', CLASS_APP = 'ezs-appview', CLASS_APP_TIMELINE_HIDDEN = CLASS_APP + '--timeline-hidden', + SELECTOR_PREVIEW_IFRAME = '#ezs-studio-preview', SELECTOR_APP = '.' + CLASS_APP, SELECTOR_APP_TIMELINE = SELECTOR_APP + '__workspace__timeline', SELECTOR_TOOLBAR = '.ezs-app-toolbar', @@ -143,10 +144,12 @@ YUI.add('ezs-browserview', function (Y) { this._updateInformationPanel(); } - iframeWindow.onpagehide = Y.bind(this._cleanInformationPanel, this); - this.set('previewUrl', iframePath); + if (iframePath.indexOf(this.get('studioActiveSiteaccess')) !== -1) { + iframePath = iframePath.substring(this.get('studioActiveSiteaccess').length + 1, iframePath.length); + } + /** * Fired when a website is loaded into preview mode/iframe. * It's checking whether a currently viewed page has the pageFieldType @@ -275,7 +278,7 @@ YUI.add('ezs-browserview', function (Y) { * @param event {Object} event facade */ _updateScheduleBlocksPreview: function (event) { - var preview = this.get('previewWindow').getDOMNode().contentDocument, + var preview = Y.one(SELECTOR_PREVIEW_IFRAME).getDOMNode().contentWindow, blocks = event.newVal.blocks; if (!preview) { @@ -283,19 +286,14 @@ YUI.add('ezs-browserview', function (Y) { } Object.keys(blocks).forEach(Y.bind(function (blockId) { - var blockNode; + var blockSelector = '[' + ATTR_BLOCK_ID + '="' + blockId + '"]', + blockPreview = blocks[blockId].html; if (blocks[blockId].json[0].type !== BLOCK_TYPE_SCHEDULE) { return; } - blockNode = preview.querySelector('[' + ATTR_BLOCK_ID + '="' + blockId + '"]'); - - if (!blockNode) { - return; - } - - blockNode.innerHTML = blocks[blockId].html; + this._setScheduleBlockPreview(blockSelector, blockPreview); this._updateIframeHeight(); }, this)); @@ -306,6 +304,25 @@ YUI.add('ezs-browserview', function (Y) { }, /** + * Updates the preview of schedule blocks. + * + * @method _setScheduleBlockPreview + * @protected + * @param selector {String} selector of schedule block + * @param blockPreview {HTML} the block preview + */ + _setScheduleBlockPreview: function (selector, blockPreview) { + var preview = Y.one(SELECTOR_PREVIEW_IFRAME).getDOMNode().contentDocument, + blockNode = preview.querySelector(selector); + + if (!blockNode) { + return; + } + + blockNode.innerHTML = blockPreview; + }, + + /** * The update preview callback to be fired after timeout. * Check if user is previewing version and updates correct preview * @@ -336,14 +353,12 @@ YUI.add('ezs-browserview', function (Y) { versionPreviewUrl = this.get('versionPreviewUrl'), versionPreviewEnabled = false; - if (!iframe.getDOMNode().contentDocument) { - this._showLoadingScreen(); + iframePath = this._getIframePath(); + if (!iframePath) { return; } - iframePath = iframe.getDOMNode().contentWindow.location.pathname; - if (this._getLandingPageFieldKey(version.get('fields')) && iframePath.indexOf(VERSION_PREVIEW_URL_PREFIX) > -1) { this._versionPreviewLoadHandler = iframe.on('load', this._getLandingPageVersionPreviewData, this); } else if (this._versionPreviewLoadHandler) { @@ -360,7 +375,7 @@ YUI.add('ezs-browserview', function (Y) { versionPreviewEnabled = true; } - if (versionPreviewUrl === iframeUrl || versionPreviewUrl === iframePath) { + if (versionPreviewUrl === iframeUrl || this._areSameIframePath(versionPreviewUrl, iframePath)) { this._hideLoadingScreen(); return; @@ -371,6 +386,35 @@ YUI.add('ezs-browserview', function (Y) { }, /** + * Checks if version url and iframe path are same. + * + * @protected + * @method _areSameIframePath + * @param versionPreviewUrl {String} version preview url + * @param iframePath {String} iframe path + */ + _areSameIframePath: function (versionPreviewUrl, iframePath) { + return versionPreviewUrl === iframePath; + }, + + /** + * Gets the iframe path. + * + * @protected + * @method _getIframePath + */ + _getIframePath: function () { + var iframe = this.get('previewWindow').getDOMNode(), + iframeDocument = iframe.contentDocument; + + if (!iframeDocument) { + return null; + } + + return iframe.contentWindow.location.pathname; + }, + + /** * Once the iframe with version preview is loaded * it starts updating version preview data * @@ -412,30 +456,43 @@ YUI.add('ezs-browserview', function (Y) { * @param event {Object} event facade */ _setupPreviewBlocks: function (event) { - var preview = this.get('previewWindow').getDOMNode().contentDocument, + var preview = this.get('previewWindow').getDOMNode().contentWindow, zones = event.newVal; if (!preview) { return; } - Object.keys(zones).forEach(function (zoneId) { - var zoneNode = preview.querySelector('[' + ATTR_ZONE + '="' + zoneId + '"]'), - blockNodes; + Object.keys(zones).forEach(Y.bind(function (zoneId) { + this._setBlockAttribute(zones[zoneId], zoneId); + }, this)); + }, - if (!zoneNode) { - return; - } + /** + * Sets the attribute to blocks in the zone. + * + * @method _setBlockAttribute + * @protected + * @param zoneBlockIds {Array} zone block ids + * @param zoneId {String} the id of zone + */ + _setBlockAttribute: function (zoneBlockIds, zoneId) { + var preview = this.get('previewWindow').getDOMNode().contentDocument, + zoneNode = preview.querySelector('[' + ATTR_ZONE + '="' + zoneId + '"]'), + blockNodes; - blockNodes = [].slice.call(zoneNode.querySelectorAll(SELECTOR_BLOCK)); + if (!zoneNode) { + return; + } - zones[zoneId].forEach(function (blockId, index) { - if (!blockNodes[index]) { - return; - } + blockNodes = [].slice.call(zoneNode.querySelectorAll(SELECTOR_BLOCK)); - blockNodes[index].setAttribute(ATTR_BLOCK_ID, blockId); - }); + zoneBlockIds.forEach(function (blockId, index) { + if (!blockNodes[index]) { + return; + } + + blockNodes[index].setAttribute(ATTR_BLOCK_ID, blockId); }); }, @@ -489,14 +546,13 @@ YUI.add('ezs-browserview', function (Y) { }, /** - * Updates the height of preview iframe + * Updates the loading screen state. * * @protected - * @method _updateIframeHeight + * @method _updateLoadingScreenState + * @return {eZS.AppView} the view itself */ - _updateIframeHeight: function () { - this.constructor.superclass._updateIframeHeight.apply(this, arguments); - + _updateLoadingScreenState: function () { if (!this.get('actionbar').getInformationPanel().checkHasAllInformation()) { this._showLoadingScreen(); } diff --git a/Resources/public/js/views/ezs-multidomainbrowserview.js b/Resources/public/js/views/ezs-multidomainbrowserview.js new file mode 100644 index 0000000..5fe2179 --- /dev/null +++ b/Resources/public/js/views/ezs-multidomainbrowserview.js @@ -0,0 +1,234 @@ +/* + * Copyright (C) eZ Systems AS. All rights reserved. + * For full copyright and license information view LICENSE file distributed with this source code. + */ +YUI.add('ezs-multidomainbrowserview', function (Y) { + 'use strict'; + /** + * Provides the StudioUI multi domain browser view class + * + * @module ezs-multidomainbrowserview + */ + Y.namespace('eZS'); + + var ATTR_BLOCK_ID = 'data-block-id', + ATTR_ZONE = 'data-studio-zone', + SELECTOR_BLOCK = '.landing-page__block', + VERSION_PREVIEW_URL_PREFIX = '/content/versionview/'; + + /** + * The StudioUI multi domain browser view + * + * @namespace eZS + * @class MultiDomainBrowserView + * @constructor + * @extends eZS.BrowserView + */ + Y.eZS.MultiDomainBrowserView = Y.Base.create('multiDomainBrowserView', Y.eZS.BrowserView, [], { + initializer: function () { + this._updateIframeDataHandler = null; + + this.get('container').addClass(this._generateViewClassName(Y.eZS.BrowserView.NAME)); + + this.on('iframeDataChange', this._eventHandlerLoad, this); + this.on('iframeDataChange', this._tryUpdateIframeHeight, this); + + this._postMassageHandler = Y.on('message', Y.bind(function (event) { + this.set('iframeData', event._event.data); + }, this)); + }, + + /** + * Adds event listener to iframe on load. + * + * @protected + * @method _attachIframeLoadEventHandlers + * @param iframe {Y.Node} the iframe node + */ + _attachIframeLoadEventHandlers: function (iframe) { + this._updateIframeDataHandler = iframe.on('load', this._updateIframeData, this); + }, + + /** + * Updates the iframe data. + * + * @protected + * @method _updateIframeData + * @param event {Object} event facade + */ + _updateIframeData: function (event) { + var origin = this._getActiveSiteaccessRootUrl(); + + event.target.getDOMNode().contentWindow.postMessage('data', origin); + }, + + /** + * Updates the preview of schedule blocks. + * + * @method _setScheduleBlockPreview + * @protected + * @param selector {String} selector of schedule block + * @param blockPreview {HTML} the block preview + */ + _setScheduleBlockPreview: function (selector, blockPreview) { + var preview = this.get('previewWindow').getDOMNode().contentWindow, + origin = this._getActiveSiteaccessRootUrl(), + data = { + content: { + selector: selector, + content: blockPreview + } + }; + + preview.postMessage(data, origin); + }, + + /** + * Sets the attribute to blocks in the zone. + * + * @method _setBlockAttribute + * @protected + * @param zoneBlockIds {Array} zone block ids + * @param zoneId {String} the id of zone + */ + _setBlockAttribute: function (zoneBlockIds, zoneId) { + var preview = this.get('previewWindow').getDOMNode().contentWindow, + selectorZone = '[' + ATTR_ZONE + '="' + zoneId + '"]', + origin = this._getActiveSiteaccessRootUrl(); + + zoneBlockIds.forEach(Y.bind(function (blockId, index) { + var data = { + blockAttribute: { + selectorZone: selectorZone, + selectorBlock: SELECTOR_BLOCK, + attributeName: ATTR_BLOCK_ID, + attributeValue: blockId, + index: index + } + }; + + preview.postMessage(data, origin); + }, this)); + }, + + /** + * Return the root url for active siteaccess. + * + * @method _getActiveSiteaccessRootUrl + * @protected + * @return {String} the root url for active siteaccess + */ + _getActiveSiteaccessRootUrl: function () { + return this.get('configStudioSiteaccesses')[this.get('studioActiveSiteaccess')].urlRoot; + }, + + /** + * Event handler for the iframe's load event. + * + * @protected + * @method _eventHandlerLoad + * @param event {Object} event facade + */ + _eventHandlerLoad: function (event) { + var iframePath = event.newVal.pathName, + iframeSrc = event.newVal.href, + isVersionPreview = iframePath.indexOf(VERSION_PREVIEW_URL_PREFIX) > -1; + + if (isVersionPreview) { + iframeSrc = this.get('previewUrl'); + + this._updateInformationPanel(); + } + + if (!isVersionPreview) { + this.set('versionPreviewEnabled', false); + + if (iframePath.indexOf(this.get('studioActiveSiteaccess')) !== -1) { + iframePath = iframePath.substring(this.get('studioActiveSiteaccess').length + 1, iframePath.length); + } + + this.set('previewUrl', iframeSrc); + + /** + * Fired when a website is loaded into preview mode/iframe. + * It's checking whether a currently viewed page has the pageFieldType + * + * @event iframePreviewLoad + * @param locationPath {String} a pathname of currently visited page (from window.location object) + */ + this.fire('iframePreviewLoad', {locationPath: iframePath}); + } + + /** + * Fired to enable preview buttons in the top action bar. + * Listened by eZS.TopActionBarView + * + * @event enablePreviewButtons + */ + this.get('actionbar').fire('enablePreviewButtons'); + }, + + /** + * Gets the iframe body height. + * + * @protected + * @method _getIframeBodyHeight + */ + _getIframeBodyHeight: function () { + var iframeData = this.get('iframeData'); + + if (!iframeData) { + return 0; + } + + return iframeData.height; + }, + + /** + * Gets the iframe path. + * + * @protected + * @method _getIframePath + */ + _getIframePath: function () { + var iframeData = this.get('iframeData'); + + if (!iframeData) { + return null; + } + + return iframeData.href; + }, + + /** + * Checks if version url and iframe path are same. + * In multi domain configuration it must return false. + * + * @protected + * @method _areSameIframePath + * @param versionPreviewUrl {String} version preview url + * @param iframePath {String} iframe path + */ + _areSameIframePath: function (versionPreviewUrl, iframePath) { + return false; + }, + + destructor: function () { + if(this._postMassageHandler) { + this._postMassageHandler.detach(); + } + + this._updateIframeDataHandler.detach(); + } + }, { + ATTRS: { + /** + * The data sent by iframe in postMessage + * + * @attribute iframeData + * @type Object + */ + iframeData: {} + } + }); +}); diff --git a/Resources/public/js/views/ezs-topactionbarview.js b/Resources/public/js/views/ezs-topactionbarview.js index b4a6ed2..7482cff 100644 --- a/Resources/public/js/views/ezs-topactionbarview.js +++ b/Resources/public/js/views/ezs-topactionbarview.js @@ -13,6 +13,7 @@ YUI.add('ezs-topactionbarview', function (Y) { var ATTR_STATE = 'data-content-state', CLASS_VISIBLE = 'is-visible', + CLASS_TRANSPARENT = 'is-transparent', SELECTOR_TOOLBAR_OVERLAY = '.ezs-toolbar__overlay', STATE_NAMES = { 0: 'view', @@ -77,14 +78,13 @@ YUI.add('ezs-topactionbarview', function (Y) { * @method toggleOverlay * @param visible {Boolean} should show overlay? */ - toggleOverlay: function (visible) { - var methodName = visible ? 'addClass' : 'removeClass'; + toggleOverlay: function (visible, isTransparent) { + var methodName = visible ? 'addClass' : 'removeClass', + transparentMethodName = isTransparent ? 'addClass' : 'removeClass', + overlay = this.get('container').one(SELECTOR_TOOLBAR_OVERLAY); - /** - * This overlay has to allow to display buttons on top of it - * That's why it is an empty div - */ - this.get('container').one(SELECTOR_TOOLBAR_OVERLAY)[methodName](CLASS_VISIBLE); + overlay[methodName](CLASS_VISIBLE); + overlay[transparentMethodName](CLASS_TRANSPARENT); }, /** diff --git a/Resources/public/js/views/navigation/ezs-dynamicnavigationitemview.js b/Resources/public/js/views/navigation/ezs-dynamicnavigationitemview.js index 03835c8..cc6d012 100644 --- a/Resources/public/js/views/navigation/ezs-dynamicnavigationitemview.js +++ b/Resources/public/js/views/navigation/ezs-dynamicnavigationitemview.js @@ -53,16 +53,25 @@ YUI.add('ezs-dynamicnavigationitemview', function (Y) { * * @protected * @method _updateAnchor - * @param {Object} Event facade + * @param event {Object} event facade */ _updateAnchor: function (event) { var app = this.get('app'), siteaccess = this.get('siteaccess'), - siteaccessUrl = siteaccess.indexOf(SLASH) === 0 ? siteaccess : SLASH + siteaccess, - url = (siteaccess === app.get('studioActiveSiteaccess')) ? - siteaccessUrl + event.newVal : - siteaccessUrl + this.get('rootPath'); + siteaccessRootUrl = app.get('config.studioSiteaccesses')[siteaccess].urlRoot, + url; + if (siteaccessRootUrl[siteaccessRootUrl.length - 1] === SLASH) { + siteaccessRootUrl = siteaccessRootUrl.substring(0, siteaccessRootUrl.length - 1); + } + + if (siteaccess === app.get('studioActiveSiteaccess')) { + url = siteaccessRootUrl + event.newVal; + } else { + url = siteaccessRootUrl + SLASH; + } + + this.get('route').params.previewContentUrl = url; this.get('container').one(SELECTOR_LINK).set('href', app.routeUri('studioPreview', {previewContentUrl: url})); }, diff --git a/Resources/public/js/views/services/ezs-browserviewservice.js b/Resources/public/js/views/services/ezs-browserviewservice.js index 6019f47..ad2c0b0 100644 --- a/Resources/public/js/views/services/ezs-browserviewservice.js +++ b/Resources/public/js/views/services/ezs-browserviewservice.js @@ -263,22 +263,13 @@ YUI.add('ezs-browserviewservice', function (Y) { var app = this.get('app'), siteaccesses = Object.keys(app.get('config.studioSiteaccesses')), activeSiteaccess = app.get('studioActiveSiteaccess') || siteaccesses[0], - siteaccessesFound = siteaccesses.filter(function (access) { - return locationPath.indexOf(SLASH + access) !== -1; - }), - activeSiteaccessPath; + siteaccessRootUrl = app.get('config.studioSiteaccesses')[activeSiteaccess].urlRoot; - if (siteaccessesFound.length) { - activeSiteaccess = siteaccessesFound[0]; + if (siteaccessRootUrl[siteaccessRootUrl.length - 1] === SLASH) { + siteaccessRootUrl = siteaccessRootUrl.substring(0, siteaccessRootUrl.length - 1); } - activeSiteaccessPath = SLASH + activeSiteaccess; - - if (locationPath === SLASH) { - locationPath = activeSiteaccessPath + SLASH; - } else if (locationPath.indexOf(activeSiteaccessPath) === -1) { - locationPath = activeSiteaccessPath + locationPath; - } + locationPath = siteaccessRootUrl + locationPath; return locationPath; }, @@ -297,10 +288,8 @@ YUI.add('ezs-browserviewservice', function (Y) { promise = new Y.Promise(Y.bind(function (resolve, reject) { Y.io(app.get('apiRoot') + this.get('hasLandingPageFieldTypeUrl'), { data: { - url: path - }, - headers: { - 'X-Siteaccess': app.get('studioActiveSiteaccess') + url: path, + siteAccessName: app.get('studioActiveSiteaccess') }, on: { success: function (id, xhr) { @@ -432,7 +421,7 @@ YUI.add('ezs-browserviewservice', function (Y) { try { Y.io(contentVersionsUrl, { - data: {siteaccessName: app.get('studioActiveSiteaccess')}, + data: {siteAccessName: app.get('studioActiveSiteaccess')}, on: { success: function (id, xhr) { resolve(JSON.parse(xhr.response)); @@ -540,7 +529,7 @@ YUI.add('ezs-browserviewservice', function (Y) { contentVersionsList.reset(contentVersionsData.versions); contentInfo.author = user.name; - contentInfo.link = [window.location.origin, previewUrl].join(''); + contentInfo.link = previewUrl; this.set('contentInfo', contentInfo); target.set('previewContentInfo', contentInfo); @@ -923,7 +912,8 @@ YUI.add('ezs-browserviewservice', function (Y) { 'previewedContentType': this.get('contentType'), 'previewedVersion': this.get('version'), 'versionPreviewUrl': this.get('versionPreviewUrl'), - 'studioActiveSiteaccess': app.get('studioActiveSiteaccess') + 'studioActiveSiteaccess': app.get('studioActiveSiteaccess'), + 'configStudioSiteaccesses': app.get('config.studioSiteaccesses') }; }, diff --git a/Resources/public/js/views/services/ezs-dynamiclandingpageeditorviewservice.js b/Resources/public/js/views/services/ezs-dynamiclandingpageeditorviewservice.js index 841ce8b..66e5572 100644 --- a/Resources/public/js/views/services/ezs-dynamiclandingpageeditorviewservice.js +++ b/Resources/public/js/views/services/ezs-dynamiclandingpageeditorviewservice.js @@ -115,6 +115,68 @@ YUI.add('ezs-dynamiclandingpageeditorviewservice', function (Y) { }, /** + * Load the parent content path + * + * @method _getParentContentPath + * @protected + * @return promise {Y.Promise} + */ + _getParentContentPath: function () { + var locationPath = this.get('parentLocation').get('pathString'); + + return new Y.Promise(Y.bind(function (resolve, reject) { + var errorConfig = { + message: 'Cannot load parent content path', + identifier: 'error-content-parent-path' + }; + + Y.io(this.get('getUserFriendlyUrl').replace('{locationPath}', locationPath), { + data: { + custom: false, + siteAccessName: this.get('app').get('studioActiveSiteaccess') + }, + on: { + success: function (id, xhr) { + resolve(JSON.parse(xhr.response).friendlyUrl); + }, + failure: function (id, xhr) { + reject(errorConfig, xhr); + } + } + }); + }, this)); + }, + + /** + * Load the parent location + * + * @method _getParentLocation + * @protected + * @return promise {Y.Promise} + */ + _getParentLocation: function () { + var parentLocation = this.get('parentLocation'), + capi = this.get('capi'); + + return new Y.Promise(function (resolve, reject) { + parentLocation.load({api: capi}, function (error, response) { + var errorConfig = { + message: 'Cannot load location data', + identifier: 'load-location-data' + }; + + if (error) { + reject(errorConfig, response); + + return; + } + + resolve(response); + }); + }); + }, + + /** * Load the parent content model from given id * * @method _getParentContentModelBasedOnId @@ -233,10 +295,30 @@ YUI.add('ezs-dynamiclandingpageeditorviewservice', function (Y) { this.set('parentLocationPath', parentLocationPath); app.set('studioActiveSiteaccess', siteaccess); + if (this.get('parentLocation').get('id')) { + this._getParentLocation() + .then(Y.bind(this._getParentContentPath, this)) + .then(Y.bind(this._setParentContentPath, this)) + .catch(Y.bind(this._handleError, this)); + } else { + this._setParentContentPath(app.get('config.studioSiteaccesses')[siteaccess].urlRoot); + } + this._initModels(next); }, /** + * Sets the parent content path + * + * @method _setParentContentPath + * @protected + * @param friendlyUrl {String} the friendly url fo parent content + */ + _setParentContentPath: function (friendlyUrl) { + this.set('parentLocationPath', friendlyUrl); + }, + + /** * Adds a root path to a preview URL path if a previewed page is a homepage * * @method _addRootUriToParentLocationPath @@ -461,7 +543,22 @@ YUI.add('ezs-dynamiclandingpageeditorviewservice', function (Y) { */ version: { cloneDefaultValue: false - } + }, + + /** + * The AJAX request url to get user friendly url + * The URL string contains a placeholder, where location's pathString is placed ({locationPath}). + * + * @attribute getUserFriendlyUrl + * @default '/studio/content/locations{locationPath}friendlyurl' + * @example '/studio/content/locations/1/2/95/friendlyurl' + * @type String + * @writeOnce 'initOnly' + */ + getUserFriendlyUrl: { + value: '/studio/content/locations{locationPath}friendlyurl', + writeOnce: 'initOnly' + }, } }); diff --git a/Resources/public/js/views/services/plugins/ezs-contentcreateredirectplugin.js b/Resources/public/js/views/services/plugins/ezs-contentcreateredirectplugin.js index 49da13a..26493af 100644 --- a/Resources/public/js/views/services/plugins/ezs-contentcreateredirectplugin.js +++ b/Resources/public/js/views/services/plugins/ezs-contentcreateredirectplugin.js @@ -11,7 +11,8 @@ YUI.add('ezs-contentcreateredirectplugin', function (Y) { */ Y.namespace('eZS.Plugin'); - var SERVICES = [ + var SLASH = '/', + SERVICES = [ 'landingPageCreatorService', 'dynamicLandingPageCreatorViewService', 'dynamicLandingPageEditorViewService' @@ -73,7 +74,7 @@ YUI.add('ezs-contentcreateredirectplugin', function (Y) { Y.io(this.get('urlAliasRefListUrl').replace('{location}', content.MainLocation._href), { data: { custom: false, - siteaccessName: app.get('studioActiveSiteaccess') + siteAccessName: app.get('studioActiveSiteaccess') }, headers: {Accept: 'application/vnd.ez.api.UrlAliasRefList+json'}, on: { @@ -117,8 +118,15 @@ YUI.add('ezs-contentcreateredirectplugin', function (Y) { }, this)); }, redirectUser = function (path) { + var activeSiteaccess = app.get('studioActiveSiteaccess'), + siteaccessRootUrl = app.get('config.studioSiteaccesses')[activeSiteaccess].urlRoot; + + if (siteaccessRootUrl[siteaccessRootUrl.length - 1] === SLASH) { + siteaccessRootUrl = siteaccessRootUrl.substring(0, siteaccessRootUrl.length - 1); + } + host.set('useCustomPublishRedirection', false); - app.navigate(app.routeUri('studioPreview', {previewContentUrl: app.get('studioActiveSiteaccess') + path})); + app.navigateTo('studioPreview', {previewContentUrl: siteaccessRootUrl + path}); }; if (error) { diff --git a/Resources/public/js/views/services/plugins/ezs-studionavigationhubplugin.js b/Resources/public/js/views/services/plugins/ezs-studionavigationhubplugin.js index e273990..e5eae6e 100644 --- a/Resources/public/js/views/services/plugins/ezs-studionavigationhubplugin.js +++ b/Resources/public/js/views/services/plugins/ezs-studionavigationhubplugin.js @@ -67,7 +67,10 @@ YUI.add('ezs-studionavigationhubplugin', function (Y) { this._isUsingAppRoutes = true; }, this); - host.get('app').on('browserView:previewContentLocationIdChange', this._setLocationIdByPreview, this); + host.get('app').on([ + 'browserView:previewContentLocationIdChange', + 'multiDomainBrowserView:previewContentLocationIdChange' + ], this._setLocationIdByPreview, this); this._originalLoadFunction = host._load; @@ -110,11 +113,17 @@ YUI.add('ezs-studionavigationhubplugin', function (Y) { locationHash = window.location.hash, siteaccesses = Object.keys(app.get('config.studioSiteaccesses')), defaultSiteaccess = siteaccesses[0], - activeSiteaccess = defaultSiteaccess, - activeSiteaccessPath, - siteaccessesFound = siteaccesses.filter(function (access) { - return locationHash.indexOf(encodeURIComponent(SLASH + access)) !== -1; - }); + activeSiteaccess = app.get('studioActiveSiteaccess') || defaultSiteaccess, + siteaccessRootUrl, + siteaccessesFound = siteaccesses.filter(Y.bind(function (access) { + var siteaccessUrl = this._getRootUrlBySiteaccess(access); + + if (siteaccessUrl[siteaccessUrl.length - 1] !== SLASH) { + siteaccessUrl = siteaccessUrl + SLASH; + } + + return locationHash.indexOf(encodeURIComponent(siteaccessUrl)) !== -1; + }, this)); if (event.prevVal === event.newVal || event.newVal !== NAVIGATION_ZONE_STUDIO || this._isUsingAppRoutes) { this._isUsingAppRoutes = false; @@ -126,24 +135,43 @@ YUI.add('ezs-studionavigationhubplugin', function (Y) { activeSiteaccess = siteaccessesFound[0]; } - app.set('studioActiveSiteaccess', activeSiteaccess); + siteaccessRootUrl = this._getRootUrlBySiteaccess(activeSiteaccess); - activeSiteaccessPath = activeSiteaccess.indexOf(SLASH) === 0 ? activeSiteaccess : SLASH + activeSiteaccess; + app.set('studioActiveSiteaccess', activeSiteaccess); if (selectedLocationId) { this._loadLocationAlias(selectedLocationId, function (alias) { - app.navigateTo('studioPreview', {previewContentUrl: activeSiteaccessPath + alias}); + if (siteaccessRootUrl[siteaccessRootUrl.length - 1] === SLASH) { + siteaccessRootUrl = siteaccessRootUrl.substring(0, siteaccessRootUrl.length - 1); + } + + app.navigateTo('studioPreview', {previewContentUrl: siteaccessRootUrl + alias}); }); return; } - if (locationHash.indexOf(encodeURIComponent(activeSiteaccess)) === -1) { - app.navigateTo('studioPreview', {previewContentUrl: activeSiteaccessPath + SLASH}); + if (locationHash.indexOf(encodeURIComponent(siteaccessRootUrl)) === -1) { + if (siteaccessRootUrl[siteaccessRootUrl.length - 1] !== SLASH) { + siteaccessRootUrl = siteaccessRootUrl + SLASH; + } + app.navigateTo('studioPreview', {previewContentUrl: siteaccessRootUrl}); } }, /** + * Return the url root for siteaccess + * + * @method _getRootUrlBySiteaccess + * @protected + * @param siteaccess {String} siteaccess + * @return {String} the siteaccess root url + */ + _getRootUrlBySiteaccess: function (siteaccess) { + return this.get('host').get('app').get('config.studioSiteaccesses')[siteaccess].urlRoot; + }, + + /** * Redirects to the first item of the active zone * * @method _navigateToFirstItemRoute @@ -169,15 +197,17 @@ YUI.add('ezs-studionavigationhubplugin', function (Y) { */ _createNavigationItem: function (siteaccess) { var host = this.get('host'), + app = host.get('app'), menuItems = this.get('menuItems'), - siteaccessPath = siteaccess.indexOf(SLASH) === 0 ? siteaccess : SLASH + siteaccess, + siteaccessRootUrl = app.get('config.studioSiteaccesses')[siteaccess].urlRoot, + previewContentUrl = siteaccessRootUrl[siteaccessRootUrl.length - 1] !== SLASH ? siteaccessRootUrl + SLASH : siteaccessRootUrl, item = host._getItem(this.get('itemView'), { title: 'Siteaccess: ' + siteaccess, identifier: 'studio-' + siteaccess, siteaccess: siteaccess, route: { name: 'studioPreview', - params: {previewContentUrl: siteaccessPath + SLASH} + params: {previewContentUrl: previewContentUrl} }, app: host.get('app') }); @@ -303,7 +333,7 @@ YUI.add('ezs-studionavigationhubplugin', function (Y) { Y.io(this.get('urlAliasRefListUrl').replace('{location}', locationId), { data: { custom: false, - siteaccessName: app.get('studioActiveSiteaccess') + siteAccessName: app.get('studioActiveSiteaccess') }, headers: {Accept: 'application/vnd.ez.api.UrlAliasRefList+json'}, on: { diff --git a/Resources/public/js/views/timeline/ezs-timelineview.js b/Resources/public/js/views/timeline/ezs-timelineview.js index e369743..ea863bb 100644 --- a/Resources/public/js/views/timeline/ezs-timelineview.js +++ b/Resources/public/js/views/timeline/ezs-timelineview.js @@ -22,7 +22,6 @@ YUI.add('ezs-timelineview', function (Y) { CLASS_QUEUE_POPUP_VISIBLE = CLASS_TIMELINE + '--queue-popup-visible', CLASS_QUEUELIST_BTN_DISABLED = CLASS_TIMELINE + '__queue-list--disabled', CLASS_SLIDER_INPUTS_DISABLED = CLASS_TIMELINE + '__slider-inputs--disabled', - SELECTOR_PREVIEW_IFRAME = '#ezs-studio-preview', SELECTOR_TIMELINE = '.' + CLASS_TIMELINE, SELECTOR_POPUP = SELECTOR_TIMELINE + '__popup', SELECTOR_INDICATORS = SELECTOR_TIMELINE + '__indicators', @@ -88,7 +87,6 @@ YUI.add('ezs-timelineview', function (Y) { this._mouseMoveIframeEventHandler = null; this._mouseUpIframeEventHandler = null; this._clickOutslideSliderHandler = null; - this._clickOutslideSliderOnIframeHandler = null; /** * Stores the X position of user cursor when user moves the slider * @@ -484,16 +482,13 @@ YUI.add('ezs-timelineview', function (Y) { * @param event {Object} event facade */ _attachEventsOnMoveSlider: function (event) { - var iframe, - keyCode = event.keyCode || event.which, + var keyCode = event.keyCode || event.which, areInputsDisabled = this.get('container').one(SELECTOR_SLIDER_INPUTS).hasClass(CLASS_SLIDER_INPUTS_DISABLED); if (keyCode === KEYCODE_RIGHT_BTN || !areInputsDisabled) { return; } - iframe = Y.one(SELECTOR_PREVIEW_IFRAME).getDOMNode().contentWindow.document; - this._positionX = event.clientX; this._startPositionX = event.clientX; @@ -502,8 +497,18 @@ YUI.add('ezs-timelineview', function (Y) { this._mouseMoveEventHandler = Y.on('mousemove', Y.bind(this._moveSlider, this)); this._mouseUpEventHandler = Y.on('mouseup', Y.bind(this._detachEventsOnStopMoveSlider, this)); - this._mouseMoveIframeEventHandler = Y.on('mousemove', Y.bind(this._moveSlider, this), iframe); - this._mouseUpIframeEventHandler = Y.on('mouseup', Y.bind(this._detachEventsOnStopMoveSlider, this), iframe); + window.clearTimeout(this._showOverlayTimeout); + + this._showOverlayTimeout = window.setTimeout(Y.bind(function () { + /** + * An event fired to show overlay. + * Listened in the eZS.AppView + * + * @event showOverlay + * @param isTransparent {Boolean} is the overlay transparent + */ + this.fire('showOverlay', {isTransparent : true}); + }, this), TIMEOUT); }, /** @@ -527,6 +532,19 @@ YUI.add('ezs-timelineview', function (Y) { } }); + window.clearTimeout(this._hideOverlayTimeout); + + this._hideOverlayTimeout = window.setTimeout(Y.bind(function () { + /** + * An event fired to hide overlay. + * Listened in the eZS.AppView + * + * @event hideOverlay + * @param isTransparent {Boolean} is the overlay transparent + */ + this.fire('hideOverlay', {isTransparent : true}); + }, this), TIMEOUT); + if (!event) { return; } @@ -941,14 +959,12 @@ YUI.add('ezs-timelineview', function (Y) { * @param event {Object} event facade */ _enableTimeInputs: function (event) { - var inputsWrapper = this.get('container').one(SELECTOR_SLIDER_INPUTS), - iframe = Y.one(SELECTOR_PREVIEW_IFRAME).getDOMNode().contentWindow.document; + var inputsWrapper = this.get('container').one(SELECTOR_SLIDER_INPUTS); this._previousSelectedTime = this.get('selectedTime'); this._toggleSliderInputs(false); this._clickOutslideSliderHandler = inputsWrapper.on('clickoutside', Y.bind(this._handleTimelineSliderClickOutside, this)); - this._clickOutslideSliderOnIframeHandler = Y.on('tap', Y.bind(this._handleTimelineSliderClickOutside, this), iframe); }, /** @@ -1015,7 +1031,6 @@ YUI.add('ezs-timelineview', function (Y) { }); this._clickOutslideSliderHandler.detach(); - this._clickOutslideSliderOnIframeHandler.detach(); }, /** @@ -1200,10 +1215,6 @@ YUI.add('ezs-timelineview', function (Y) { if (this._clickOutslideSliderHandler) { this._clickOutslideSliderHandler.detach(); } - - if (this._clickOutslideSliderOnIframeHandler) { - this._clickOutslideSliderOnIframeHandler.detach(); - } } }, { ATTRS: { diff --git a/Resources/views/multidomain.script.twig b/Resources/views/multidomain.script.twig index 92b4adf..04610aa 100644 --- a/Resources/views/multidomain.script.twig +++ b/Resources/views/multidomain.script.twig @@ -1,20 +1,21 @@ diff --git a/Tests/js/views/assets/ezs-appview-tests.js b/Tests/js/views/assets/ezs-appview-tests.js index 8e6eb72..5309492 100644 --- a/Tests/js/views/assets/ezs-appview-tests.js +++ b/Tests/js/views/assets/ezs-appview-tests.js @@ -110,7 +110,7 @@ YUI.add('ezs-appview-tests', function (Y) { Y.Mock.expect(this.bar, { method: 'toggleOverlay', - args: [Y.Mock.Value.Boolean] + args: [Y.Mock.Value.Boolean, Y.Mock.Value.Boolean] }); this.locationPath = '/Tests/js/views/assets/iframeTest.htm'; diff --git a/Tests/js/views/assets/ezs-browserview-tests.js b/Tests/js/views/assets/ezs-browserview-tests.js index f32f3bf..9629bcd 100644 --- a/Tests/js/views/assets/ezs-browserview-tests.js +++ b/Tests/js/views/assets/ezs-browserview-tests.js @@ -17,10 +17,17 @@ YUI.add('ezs-browserview-tests', function (Y) { setUp: function () { this.versionModel = new Y.Model(); + this.bar = new Y.Mock(); + + Y.Mock.expect(this.bar, { + method: 'removeTarget', + args: [Y.Mock.Value.Object] + }); this.view = new Y.eZS.BrowserView({ container: '.container', - previewedVersion: this.versionModel + previewedVersion: this.versionModel, + actionbar: this.bar, }); }, @@ -170,7 +177,7 @@ YUI.add('ezs-browserview-tests', function (Y) { previewedVersion.set('status', VERSION_STATUS_DRAFT); view = view.render(); - view.on('editVersion', function (event) { + view.on('studioEditVersion', function (event) { isEventFired = true; Y.Assert.areSame(expectedPreviewedVersionId, event.versionId, 'Should pass correct version id'); @@ -184,21 +191,25 @@ YUI.add('ezs-browserview-tests', function (Y) { 'Should set up view properties correctly when iframe content is loaded': function () { var view = this.view, - that = this, iframe; - view.after('iframePreviewLoad', function (event) { - Y.Assert.areEqual(that.locationPath, event.locationPath, 'The locationPath param should be passed correctly'); - }); + view.after('iframePreviewLoad', Y.bind(function (event) { + Y.Assert.areEqual(this.locationPath, event.locationPath, 'The locationPath param should be passed correctly'); + }, this)); + + iframe = view.render().get('container').one(SELECTOR_APP_PREVIEW); + iframe.on('load', Y.bind(function () { + this.resume(Y.bind(function () { + Y.Assert.areEqual( + this.locationPath, + view.get('previewUrl'), + 'The `previewUrl` param should be passed correctly' + ); + }, this)); + }, this)); - iframe = view.render().get('container').one('.ezs-appview__workspace__preview'); - iframe.on('load', function () { - that.resume(function () { - Y.Assert.areEqual(that.locationPath, view.get('previewUrl'), 'The `previewUrl` param should be passed correctly'); - }); - }); iframe.set('src', this.locationPath); - that.wait(); + this.wait(); }, 'Should update info in the information panel': function () { diff --git a/Tests/js/views/navigation/assets/ezs-dynamicnavigationitemview-tests.js b/Tests/js/views/navigation/assets/ezs-dynamicnavigationitemview-tests.js index 8ae8d0a..89d0803 100644 --- a/Tests/js/views/navigation/assets/ezs-dynamicnavigationitemview-tests.js +++ b/Tests/js/views/navigation/assets/ezs-dynamicnavigationitemview-tests.js @@ -66,7 +66,12 @@ YUI.add('ezs-dynamicnavigationitemview-tests', function (Y) { this.siteaccess = 'rock'; this.app = new Y.Mock(); this.appAttrs = { - studioActiveSiteaccess: this.siteaccess + studioActiveSiteaccess: this.siteaccess, + 'config.studioSiteaccesses': { + rock: { + urlRoot: 'http://ez.no' + } + } }; Y.Mock.expect(this.app, { @@ -118,11 +123,17 @@ YUI.add('ezs-dynamicnavigationitemview-tests', function (Y) { Y.Assert.isFalse(view.get('container').hasClass(CLASS_ACTIVE), 'The item should not be selected'); }, - 'Should update an anchor when URL alias (siteaccess without `/` at the beginning) is changed': function () { + 'Should update an anchor when URL alias is changed': function () { var alias = '/bon/jovi/crush', - origin = Y.UA.phantomjs ? 'http://127.0.0.1:7010' : 'http://127.0.0.1:7020', - expectedHref = origin + PREVIEW_ROUTE + encodeURIComponent('/' + this.siteaccess + alias), - view = this.view.render(); + origin = window.location.origin, + expectedPreviewUrl = this.appAttrs['config.studioSiteaccesses'].rock.urlRoot + alias, + expectedHref = origin + PREVIEW_ROUTE + encodeURIComponent(expectedPreviewUrl), + view = this.view.render(), + route = { + params: { + previewContentUrl: 'Ace/Of/Spades' + } + }; Y.Mock.expect(this.app, { method: 'routeUri', @@ -134,6 +145,7 @@ YUI.add('ezs-dynamicnavigationitemview-tests', function (Y) { } }); + view.set('route', route); view.set('urlAliasPath', alias); Y.Assert.areSame( @@ -142,33 +154,10 @@ YUI.add('ezs-dynamicnavigationitemview-tests', function (Y) { 'The link href should be updated correctly' ); - Y.Mock.verify(this.app); - }, - - 'Should update an anchor when URL alias (siteaccess with `/` at the beginning) is changed': function () { - var alias = '/bon/jovi/crush', - origin = Y.UA.phantomjs ? 'http://127.0.0.1:7010' : 'http://127.0.0.1:7020', - expectedHref = origin + PREVIEW_ROUTE + encodeURIComponent('/' + this.siteaccess + alias), - view = this.view.render(); - - Y.Mock.expect(this.app, { - method: 'routeUri', - args: ['studioPreview', Y.Mock.Value.Object], - run: function (name, config) { - Y.Assert.isTrue(config.hasOwnProperty('previewContentUrl'), 'Should pass a correct config property'); - - return PREVIEW_ROUTE + encodeURIComponent(config.previewContentUrl); - } - }); - - this.appAttrs.studioActiveSiteaccess = '/' + this.appAttrs.studioActiveSiteaccess; - view.set('siteaccess', '/' + this.siteaccess); - view.set('urlAliasPath', alias); - Y.Assert.areSame( - expectedHref, - view.get('container').one(SELECTOR_LINK_DYNAMIC).get('href'), - 'The link href should be updated correctly' + expectedPreviewUrl, + view.get('route').params.previewContentUrl, + 'The preview content url should be updated' ); Y.Mock.verify(this.app); diff --git a/Tests/js/views/services/assets/ezs-browserviewservice-tests.js b/Tests/js/views/services/assets/ezs-browserviewservice-tests.js index ab72ace..53b70bc 100644 --- a/Tests/js/views/services/assets/ezs-browserviewservice-tests.js +++ b/Tests/js/views/services/assets/ezs-browserviewservice-tests.js @@ -9,7 +9,8 @@ YUI.add('ezs-browserviewservice-tests', function (Y) { studioActiveSiteaccess: 'site', 'config.studioSiteaccesses': { 'site': { - languages: ['eng-GB'] + languages: ['eng-GB'], + urlRoot: 'http://ez.no' } } }, @@ -73,7 +74,7 @@ YUI.add('ezs-browserviewservice-tests', function (Y) { 'getViewParameters should pass correct properties to a view': function () { var params = this.service.getViewParameters(), - expectedParamsCount = 9; + expectedParamsCount = 11; Y.Assert.isObject(params, 'getViewParameters() result should be an object'); Y.Assert.areEqual( @@ -277,7 +278,11 @@ YUI.add('ezs-browserviewservice-tests', function (Y) { service.on('previewUrlChange', Y.bind(function (event) { isPreviewUrlChanged = true; - Y.Assert.areSame('/' + this.activeSiteaccess + locationPath, event.newVal, 'The `previewUrl` value should be set correctly'); + Y.Assert.areSame( + APP_ATTRS['config.studioSiteaccesses'].site.urlRoot + locationPath, + event.newVal, + 'The `previewUrl` value should be set correctly' + ); }, this)); service.on('contentInfoChange', Y.bind(function (event) { @@ -288,7 +293,7 @@ YUI.add('ezs-browserviewservice-tests', function (Y) { return; } - link = [window.location.origin, '/', this.activeSiteaccess, locationPath].join(''); + link = [APP_ATTRS['config.studioSiteaccesses'].site.urlRoot, locationPath].join(''); isContentInfoValueChanged = true; diff --git a/Tests/js/views/services/plugins/assets/ezs-contentcreateredirectplugin-tests.js b/Tests/js/views/services/plugins/assets/ezs-contentcreateredirectplugin-tests.js index 848ea0f..ecae7e8 100644 --- a/Tests/js/views/services/plugins/assets/ezs-contentcreateredirectplugin-tests.js +++ b/Tests/js/views/services/plugins/assets/ezs-contentcreateredirectplugin-tests.js @@ -235,6 +235,11 @@ YUI.add('ezs-contentcreateredirectplugin-tests', function (Y) { } }); + Y.Mock.expect(this.app, { + method: 'onceAfter', + args: ['loadingChange', Y.Mock.Value.Function] + }); + this.service.set('useCustomPublishRedirection', false); this.service.fire('whatever:publishAction', { diff --git a/Tests/js/views/services/plugins/assets/ezs-studionavigationhubplugin-tests.js b/Tests/js/views/services/plugins/assets/ezs-studionavigationhubplugin-tests.js index 675e27d..b0b5f15 100644 --- a/Tests/js/views/services/plugins/assets/ezs-studionavigationhubplugin-tests.js +++ b/Tests/js/views/services/plugins/assets/ezs-studionavigationhubplugin-tests.js @@ -3,48 +3,11 @@ * For full copyright and license information view LICENSE file distributed with this source code. */ YUI.add('ezs-studionavigationhubplugin-tests', function (Y) { - var ajaxSuccessPluginTest, - ajaxFailurePluginTest, - navigateEventsPluginTest, + var navigateEventsPluginTest, registerTest, eventsTest, responseUrl = 'Tests/js/views/services/plugins/echo/get/json/?response=', responseData = Y.config.win.encodeURIComponent(JSON.stringify({siteaccesses: {0: 'eng', 1: 'pl'}})); - ajaxSuccessPluginTest = new Y.Test.Case({ - name: 'eZS Studio Navigation Hub plugin AJAX success tests', - - setUp: function () { - var siteaccessesUrl = responseUrl + responseData; - - this.app = new Y.Base(); - this.app.set('apiRoot', '/'); - this.service = new Y.View({ - app: this.app, - studioNavigationItems: [] - }); - this.itemView = Y.View; - - this.service.addNavigationItem = function (item, zone) { - this.get(zone + 'NavigationItems').push(item); - }; - - this.plugin = new Y.eZS.Plugin.StudioNavigationHub({ - host: this.service, - itemView: this.itemView, - siteaccessesUrl: siteaccessesUrl - }); - }, - - tearDown: function () { - this.service.destroy(); - this.plugin.destroy(); - - delete this.service; - delete this.plugin; - delete this.app; - }, - }); - eventsTest = new Y.Test.Case({ name: 'eZS Studio Navigation Hub plugin events tests', @@ -116,50 +79,6 @@ YUI.add('ezs-studionavigationhubplugin-tests', function (Y) { } }); }, - - // 'Should update route URL in each menu item': function () { - // var locationId = '/api/ezp/v2/content/locations/1/2/90/93', - // locationRefAlias = '/api/ezp/v2/content/urlaliases/69-d892a4dcb8f7fa9c714cfcf2a85942b0', - // locationPath = '/Blog/Oh-c-mon', - // menuItems = this.plugin.get('host').get('studioNavigationItems'); - - // Y.Mock.expect(this.contentService, { - // method: 'listLocationAliases', - // args: [locationId, false, Y.Mock.Value.Function], - // run: function (id, custom, callback) { - // callback(false, {document: {UrlAliasRefList: {UrlAlias: [{_href: locationRefAlias}]}}}); - // } - // }); - - // Y.Mock.expect(this.contentService, { - // method: 'loadUrlAlias', - // args: [locationRefAlias, Y.Mock.Value.Function], - // run: function (refAlias, callback) { - // callback(false, {document: {UrlAlias: {path: locationPath}}}); - // } - // }); - - // Y.Mock.expect(this.app, { - // method: 'routeUri', - // args: ['studioPreview', Y.Mock.Value.Object], - // run: function () { - // return locationPath; - // }, - // callCount: menuItems.length - // }); - - // this.service.set('matchedRoute', { - // view: 'locationViewView', - // parameters: {id: locationId} - // }); - - // menuItems.forEach(function (item) { - // Y.Assert.areEqual(locationPath, item.get('route'), 'The route param should be set correctly on menu items'); - // }); - - // Y.Mock.verify(this.contentService); - // Y.Mock.verify(this.app); - // }, }); navigateEventsPluginTest = new Y.Test.Case({ @@ -181,19 +100,23 @@ YUI.add('ezs-studionavigationhubplugin-tests', function (Y) { Y.Mock.expect(this.app, { method: 'get', args: [Y.Mock.Value.String], - callCount: 2, - run: function (name) { + run: function (key) { var params = { - 'config.studioSiteaccesses': ['site'] + studioActiveSiteaccess: 'site', + 'config.studioSiteaccesses': { + site: { + urlRoot: window.location.origin + } + } }; - return params[name]; + return params[key]; } }); Y.Mock.expect(this.app, { method: 'on', - args: [Y.Mock.Value.String, Y.Mock.Value.Function, Y.Mock.Value.Object], + args: [Y.Mock.Value.Any, Y.Mock.Value.Function, Y.Mock.Value.Object], callCount: 3 }); @@ -261,6 +184,31 @@ YUI.add('ezs-studionavigationhubplugin-tests', function (Y) { callCount: 0, }); + Y.Mock.expect(this.app, { + method: 'get', + args: [Y.Mock.Value.String], + callCount: 0, + run: function (key) { + var params = { + studioActiveSiteaccess: 'site', + 'config.studioSiteaccesses': { + site: { + urlRoot: window.location.origin + } + } + }; + + return params[key]; + } + }); + + Y.Mock.expect(this.service, { + method: '_getItem', + args: [Y.Mock.Value.Object, Y.Mock.Value.Object], + callCount: 0, + returns: true + }); + Y.Mock.verify(this.service); Y.Mock.verify(this.app); Y.Mock.verify(this.capi); @@ -275,6 +223,23 @@ YUI.add('ezs-studionavigationhubplugin-tests', function (Y) { }); Y.Mock.expect(this.app, { + method: 'get', + args: [Y.Mock.Value.String], + callCount: 3, + run: function (name) { + var params = { + 'config.studioSiteaccesses': { + site: { + urlRoot: window.location.origin + } + } + }; + + return params[name]; + } + }); + + Y.Mock.expect(this.app, { method: 'navigateTo', args: [Y.Mock.Value.String, Y.Mock.Value.Object], callCount: 0 @@ -294,8 +259,6 @@ YUI.add('ezs-studionavigationhubplugin-tests', function (Y) { registerTest.components = ['navigationHubViewService']; Y.Test.Runner.setName('eZS Studio Navigation Hub plugin tests'); - Y.Test.Runner.add(ajaxSuccessPluginTest); - Y.Test.Runner.add(ajaxFailurePluginTest); Y.Test.Runner.add(navigateEventsPluginTest); Y.Test.Runner.add(eventsTest); Y.Test.Runner.add(registerTest); -- 2.6.4 (Apple Git-63)