[FEATURE] Add distribution management to extension manager 76/23476/4
authorSusanne Moog <typo3@susannemoog.de>
Thu, 29 Aug 2013 15:56:44 +0000 (17:56 +0200)
committerChristian Kuhn <lolli@schwarzbu.ch>
Thu, 29 Aug 2013 19:30:29 +0000 (21:30 +0200)
To install distribution like the introduction or government
package, the extension manager needs a distribution management.

The distribution management consists of a controller that shows
all available distributions and additions to several actions.
The controller lists the packages to be installed. After
click on installing the distribution extension is downloaded,
all dependencies get resolved via the existing dependency
handling and the user is redirected to the configuration. Upon
saving the configuration the user is redirected to a package
welcome side from where he can jump directly to Web>View and
Web>page.

Resolves: #51537
Releases: 6.2
Change-Id: I4aeecc2d2c2d44bdc138bd502d1b2317d33325fd
Reviewed-on: https://review.typo3.org/23476
Reviewed-by: Kai Ole Hartwig
Tested-by: Kai Ole Hartwig
Reviewed-by: Christian Kuhn
Tested-by: Christian Kuhn
17 files changed:
typo3/sysext/extensionmanager/Classes/Controller/ConfigurationController.php
typo3/sysext/extensionmanager/Classes/Controller/DistributionController.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/Controller/DownloadController.php
typo3/sysext/extensionmanager/Classes/Controller/ListController.php
typo3/sysext/extensionmanager/Classes/Domain/Model/Extension.php
typo3/sysext/extensionmanager/Classes/Domain/Repository/ExtensionRepository.php
typo3/sysext/extensionmanager/Classes/ViewHelpers/ImageViewHelper.php
typo3/sysext/extensionmanager/Resources/Private/Language/locallang.xlf
typo3/sysext/extensionmanager/Resources/Private/Layouts/Main.html
typo3/sysext/extensionmanager/Resources/Private/Templates/Distribution/Welcome.html [new file with mode: 0644]
typo3/sysext/extensionmanager/Resources/Private/Templates/List/Distributions.html [new file with mode: 0644]
typo3/sysext/extensionmanager/Resources/Public/Css/main.css
typo3/sysext/extensionmanager/Resources/Public/Images/Distribution.png [new file with mode: 0644]
typo3/sysext/extensionmanager/Resources/Public/Images/DistributionWelcome.png [new file with mode: 0644]
typo3/sysext/extensionmanager/Resources/Public/JavaScript/jquery.expander.min.js [new file with mode: 0644]
typo3/sysext/extensionmanager/Resources/Public/JavaScript/main.js
typo3/sysext/extensionmanager/ext_tables.php

index a5b2635..c516bf2 100644 (file)
@@ -26,6 +26,8 @@ namespace TYPO3\CMS\Extensionmanager\Controller;
  *
  *  This copyright notice MUST APPEAR in all copies of the script!
  ***************************************************************/
+use TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException;
+
 /**
  * Controller for configuration related actions.
  *
@@ -39,6 +41,12 @@ class ConfigurationController extends \TYPO3\CMS\Extensionmanager\Controller\Abs
         */
        protected $configurationItemRepository;
 
