Add GUI for clipboardAction package installation plugin
authorMatthias Schmidt <gravatronics@live.com>
Wed, 18 Jul 2018 17:05:58 +0000 (19:05 +0200)
committerMatthias Schmidt <gravatronics@live.com>
Wed, 18 Jul 2018 17:05:58 +0000 (19:05 +0200)
See #2545

wcfsetup/install/files/lib/system/devtools/pip/TXmlGuiPackageInstallationPlugin.class.php
wcfsetup/install/files/lib/system/package/plugin/ClipboardActionPackageInstallationPlugin.class.php
wcfsetup/install/lang/en.xml

index 9012bbfe8579de07617f034ffcee6d54ae6000cc..8c8bd947c118730a891cb974d2f125a348851484 100644 (file)
@@ -6,6 +6,7 @@ use wcf\data\IEditableCachedObject;
 use wcf\system\form\builder\field\IFormField;
 use wcf\system\form\builder\IFormDocument;
 use wcf\system\form\builder\IFormNode;
+use wcf\system\package\PackageInstallationDispatcher;
 use wcf\system\WCF;
 use wcf\util\DOMUtil;
 use wcf\util\StringUtil;
@@ -403,6 +404,7 @@ XML;
         * @param       callable        $sortFunction
         */
        protected function sortChildNodes(\DOMNodeList $nodeList, callable $sortFunction) {
+               /** @var \DOMElement $node */
                foreach ($nodeList as $node) {
                        $childNodes = array_filter(iterator_to_array($node->childNodes), function($element) {
                                return $element instanceof \DOMElement;
index 25c8989dc580a7b4a98ed4e2b0dc113b58c06c16..a74ac2db27104a329ce06dd68800eef660474749 100644 (file)
@@ -3,18 +3,32 @@ declare(strict_types=1);
 namespace wcf\system\package\plugin;
 use wcf\data\clipboard\action\ClipboardAction;
 use wcf\data\clipboard\action\ClipboardActionEditor;
-use wcf\system\devtools\pip\IIdempotentPackageInstallationPlugin;
+use wcf\data\clipboard\action\ClipboardActionList;
+use wcf\system\clipboard\action\IClipboardAction;
+use wcf\system\devtools\pip\IDevtoolsPipEntryList;
+use wcf\system\devtools\pip\IGuiPackageInstallationPlugin;
+use wcf\system\devtools\pip\TXmlGuiPackageInstallationPlugin;
+use wcf\system\form\builder\container\FormContainer;
+use wcf\system\form\builder\field\ClassNameFormField;
+use wcf\system\form\builder\field\IntegerFormField;
+use wcf\system\form\builder\field\ItemListFormField;
+use wcf\system\form\builder\field\TextFormField;
+use wcf\system\form\builder\field\validation\FormFieldValidationError;
+use wcf\system\form\builder\field\validation\FormFieldValidator;
+use wcf\system\form\builder\IFormDocument;
 use wcf\system\WCF;
 
 /**
  * Installs, updates and deletes clipboard actions.
  * 
- * @author     Alexander Ebert
+ * @author     Alexander Ebert, Matthias Schmidt
  * @copyright  2001-2018 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\Acp\Package\Plugin
  */
-class ClipboardActionPackageInstallationPlugin extends AbstractXMLPackageInstallationPlugin implements IIdempotentPackageInstallationPlugin {
+class ClipboardActionPackageInstallationPlugin extends AbstractXMLPackageInstallationPlugin implements IGuiPackageInstallationPlugin {
+       use TXmlGuiPackageInstallationPlugin;
+       
        /**
         * @inheritDoc
         */
@@ -151,8 +165,206 @@ class ClipboardActionPackageInstallationPlugin extends AbstractXMLPackageInstall
        
        /**
         * @inheritDoc
+        * @since       3.1
         */
        public static function getSyncDependencies() {
                return [];
        }
+       
+       /**
+        * @inheritDoc
+        * @since       3.2
+        */
+       public function addFormFields(IFormDocument $form) {
+               /** @var FormContainer $dataContainer */
+               $dataContainer = $form->getNodeById('data');
+               
+               $dataContainer->appendChildren([
+                       TextFormField::create('actionName')
+                               ->objectProperty('name')
+                               ->label('wcf.acp.pip.clipboardAction.actionName')
+                               ->description('wcf.acp.pip.clipboardAction.actionName.description')
+                               ->required()
+                               ->addValidator(new FormFieldValidator('format', function(TextFormField $formField) {
+                                       if (!preg_match('~^[a-z][A-z]+$~', $formField->getValue())) {
+                                               $formField->addValidationError(
+                                                       new FormFieldValidationError(
+                                                               'format',
+                                                               'wcf.acp.pip.clipboardAction.actionName.error.format'
+                                                       )
+                                               );
+                                       }
+                               })),
+                       
+                       ClassNameFormField::create('actionClassName')
+                               ->label('wcf.acp.pip.clipboardAction.actionClassName')
+                               ->objectProperty('actionclassname')
+                               ->required()
+                               ->implementedInterface(IClipboardAction::class)
+                               ->addValidator(new FormFieldValidator('uniqueness', function(ClassNameFormField $formField) {
+                                       /** @var TextFormField $actionNameFormField */
+                                       $actionNameFormField = $formField->getDocument()->getNodeById('actionName');
+                                       
+                                       if (
+                                               $formField->getDocument()->getFormMode() === IFormDocument::FORM_MODE_CREATE ||
+                                               (
+                                                       $this->editedEntry->getAttribute('name') !== $actionNameFormField->getSaveValue() ||
+                                                       $this->editedEntry->getElementsByTagName('actionclassname')->item(0)->nodeValue !== $formField->getSaveValue()
+                                               )
+                                       ) {
+                                               $clipboardActionList = new ClipboardActionList();
+                                               $clipboardActionList->getConditionBuilder()->add('actionName = ?', [$actionNameFormField->getSaveValue()]);
+                                               $clipboardActionList->getConditionBuilder()->add('actionClassName = ?', [$formField->getSaveValue()]);
+                                               
+                                               if ($clipboardActionList->countObjects() > 0) {
+                                                       $actionNameFormField->addValidationError(
+                                                               new FormFieldValidationError(
+                                                                       'notUnique',
+                                                                       'wcf.acp.pip.clipboardAction.actionClassName.error.notUnique'
+                                                               )
+                                                       );
+                                               }
+                                       }
+                               })),
+                       
+                       IntegerFormField::create('showOrder')
+                               ->objectProperty('showorder')
+                               ->label('wcf.acp.pip.clipboardAction.showOrder')
+                               ->description('wcf.acp.pip.clipboardAction.showOrder.description')
+                               ->nullable(),
+                       
+                       ItemListFormField::create('pages')
+                               ->label('wcf.acp.pip.clipboardAction.pages')
+                               ->description('wcf.acp.pip.clipboardAction.pages.description')
+                               ->saveValueType(ItemListFormField::SAVE_VALUE_TYPE_ARRAY)
+                               ->required()
+               ]);
+       }
+       
+       /**
+        * @inheritDoc
+        * @since       3.2
+        */
+       protected function getElementData(\DOMElement $element, bool $saveData = false): array {
+               $data = [
+                       'actionClassName' => $element->getElementsByTagName('actionclassname')->item(0)->nodeValue,
+                       'actionName' => $element->getAttribute('name'),
+                       'packageID' => $this->installation->getPackage()->packageID,
+                       'pages' => []
+               ];
+               
+               $showOrder = $element->getElementsByTagName('showorder')->item(0);
+               if ($showOrder !== null) {
+                       $data['showOrder'] = $showOrder->nodeValue;
+               }
+               
+               /** @var \DOMElement $page */
+               foreach ($element->getElementsByTagName('pages')->item(0)->childNodes as $page) {
+                       if ($page->nodeName === 'page') {
+                               $data['pages'][] = $page->nodeValue;
+                       }
+               }
+               
+               if (!$saveData) {
+                       $data['pages'] = implode(',', $data['pages']);
+               }
+               
+               return $data;
+       }
+       
+       /**
+        * @inheritDoc
+        * @since       3.2
+        */
+       public function getElementIdentifier(\DOMElement $element): string {
+               return sha1(
+                       $element->getElementsByTagName('actionclassname')->item(0)->nodeValue . '/' .
+                       $element->getAttribute('name')
+               );
+       }
+       
+       /**
+        * @inheritDoc
+        * @since       3.2
+        */
+       protected function setEntryListKeys(IDevtoolsPipEntryList $entryList) {
+               $entryList->setKeys([
+                       'actionName' => 'wcf.acp.pip.clipboardAction.actionName',
+                       'actionClassName' => 'wcf.acp.pip.clipboardAction.actionClassName'
+               ]);
+       }
+       
+       /**
+        * @inheritDoc
+        * @since       3.2
+        */
+       protected function sortDocument(\DOMDocument $document) {
+               $this->sortImportDelete($document);
+               
+               $sortFunction = function(\DOMElement $element1, \DOMElement $element2) {
+                       $className1 = $element1->getElementsByTagName('actionclassname')->item(0)->nodeValue;
+                       $className2 = $element2->getElementsByTagName('actionclassname')->item(0)->nodeValue;
+                       
+                       $compare = strcmp($className1, $className2);
+                       
+                       if ($compare !== 0) {
+                               return $compare;
+                       }
+                       
+                       $showOrder1 = $element1->getElementsByTagName('showorder')->item(0);
+                       $showOrder2 = $element2->getElementsByTagName('showorder')->item(0);
+                       
+                       if ($showOrder1 !== null) {
+                               if ($showOrder2 !== null) {
+                                       $compare = $showOrder1->nodeValue <=> $showOrder2->nodeValue;
+                                       
+                                       if ($compare !== 0) {
+                                               return $compare;
+                                       }
+                               }
+                               
+                               return -1;
+                       }
+                       else if ($showOrder2 !== null) {
+                               return 1;
+                       }
+                       
+                       return strcmp(
+                               $element1->getAttribute('name'),
+                               $element2->getAttribute('name')
+                       );
+               };
+               
+               $this->sortChildNodes($document->getElementsByTagName('import'), $sortFunction);
+               $this->sortChildNodes($document->getElementsByTagName('delete'), $sortFunction);
+       }
+       
+       /**
+        * @inheritDoc
+        * @since       3.2
+        */
+       protected function writeEntry(\DOMDocument $document, IFormDocument $form): \DOMElement {
+               $formData = $form->getData();
+               $data = $formData['data'];
+               
+               $clipboardAction = $document->createElement($this->tagName);
+               $clipboardAction->setAttribute('name', $data['name']);
+               
+               $clipboardAction->appendChild($document->createElement('actionclassname', $data['actionclassname']));
+               
+               if (!empty($data['showorder'])) {
+                       $clipboardAction->appendChild($document->createElement('showorder', (string)$data['showorder']));
+               }
+               
+               $pages = $document->createElement('pages');
+               $clipboardAction->appendChild($pages);
+               
+               foreach ($formData['pages'] as $page) {
+                       $pages->appendChild($document->createElement('page', $page));
+               }
+               
+               $document->getElementsByTagName('import')->item(0)->appendChild($clipboardAction);
+               
+               return $clipboardAction;
+       }
 }
index fd4e7237551d83184f25b2f3e4d182660da3f606..1771515198436adc4c442326f922d9362a5bd551 100644 (file)
@@ -2049,6 +2049,15 @@ If you have <strong>already bought the licenses for the listed apps</strong>, th
                <item name="wcf.acp.pip.eventListener.niceValue.description"><![CDATA[The nice value is used to determine the order in which event listeners for the same event are executed. Event listeners with lower nice value are executed first.]]></item>
                <item name="wcf.acp.pip.eventListener.options.description"><![CDATA[At least one of the entered options has to be enabled for the event listener to be executed. Options of non-required packages will be reported as non-existing.]]></item>
                <item name="wcf.acp.pip.eventListener.permissions.description"><![CDATA[The active user must be granted at least one of the entered permissions for the event listener to be executed. Permissions of non-required packages will be reported as non-existing.]]></item>
+               <item name="wcf.acp.pip.clipboardAction.actionName"><![CDATA[Clipboard Action Name]]></item>
+               <item name="wcf.acp.pip.clipboardAction.actionName.description"><![CDATA[Unique textual identifier (per clipboard action class name) of the clipboard action that may only contain letters and must start with a lowercase letter.]]></item>
+               <item name="wcf.acp.pip.clipboardAction.actionName.error.format"><![CDATA[The entered name is invalid.]]></item>
+               <item name="wcf.acp.pip.clipboardAction.actionClassName"><![CDATA[Clipboard Action Class Name]]></item>
+               <item name="wcf.acp.pip.clipboardAction.actionClassName.error.notUnique"><![CDATA[There is already a clipboard action for the entered action class with this action name.]]></item>
+               <item name="wcf.acp.pip.clipboardAction.showOrder"><![CDATA[Position]]></item>
+               <item name="wcf.acp.pip.clipboardAction.showOrder.description"><![CDATA[The entered value determines in which order the clipboard actions for the same clipboard action class are shown.]]></item>
+               <item name="wcf.acp.pip.clipboardAction.pages"><![CDATA[Pages]]></item>
+               <item name="wcf.acp.pip.clipboardAction.pages.description"><![CDATA[The clipboard action is available on the entered pages.]]></item>
        </category>
        
        <category name="wcf.acp.rebuildData">