+       /**
+        * @var \TYPO3\CMS\Extensionmanager\Domain\Repository\ExtensionRepository
+        * @inject
+        */
+       protected $extensionRepository;
+
        /**
         * Show the extension configuration form. The whole form field handling is done
         * in the corresponding view helper
@@ -49,14 +57,25 @@ class ConfigurationController extends \TYPO3\CMS\Extensionmanager\Controller\Abs
         */
        public function showConfigurationFormAction(array $extension) {
                if (!array_key_exists('key', $extension)) {
-                       throw new \TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException(
+                       throw new ExtensionManagerException(
                                'Extension key not found.',
                                1359206803
                        );
                }
-               $this->view
-                       ->assign('configuration', $this->configurationItemRepository->findByExtensionKey($extension['key']))
-                       ->assign('extension', $extension);
+               $configuration = $this->configurationItemRepository->findByExtensionKey($extension['key']);
+               if ($configuration) {
+                       $this->view
+                               ->assign('configuration', $configuration)
+                               ->assign('extension', $extension);
+               } else {
+                       /** @var \TYPO3\CMS\Extensionmanager\Domain\Model\Extension $extension */
+                       $extension = $this->extensionRepository->findOneByCurrentVersionByExtensionKey($extension['key']);
+                       // Extension has no configuration and is a distribution
+                       if ($extension->getCategory() === \TYPO3\CMS\Extensionmanager\Domain\Model\Extension::DISTRIBUTION_CATEGORY) {
+                               $this->redirect('welcome', 'Distribution', NULL, array('extension' => $extension->getUid()));
+                       }
+                       throw new ExtensionManagerException('The extension ' . htmlspecialchars($extension['key']) . ' has no configuration.');
+               }
        }
 
        /**
@@ -72,8 +91,19 @@ class ConfigurationController extends \TYPO3\CMS\Extensionmanager\Controller\Abs
                $configurationUtility = $this->objectManager->get('TYPO3\\CMS\\Extensionmanager\\Utility\\ConfigurationUtility');
                $currentFullConfiguration = $configurationUtility->getCurrentConfiguration($extensionKey);
                $newConfiguration = \TYPO3\CMS\Core\Utility\GeneralUtility::array_merge_recursive_overrule($currentFullConfiguration, $config);
-               $configurationUtility->writeConfiguration($configurationUtility->convertValuedToNestedConfiguration($newConfiguration), $extensionKey);
-               $this->redirect('showConfigurationForm', NULL, NULL, array('extension' => array('key' => $extensionKey)));
+               $configurationUtility->writeConfiguration(
+                       $configurationUtility->convertValuedToNestedConfiguration($newConfiguration),
+                       $extensionKey
+               );
+               $this->signalSlotDispatcher->dispatch(__CLASS__, 'afterExtensionConfigurationWrite', array($newConfiguration, $this));
+               /** @var \TYPO3\CMS\Extensionmanager\Domain\Model\Extension $extension */
+               $extension = $this->extensionRepository->findOneByCurrentVersionByExtensionKey($extensionKey);
+               // Different handling for distribution installation
+               if ($extension->getCategory() === \TYPO3\CMS\Extensionmanager\Domain\Model\Extension::DISTRIBUTION_CATEGORY) {
+                       $this->redirect('welcome', 'Distribution', NULL, array('extension' => $extension->getUid()));
+               } else {
+                       $this->redirect('showConfigurationForm', NULL, NULL, array('extension' => array('key' => $extensionKey)));
+               }
        }
 
 }
diff --git a/typo3/sysext/extensionmanager/Classes/Controller/DistributionController.php b/typo3/sysext/extensionmanager/Classes/Controller/DistributionController.php
new file mode 100644 (file)
index 0000000..944d6f9
--- /dev/null
@@ -0,0 +1,45 @@
+<?php
+namespace TYPO3\CMS\Extensionmanager\Controller;
+
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2012-2013 Susanne Moog, <typo3@susannemoog.de>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *  A copy is found in the textfile GPL.txt and important notices to the license
+ *  from the author is found in LICENSE.txt distributed with these scripts.
+ *
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+/**
+ * Controller for distribution related actions
+ *
+ * @author Susanne Moog <typo3@susannemoog.de>
+ */
+class DistributionController extends \TYPO3\CMS\Extensionmanager\Controller\AbstractController {
+
+       /**
+        * Displays welcoming page of a package
+        *
+        * @param \TYPO3\CMS\Extensionmanager\Domain\Model\Extension $extension
+        */
+       public function welcomeAction(\TYPO3\CMS\Extensionmanager\Domain\Model\Extension $extension) {
+               $this->view->assign('extension', $extension);
+       }
+}
+?>
\ No newline at end of file
index c3c647b..d2b0584 100644 (file)
@@ -107,23 +107,43 @@ class DownloadController extends \TYPO3\CMS\Extensionmanager\Controller\Abstract
        }
 
        /**
-        * Install an extension from TER
+        * Install an extension from TER action
         *
         * @param \TYPO3\CMS\Extensionmanager\Domain\Model\Extension $extension
         * @param string $downloadPath
-        * @throws \TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException
         */
        public function installFromTerAction(\TYPO3\CMS\Extensionmanager\Domain\Model\Extension $extension, $downloadPath) {
-               $result = FALSE;
-               $errorMessage = '';
-               try {
-                       $this->downloadUtility->setDownloadPath($downloadPath);
-                       $this->prepareExtensionForImport($extension);
-                       $result = $this->managementService->resolveDependenciesAndInstall($extension);
-               } catch (\TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException $e) {
-                       $errorMessage = $e->getMessage();
+               list($result, $errorMessage) = $this->installFromTer($extension, $downloadPath);
+               $this->view
+                       ->assign('result', $result)
+                       ->assign('extension', $extension)
+                       ->assign('errorMessage', $errorMessage);
+       }
+
+       /**
+        * Action for installing a distribution -
+        * redirects directly to configuration after installing
+        *
+        * @param \TYPO3\CMS\Extensionmanager\Domain\Model\Extension $extension
+        * @return void
+        */
+       public function installDistributionAction(\TYPO3\CMS\Extensionmanager\Domain\Model\Extension $extension) {
+               list($result, $errorMessage) = $this->installFromTer($extension);
+               if ($errorMessage) {
+                       // @TODO: write Template
+                       $this->view
+                               ->assign('result', $result)
+                               ->assign('errorMessage', $errorMessage);
+               } else {
+                       $this->redirect(
+                               'showConfigurationForm',
+                               'Configuration',
+                               NULL,
+                               array(
+                                       'extension' => $this->installUtility->enrichExtensionWithDetails($extension->getExtensionKey())
+                               )
+                       );
                }
-               $this->view->assign('result', $result)->assign('extension', $extension)->assign('errorMessage', $errorMessage);
        }
 
        /**
@@ -176,6 +196,27 @@ class DownloadController extends \TYPO3\CMS\Extensionmanager\Controller\Abstract
                }
                $this->view->assign('updateComments', $updateComments)->assign('extensionKey', $extensionKey);
        }
+
+       /**
+        * Install an action from TER
+        * Downloads the extension, resolves dependencies and installs it
+        *
+        * @param \TYPO3\CMS\Extensionmanager\Domain\Model\Extension $extension
+        * @param string $downloadPath
+        * @return array
+        */
+       protected function installFromTer(\TYPO3\CMS\Extensionmanager\Domain\Model\Extension $extension, $downloadPath = 'Local') {
+               $result = FALSE;
+               $errorMessage = '';
+               try {
+                       $this->downloadUtility->setDownloadPath($downloadPath);
+                       $this->prepareExtensionForImport($extension);
+                       $result = $this->managementService->resolveDependenciesAndInstall($extension);
+               } catch (\TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException $e) {
+                       $errorMessage = $e->getMessage();
+               }
+               return array($result, $errorMessage);
+       }
 }
 
 
index 77a4b57..51cab1d 100644 (file)
@@ -77,6 +77,7 @@ class ListController extends \TYPO3\CMS\Extensionmanager\Controller\AbstractCont
         * Either all extensions or depending on a search param
         *
         * @param string $search
+        * @return void
         */
        public function terAction($search = '') {
                if (!empty($search)) {
@@ -90,10 +91,21 @@ class ListController extends \TYPO3\CMS\Extensionmanager\Controller\AbstractCont
                                ->assign('availableAndInstalled', $availableAndInstalledExtensions);
        }
 
+       /**
+        * Action for listing all possible distributions
+        *
+        * @return void
+        */
+       public function distributionsAction() {
+               $distributions = $this->extensionRepository->findAllDistributions();
+               $this->view->assign('distributions', $distributions);
+       }
+
        /**
         * Shows all versions of a specific extension
         *
         * @param string $extensionKey
+        * @return void
         */
        public function showAllVersionsAction($extensionKey) {
                $currentVersion = $this->extensionRepository->findOneByCurrentVersionByExtensionKey($extensionKey);
index 9624071..9bf4210 100644 (file)
@@ -33,6 +33,11 @@ namespace TYPO3\CMS\Extensionmanager\Domain\Model;
  */
 class Extension extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity {
 
+       /**
+        * Category index for distributions
+        */
+       const DISTRIBUTION_CATEGORY = 10;
+
        /**
         * Contains default categories.
         *
@@ -47,7 +52,8 @@ class Extension extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity {
                5 => 'services',
                6 => 'templates',
                8 => 'doc',
-               9 => 'example'
+               9 => 'example',
+               Extension::DISTRIBUTION_CATEGORY => 'distribution'
        );
 
        /**
@@ -232,7 +238,7 @@ class Extension extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity {
                $categoryIndex = 4;
                if (\TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($category)) {
                        $categoryIndex = (integer)$category;
-                       if ($categoryIndex < 0 || $categoryIndex > 9) {
+                       if ($categoryIndex < 0 || $categoryIndex > 10) {
                                $categoryIndex = 4;
                        }
                } elseif (is_string($category)) {
index 1620a40..1f96076 100644 (file)
@@ -194,6 +194,22 @@ class ExtensionRepository extends \TYPO3\CMS\Extbase\Persistence\Repository {
                return $query->execute();
        }
 
+       /**
+        * Finds all extensions with category "distribution"
+        *
+        * @return \TYPO3\CMS\Extbase\Persistence\QueryResultInterface
+        */
+       public function findAllDistributions() {
+               $query = $this->createQuery();
+               $query->matching(
+                       $query->logicalAnd(
+                               $query->equals('category', \TYPO3\CMS\Extensionmanager\Domain\Model\Extension::DISTRIBUTION_CATEGORY),
+                               $query->equals('currentVersion', 1)
+                       )
+               );
+               return $query->execute();
+       }
+
        /**
         * Count extensions with a certain key between a given version range
         *
index 97eb9d9..6b91063 100644 (file)
@@ -26,6 +26,7 @@ namespace TYPO3\CMS\Extensionmanager\ViewHelpers;
  *
  *  This copyright notice MUST APPEAR in all copies of the script!
  ***************************************************************/
+
 /**
  * Resizes a given image (if required) and renders the respective img tag
  * In general just calls the parent image view helper but catches
@@ -69,14 +70,20 @@ class ImageViewHelper extends \TYPO3\CMS\Fluid\ViewHelpers\ImageViewHelper {
         * @param integer $minHeight minimum height of the image
         * @param integer $maxWidth maximum width of the image
         * @param integer $maxHeight maximum height of the image
+        * @param string $fallbackImage an optional fallback image if the $src image cannot be loaded
         * @return string rendered tag.
         */
-       public function render($src, $width = NULL, $height = NULL, $minWidth = NULL, $minHeight = NULL, $maxWidth = NULL, $maxHeight = NULL) {
+       public function render($src, $width = NULL, $height = NULL, $minWidth = NULL, $minHeight = NULL, $maxWidth = NULL, $maxHeight = NULL, $fallbackImage = '') {
                $image = '';
                try {
                        $image = parent::render($src, $width, $height, $minWidth, $minHeight, $maxWidth, $maxHeight);
                } catch (\Exception $e) {
-
+                       if ($fallbackImage !== '') {
+                               $image = static::render($fallbackImage, $width, $height, $minWidth, $minHeight, $maxWidth, $maxHeight);
+                       }
+                       /** @var \TYPO3\CMS\Core\Log\Logger $logger */
+                       $logger = $this->objectManager->get('TYPO3\\CMS\\Core\\Log\\LogManager')->getLogger(__CLASS__);
+                       $logger->log(\TYPO3\CMS\Core\Log\LogLevel::WARNING, $e->getMessage());
                }
                return $image;
        }
index 3f66fe2..0c58891 100644 (file)
                        <trans-unit id="extensionList.showAllVersions.readOnline" xml:space="preserve">
                                <source>Read online</source>
                        </trans-unit>
-
+                       <trans-unit id="extensionList.distribution.key" xml:space="preserve">
+                               <source>Distribution-Key:</source>
+                       </trans-unit>
+                       <trans-unit id="distributions" xml:space="preserve">
+                               <source>Get preconfigured distribution</source>
+                       </trans-unit>
+                       <trans-unit id="extensionList.installDistribution" xml:space="preserve">
+                               <source>Install distribution</source>
+                       </trans-unit>
                        <trans-unit id="extensionList.updateFromTer.label" xml:space="preserve">
                                <source>Retrieving Extension-List from TYPO3 Extension Repository (TER)</source>
                        </trans-unit>
                        <trans-unit id="extensionList.uninstall.dependencyError" xml:space="preserve">
                                <source>Cannot deactivate extension '%s' - The extension(s) '%s' depend on it.</source>
                        </trans-unit>
-
+                       <trans-unit id="distribution.welcome.headline" xml:space="preserve">
+                               <source>Congratulations...</source>
+                       </trans-unit>
+                       <trans-unit id="distribution.welcome.message" xml:space="preserve">
+                               <source>You successfully installed the distribution:</source>
+                       </trans-unit>
+                       <trans-unit id="distribution.welcome.nextSteps" xml:space="preserve">
+                               <source>Now you can:</source>
+                       </trans-unit>
+                       <trans-unit id="distribution.welcome.openViewModule" xml:space="preserve">
+                               <source>View your website</source>
+                       </trans-unit>
+                       <trans-unit id="distribution.welcome.openPageModule" xml:space="preserve">
+                               <source>Start editing your website</source>
+                       </trans-unit>
                        <trans-unit id="task.updateExtensionListTask.name" xml:space="preserve">
                                <source>Update extension list</source>
                        </trans-unit>
index cedd161..22e32b1 100644 (file)
                0:'{f:uri.resource(path:\'JavaScript/jquery-1.8.2.min.js\')}',
                1:'{f:uri.resource(path:\'JavaScript/jquery.dataTables-1.9.4.min.js\')}',
                2:'{f:uri.resource(path:\'JavaScript/jquery-ui-1.8.17.custom.min.js\')}',
-               3:'{f:uri.resource(path:\'JavaScript/jquery.tools.min.js\')}',
-               3a:'{f:uri.resource(path:\'JavaScript/jquery.clearable.js\')}',
-               4:'{f:uri.resource(path:\'Contrib/LoadMask/jquery.loadmask.js\')}',
-               5:'{f:uri.resource(path:\'JavaScript/main.js\')}',
-               6:'{f:uri.resource(path:\'JavaScript/ter.js\')}',
-               7:'{f:uri.resource(path:\'JavaScript/configuration.js\')}'
-               8:'{f:uri.resource(path:\'JavaScript/update.js\')}',
-               9:'{f:uri.resource(path:\'JavaScript/upload.js\')}'
+               3:'{f:uri.resource(path:\'JavaScript/jquery.expander.min.js\')}',
+               4:'{f:uri.resource(path:\'JavaScript/jquery.tools.min.js\')}',
+               5:'{f:uri.resource(path:\'JavaScript/jquery.clearable.js\')}',
+               6:'{f:uri.resource(path:\'Contrib/LoadMask/jquery.loadmask.js\')}',
+               7:'{f:uri.resource(path:\'JavaScript/main.js\')}',
+               8:'{f:uri.resource(path:\'JavaScript/ter.js\')}',
+               9:'{f:uri.resource(path:\'JavaScript/configuration.js\')}'
+               10:'{f:uri.resource(path:\'JavaScript/update.js\')}',
+               11:'{f:uri.resource(path:\'JavaScript/upload.js\')}'
                }">
 
        <em:be.trigger triggers="{triggers}" />
@@ -27,6 +28,7 @@
                        <f:be.menus.actionMenu>
                                <f:be.menus.actionMenuItem label="{f:translate(key: 'manageExtensions')}" controller="List" action="index" />
                                <f:be.menus.actionMenuItem label="{f:translate(key: 'getExtensions')}" controller="List" action="ter" />
+                               <f:be.menus.actionMenuItem label="{f:translate(key: 'distributions')}" controller="List" action="distributions" />
                                <f:if condition="{actionName} == 'showAllVersions'">
                                        <f:be.menus.actionMenuItem label="{f:translate(key: 'showAllVersions')} {extensionKey}" controller="List" action="showAllVersions" />
                                </f:if>
diff --git a/typo3/sysext/extensionmanager/Resources/Private/Templates/Distribution/Welcome.html b/typo3/sysext/extensionmanager/Resources/Private/Templates/Distribution/Welcome.html
new file mode 100644 (file)
index 0000000..95c10b6
--- /dev/null
@@ -0,0 +1,30 @@
+{namespace em=TYPO3\CMS\Extensionmanager\ViewHelpers}
+<f:layout name="main" />
+
+<f:section name="docheader-buttons">
+</f:section>
+
+<f:section name="module-headline">
+</f:section>
+
+<f:section name="Content">
+       <div class="em-distribution-welcome">
+               <h1>
+                       <f:translate key="distribution.welcome.headline" />
+               </h1>
+               <em:image
+                       src="EXT:{distribution.extensionKey}/Resources/Public/Images/DistributionWelcome.png" alt="{distribution.title}"
+                       fallbackImage="EXT:extensionmanager/Resources/Public/Images/DistributionWelcome.png"
+               />
+               <div class="em-distribution-welcome-text">
+                       <f:translate key="distribution.welcome.message" /> <strong>{extension.extensionKey}</strong>
+                       <h2><f:translate key="distribution.welcome.nextSteps" /></h2>
+                       <ul>
+                               <li><a href="#" class="distribution-openViewModule" onclick="top.goToModule('web_ViewpageView');"><f:translate key="distribution.welcome.openViewModule" /></a></li>
+                               <li><a href="#" class="distribution-openPageModule" onclick="top.goToModule('web_page');">
+                                       <f:translate key="distribution.welcome.openPageModule" />
+                               </a></li>
+                       </ul>
+               </div>
+       </div>
+</f:section>
\ No newline at end of file
diff --git a/typo3/sysext/extensionmanager/Resources/Private/Templates/List/Distributions.html b/typo3/sysext/extensionmanager/Resources/Private/Templates/List/Distributions.html
new file mode 100644 (file)
index 0000000..1a53095
--- /dev/null
@@ -0,0 +1,36 @@
+{namespace em=TYPO3\CMS\Extensionmanager\ViewHelpers}
+
+<f:layout name="main"/>
+
+<f:section name="docheader-buttons">
+</f:section>
+
+<f:section name="module-headline">
+       <h1><f:translate key="distributions">Get Distributions</f:translate></h1>
+</f:section>
+
+<f:section name="Content">
+       <f:flashMessages renderMode="div" />
+       <f:for each="{distributions}" as="distribution">
+               <div class="distribution">
+                       <div class="distributionInner">
+                               <div class="distributionName"><h2>{distribution.title}</h2></div>
+                               <div class="distributionImage">
+                                       <em:image
+                                               src="EXT:{distribution.extensionKey}/Resources/Public/Images/Distribution.png" alt="{distribution.title}"
+                                               fallbackImage="EXT:extensionmanager/Resources/Public/Images/Distribution.png"
+                                               height="150px"
+                                               width="220px"
+                                       />
+                               </div>
+                               <div class="distributionKey"><strong><f:translate key="extensionList.distribution.key" /> </strong>{distribution.extensionKey}</div>
+                               <div class="distributionDescription expandable">{distribution.description} </div>
+                               <div class="distributionInstall">
+                                       <f:link.action action="installDistribution" controller="Download" arguments="{extension:distribution}">
+                                               <f:translate key="extensionList.installDistribution">Install Distribution</f:translate>
+                                       </f:link.action>
+                               </div>
+                       </div>
+               </div>
+       </f:for>
+</f:section>
\ No newline at end of file
index 988dd9d..d822cc9 100644 (file)
@@ -2326,3 +2326,111 @@ span.ter-ext-state-beta {
 span.ter-ext-state-alpha {
   color: #f14400;
 }
+
+div.distribution {
+       float: left;
+       width: 242px;
+       height: 335px;
+       margin: 0 25px 25px 0;
+}
+
+div.distributionInner {
+       text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);
+       background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6);
+       background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));
+       background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6);
+       background-image: -o-linear-gradient(top, #ffffff, #e6e6e6);
+       background-image: linear-gradient(to bottom, #ffffff, #e6e6e6);
+       background-repeat: repeat-x;
+       border: 1px solid #cccccc;
+       border-color: #e6e6e6 #e6e6e6 #bfbfbf;
+       border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+       border-bottom-color: #b3b3b3;
+       -webkit-border-radius: 4px;
+       -moz-border-radius: 4px;
+       border-radius: 4px;
+       background-color: #f5f5f5;
+       -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+       -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+       box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+       padding: 10px;
+       width: 220px;
+       position: relative;
+}
+
+div.distributionInstall a {
+       color: #ffffff;
+       text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+       background-color: #5bb75b;
+       background-image: -moz-linear-gradient(top, #62c462, #51a351);
+       background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));
+       background-image: -webkit-linear-gradient(top, #62c462, #51a351);
+       background-image: -o-linear-gradient(top, #62c462, #51a351);
+       background-image: linear-gradient(to bottom, #62c462, #51a351);
+       background-repeat: repeat-x;
+       border: 1px solid #cccccc;
+       border-bottom-color: #b3b3b3;
+       -webkit-border-radius: 4px;
+       -moz-border-radius: 4px;
+       border-radius: 4px;
+       background-color: #f5f5f5;
+       -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+       -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+       box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+       border-color: #51a351 #51a351 #387038;
+       border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+       display: inline-block;
+       padding: 5px;
+}
+
+div.distributionKey {
+       margin-bottom: 10px;
+}
+
+div.distributionDescription {
+       margin-bottom: 10px;
+       min-height: 50px;
+}
+
+div.distribution .read-more a,
+div.distribution .read-less a {
+       font-weight: bold;
+       display: block;
+}
+
+div.em-distribution-welcome {
+       font-size: 14px;
+       text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);
+       background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6);
+       background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));
+       background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6);
+       background-image: -o-linear-gradient(top, #ffffff, #e6e6e6);
+       background-image: linear-gradient(to bottom, #ffffff, #e6e6e6);
+       background-repeat: repeat-x;
+       border: 1px solid #cccccc;
+       border-color: #e6e6e6 #e6e6e6 #bfbfbf;
+       border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+       border-bottom-color: #b3b3b3;
+       -webkit-border-radius: 4px;
+       -moz-border-radius: 4px;
+       border-radius: 4px;
+       background-color: #f5f5f5;
+       -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+       -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+       box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+       padding: 10px 10px;
+       float: left;
+}
+
+div.em-distribution-welcome-text {
+       margin-top: 10px;
+}
+
+div.em-distribution-welcome-text h2 {
+       margin-top: 10px;
+}
+
+div.em-distribution-welcome-text ul li {
+       list-style: disc;
+       margin-left: 20px;
+}
\ No newline at end of file
diff --git a/typo3/sysext/extensionmanager/Resources/Public/Images/Distribution.png b/typo3/sysext/extensionmanager/Resources/Public/Images/Distribution.png
new file mode 100644 (file)
index 0000000..00e4cc4
Binary files /dev/null and b/typo3/sysext/extensionmanager/Resources/Public/Images/Distribution.png differ
diff --git a/typo3/sysext/extensionmanager/Resources/Public/Images/DistributionWelcome.png b/typo3/sysext/extensionmanager/Resources/Public/Images/DistributionWelcome.png
new file mode 100644 (file)
index 0000000..31d2a16
Binary files /dev/null and b/typo3/sysext/extensionmanager/Resources/Public/Images/DistributionWelcome.png differ
diff --git a/typo3/sysext/extensionmanager/Resources/Public/JavaScript/jquery.expander.min.js b/typo3/sysext/extensionmanager/Resources/Public/JavaScript/jquery.expander.min.js
new file mode 100644 (file)
index 0000000..8a3ee3a
--- /dev/null
@@ -0,0 +1,8 @@
+/*!
+ * Expander - v1.4.5 - 2013-03-24
+ * http://plugins.learningjquery.com/expander/
+ * Copyright (c) 2013 Karl Swedberg
+ * Licensed MIT (http://www.opensource.org/licenses/mit-license.php)
+ */
+
+(function(e){e.expander={version:"1.4.5",defaults:{slicePoint:100,preserveWords:!0,widow:4,expandText:"read more",expandPrefix:"&hellip; ",expandAfterSummary:!1,summaryClass:"summary",detailClass:"details",moreClass:"read-more",lessClass:"read-less",collapseTimer:0,expandEffect:"slideDown",expandSpeed:250,collapseEffect:"slideUp",collapseSpeed:200,userCollapse:!0,userCollapseText:"read less",userCollapsePrefix:" ",onSlice:null,beforeExpand:null,afterExpand:null,onCollapse:null,afterCollapse:null}},e.fn.expander=function(a){function l(e,a){var l="span",s=e.summary;return a?(l="div",x.test(s)&&!e.expandAfterSummary?s=s.replace(x,e.moreLabel+"$1"):s+=e.moreLabel,s='<div class="'+e.summaryClass+'">'+s+"</div>"):s+=e.moreLabel,[s,"<",l+' class="'+e.detailClass+'"',">",e.details,"</"+l+">"].join("")}function s(e){var a='<span class="'+e.moreClass+'">'+e.expandPrefix;return a+='<a href="#">'+e.expandText+"</a></span>"}function n(a,l){return a.lastIndexOf("<")>a.lastIndexOf(">")&&(a=a.slice(0,a.lastIndexOf("<"))),l&&(a=a.replace(c,"")),e.trim(a)}function t(e,a){a.stop(!0,!0)[e.collapseEffect](e.collapseSpeed,function(){var l=a.prev("span."+e.moreClass).show();l.length||a.parent().children("div."+e.summaryClass).show().find("span."+e.moreClass).show(),e.afterCollapse&&e.afterCollapse.call(a)})}function r(a,l,s){a.collapseTimer&&(o=setTimeout(function(){t(a,l),e.isFunction(a.onCollapse)&&a.onCollapse.call(s,!1)},a.collapseTimer))}var i="init";"string"==typeof a&&(i=a,a={});var o,d=e.extend({},e.expander.defaults,a),p=/^<(?:area|br|col|embed|hr|img|input|link|meta|param).*>$/i,c=d.wordEnd||/(&(?:[^;]+;)?|[a-zA-Z\u00C0-\u0100]+)$/,f=/<\/?(\w+)[^>]*>/g,u=/<(\w+)[^>]*>/g,m=/<\/(\w+)>/g,x=/(<\/[^>]+>)\s*$/,h=/^(<[^>]+>)+.?/,C={init:function(){this.each(function(){var a,i,c,x,C,v,S,g,b,y,E,w,T,I,P=[],j=[],k={},D=this,$=e(this),A=e([]),L=e.extend({},d,$.data("expander")||e.meta&&$.data()||{}),O=!!$.find("."+L.detailClass).length,z=!!$.find("*").filter(function(){var a=e(this).css("display");return/^block|table|list/.test(a)}).length,F=z?"div":"span",U=F+"."+L.detailClass,W=L.moreClass+"",Q=L.lessClass+"",Z=L.expandSpeed||0,q=e.trim($.html()),B=(e.trim($.text()),q.slice(0,L.slicePoint));if(L.moreSelector="span."+W.split(" ").join("."),L.lessSelector="span."+Q.split(" ").join("."),!e.data(this,"expanderInit")){for(e.data(this,"expanderInit",!0),e.data(this,"expander",L),e.each(["onSlice","beforeExpand","afterExpand","onCollapse","afterCollapse"],function(a,l){k[l]=e.isFunction(L[l])}),B=n(B),C=B.replace(f,"").length;L.slicePoint>C;)x=q.charAt(B.length),"<"===x&&(x=q.slice(B.length).match(h)[0]),B+=x,C++;for(B=n(B,L.preserveWords),v=B.match(u)||[],S=B.match(m)||[],c=[],e.each(v,function(e,a){p.test(a)||c.push(a)}),v=c,i=S.length,a=0;i>a;a++)S[a]=S[a].replace(m,"$1");if(e.each(v,function(a,l){var s=l.replace(u,"$1"),n=e.inArray(s,S);-1===n?(P.push(l),j.push("</"+s+">")):S.splice(n,1)}),j.reverse(),O)b=$.find(U).remove().html(),B=$.html(),q=B+b,g="";else{if(b=q.slice(B.length),y=e.trim(b.replace(f,"")),""===y||y.split(/\s+/).length<L.widow)return;g=j.pop()||"",B+=j.join(""),b=P.join("")+b}L.moreLabel=$.find(L.moreSelector).length?"":s(L),z&&(b=q),B+=g,L.summary=B,L.details=b,L.lastCloseTag=g,k.onSlice&&(c=L.onSlice.call(D,L),L=c&&c.details?c:L),E=l(L,z),$.html(E),T=$.find(U),I=$.find(L.moreSelector),"slideUp"===L.collapseEffect&&"slideDown"!==L.expandEffect||$.is(":hidden")?T.css({display:"none"}):T[L.collapseEffect](0),A=$.find("div."+L.summaryClass),w=function(e){e.preventDefault(),I.hide(),A.hide(),k.beforeExpand&&L.beforeExpand.call(D),T.stop(!1,!0)[L.expandEffect](Z,function(){T.css({zoom:""}),k.afterExpand&&L.afterExpand.call(D),r(L,T,D)})},I.find("a").unbind("click.expander").bind("click.expander",w),L.userCollapse&&!$.find(L.lessSelector).length&&$.find(U).append('<span class="'+L.lessClass+'">'+L.userCollapsePrefix+'<a href="#">'+L.userCollapseText+"</a></span>"),$.find(L.lessSelector+" a").unbind("click.expander").bind("click.expander",function(a){a.preventDefault(),clearTimeout(o);var l=e(this).closest(U);t(L,l),k.onCollapse&&L.onCollapse.call(D,!0)})}})},destroy:function(){this.each(function(){var a,l,s=e(this);s.data("expanderInit")&&(a=e.extend({},s.data("expander")||{},d),l=s.find("."+a.detailClass).contents(),s.removeData("expanderInit"),s.removeData("expander"),s.find(a.moreSelector).remove(),s.find("."+a.summaryClass).remove(),s.find("."+a.detailClass).after(l).remove(),s.find(a.lessSelector).remove())})}};return C[i]&&C[i].call(this),this},e.fn.expander.defaults=e.expander.defaults})(jQuery);
\ No newline at end of file
index f76c207..91fdc94 100644 (file)
                                datatable.fnFilter('');
                        }
                });
+
+               $('.expandable').expander({
+                       expandEffect: 'slideDown',
+                       collapseEffect: 'slideUp',
+                       beforeExpand: function() {
+                               $(this).parent().css('z-index', 199);
+                       },
+                       afterCollapse: function() {
+                               $(this).parent().css('z-index', 1);
+                       }
+               });
        });
 
        function getUrlVars() {
index 85deea9..0826ee2 100644 (file)
@@ -8,13 +8,14 @@ if (TYPO3_MODE === 'BE') {
                'TYPO3.CMS.' . $_EXTKEY,
                'tools',
                'extensionmanager', '', array(
-                       'List' => 'index,ter,showAllVersions',
+                       'List' => 'index,ter,showAllVersions,distributions',
                        'Action' => 'toggleExtensionInstallationState,removeExtension,downloadExtensionZip,downloadExtensionData',
                        'Configuration' => 'showConfigurationForm,save',
-                       'Download' => 'checkDependencies,installFromTer,updateExtension,updateCommentForUpdatableVersions',
+                       'Download' => 'checkDependencies,installFromTer,installDistribution,updateExtension,updateCommentForUpdatableVersions',
                        'UpdateScript' => 'show',
                        'UpdateFromTer' => 'updateExtensionListFromTer',
-                       'UploadExtensionFile' => 'form,extract'
+                       'UploadExtensionFile' => 'form,extract',
+                       'Distribution' => 'welcome'
                ),
                array(
                        'access' => 'user,group',