Add support for (location-specific) variables in ads
authorMatthias Schmidt <gravatronics@live.com>
Sun, 3 Feb 2019 17:04:39 +0000 (18:04 +0100)
committerMatthias Schmidt <gravatronics@live.com>
Sun, 3 Feb 2019 17:04:39 +0000 (18:04 +0100)
Close #2843

wcfsetup/install/files/acp/js/WCF.ACP.js
wcfsetup/install/files/acp/templates/adAdd.tpl
wcfsetup/install/files/lib/acp/form/AdAddForm.class.php
wcfsetup/install/files/lib/data/ad/Ad.class.php
wcfsetup/install/files/lib/system/ad/AdHandler.class.php
wcfsetup/install/files/lib/system/ad/location/AbstractAdLocation.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/system/ad/location/IAdLocation.class.php [new file with mode: 0644]
wcfsetup/install/lang/de.xml
wcfsetup/install/lang/en.xml

index d48e7c392b52f78419954e960b1be18f8c9ca70d..cd09681e2e1aa7e8cd8d5cba11385fcbe2835935 100644 (file)
@@ -2480,11 +2480,17 @@ WCF.ACP.Ad.LocationHandler = Class.extend({
        
        /**
         * Initializes a new WCF.ACP.Ad.LocationHandler object.
+        * 
+        * @param       {object}        variablesDescriptions
         */
-       init: function() {
+       init: function(variablesDescriptions) {
+               this._variablesDescriptions = variablesDescriptions;
+               
                this._pageConditions = $('#pageConditions');
                this._pageInputs = $('input[name="pageIDs[]"]');
                
+               this._variablesDescriptionsList = $('#ad').next('small').children('ul');
+               
                var dl = $(this._pageInputs[0]).parents('dl:eq(0)');
                
                // hide the page controller elements
@@ -2551,6 +2557,13 @@ WCF.ACP.Ad.LocationHandler = Class.extend({
                                if (triggerEvent) Core.triggerEvent(this._pageInputs[i], 'change');
                        }
                }.bind(this));
+               
+               this._variablesDescriptionsList.children(':not(.jsDefaultItem)').remove();
+               
+               var objectTypeId = $('#objectTypeID').val();
+               if (objectTypeId in this._variablesDescriptions) {
+                       this._variablesDescriptionsList[0].innerHTML += this._variablesDescriptions[objectTypeId];
+               }
        },
        
        /**
index 3f438f87707780ed9b04cea3d303d0b7bcdc97b8..d583b758113225361ee3bcff3fc1d4eb33c721c4 100644 (file)
@@ -2,7 +2,9 @@
 
 <script data-relocate="true">
        $(function() {
-               new WCF.ACP.Ad.LocationHandler();
+               new WCF.ACP.Ad.LocationHandler({
+                       {implode from=$variablesDescriptions key=objectType item=description}'{$objectType}': '{@$description|encodeJS}'{/implode}
+               });
        });
 </script>
 
index a13764c2217aa1839607b3cc4abd4101787b846f..c2c66524ee0dbc06edf8a20ed13d02d0b215a90b 100644 (file)
@@ -5,6 +5,7 @@ use wcf\data\object\type\ObjectTypeCache;
 use wcf\data\ad\AdAction;
 use wcf\form\AbstractForm;
 use wcf\system\ad\AdHandler;
+use wcf\system\ad\location\IAdLocation;
 use wcf\system\condition\ConditionHandler;
 use wcf\system\exception\UserInputException;
 use wcf\system\WCF;
@@ -88,6 +89,16 @@ class AdAddForm extends AbstractForm {
        public function assignVariables() {
                parent::assignVariables();
                
+               $variablesDescriptions = [];
+               foreach ($this->locationObjectTypes as $objectType) {
+                       if ($objectType->className && is_subclass_of($objectType->className, IAdLocation::class)) {
+                               /** @var IAdLocation $adLocation */
+                               $adLocation = $objectType->getProcessor();
+                               
+                               $variablesDescriptions[$objectType->objectTypeID] = $adLocation->getVariablesDescription();
+                       }
+               }
+               
                WCF::getTPL()->assign([
                        'action' => 'add',
                        'ad' => $this->ad,
@@ -97,7 +108,8 @@ class AdAddForm extends AbstractForm {
                        'isDisabled' => $this->isDisabled,
                        'groupedConditionObjectTypes' => $this->groupedConditionObjectTypes,
                        'objectTypeID' => $this->objectTypeID,
-                       'showOrder' => $this->showOrder
+                       'showOrder' => $this->showOrder,
+                       'variablesDescriptions' => $variablesDescriptions
                ]);
        }
        
index 321130a57a5a6d7a633cc42f86b0a204113a1ab0..7f4a9ad07df15aa864ff6c5c29b26c2e74bc6943 100644 (file)
@@ -3,9 +3,11 @@ namespace wcf\data\ad;
 use wcf\data\condition\Condition;
 use wcf\data\object\type\ObjectTypeCache;
 use wcf\data\DatabaseObject;
+use wcf\system\ad\location\IAdLocation;
 use wcf\system\condition\ConditionHandler;
 use wcf\system\request\IRouteController;
 use wcf\system\WCF;
+use wcf\util\StringUtil;
 
 /**
  * Represents an ad.
@@ -56,4 +58,32 @@ class Ad extends DatabaseObject implements IRouteController {
        public function getTitle() {
                return $this->adName;
        }
+       
+       /**
+        * Returns the HTML code used to display the ad.
+        * 
+        * @return      string
+        * @since       5.2
+        */
+       public function getHtmlCode() {
+               $output = $this->ad;
+               
+               $objectType = ObjectTypeCache::getInstance()->getObjectType($this->objectTypeID);
+               
+               if (WCF::getUser()->userID) {
+                       $output = strtr($output, ['{$username}' => StringUtil::encodeHTML(WCF::getUser()->username)]);
+               }
+               else {
+                       $output = strtr($output, ['{$username}' => StringUtil::encodeHTML(WCF::getLanguage()->get('wcf.user.guest'))]);
+               }
+               
+               if ($objectType->className && is_subclass_of($objectType->className, IAdLocation::class)) {
+                       /** @var IAdLocation $adLocation */
+                       $adLocation = $objectType->getProcessor();
+                       
+                       $output = $adLocation->replaceVariables($output);
+               }
+               
+               return $output;
+       }
 }
index 79703f05b879dd1c753e03d667624f553b590d17..c671e9d45b0e19207d2e9450a0de2bdbb1cd6fb3 100644 (file)
@@ -62,7 +62,7 @@ class AdHandler extends SingletonFactory {
                                }
                        }
                        
-                       $output .= '<div>' . $ad->ad . '</div>';
+                       $output .= '<div>' . $ad->getHtmlCode() . '</div>';
                        if (ENABLE_AD_ROTATION) break;
                }
                
diff --git a/wcfsetup/install/files/lib/system/ad/location/AbstractAdLocation.class.php b/wcfsetup/install/files/lib/system/ad/location/AbstractAdLocation.class.php
new file mode 100644 (file)
index 0000000..dac08ba
--- /dev/null
@@ -0,0 +1,14 @@
+<?php
+namespace wcf\system\ad\location;
+
+/**
+ * Abstract implementation of the `IAdLocation` that has to be extended instead of implementing the
+ * interface directly.
+ * 
+ * @author     Matthias Schmidt
+ * @copyright  2001-2019 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    WoltLabSuite\Core\System\Ad\Location
+ * @since      5.2
+ */
+abstract class AbstractAdLocation implements IAdLocation {}
diff --git a/wcfsetup/install/files/lib/system/ad/location/IAdLocation.class.php b/wcfsetup/install/files/lib/system/ad/location/IAdLocation.class.php
new file mode 100644 (file)
index 0000000..dd8afab
--- /dev/null
@@ -0,0 +1,32 @@
+<?php
+namespace wcf\system\ad\location;
+
+/**
+ * Every ad location that provides custom variables has to provide a PHP class implementing this
+ * interface.
+ * 
+ * @author     Matthias Schmidt
+ * @copyright  2001-2019 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    WoltLabSuite\Core\System\Ad\Location
+ * @since      5.2
+ */
+interface IAdLocation {
+       /**
+        * Returns the description of the additional variables that can be used in ads in the active
+        * user's language.
+        * 
+        * The returned description will be inserted into a list, thus each variable should be in a
+        * list item (`<li>`) element.
+        * 
+        * @return      string
+        */
+       public function getVariablesDescription();
+       
+       /**
+        * Replaces all relevant variables in the given ad and returns the processed ad.
+        * 
+        * @return      string
+        */
+       public function replaceVariables($ad);
+}
index 0d6341fe3bd527eaa1d93c62f5e3dfc7e8646577..22c7dd94808b49deb135194a02dd54b421e11693 100644 (file)
        </category>
        <category name="wcf.acp.ad">
                <item name="wcf.acp.ad.ad"><![CDATA[Werbung]]></item>
-               <item name="wcf.acp.ad.ad.description"><![CDATA[HTML-Code der Werbung]]></item>
+               <item name="wcf.acp.ad.ad.description"><![CDATA[HTML-Code der Werbung. Die folgende Ausdrücke werden automatisch im HTML-Code ersetzt:\r
+<ul class="nativeList">\r
+       <li class="jsDefaultItem"><kbd>{literal}{$username}{/literal}</kbd> durch den Namen des aktiven Benutzers oder durch „Gast“</li>\r
+</ul>]]></item>
                <item name="wcf.acp.ad.add"><![CDATA[Werbung hinzufügen]]></item>
                <item name="wcf.acp.ad.conditions"><![CDATA[Bedingungen]]></item>
                <item name="wcf.acp.ad.conditions.description"><![CDATA[Werden keine Bedingungen ausgewählt, wird die Werbung für jeden Benutzer angezeigt.]]></item>
index 0b63e1611d8de6740dd3696c7a54cc7e949218b2..f68a58e9682c64e626e55459e23f4deecceed825 100644 (file)
        </category>
        <category name="wcf.acp.ad">
                <item name="wcf.acp.ad.ad"><![CDATA[Ads]]></item>
-               <item name="wcf.acp.ad.ad.description"><![CDATA[Enter the ad’s HTML code here.]]></item>
+               <item name="wcf.acp.ad.ad.description"><![CDATA[Enter the ad’s HTML code here. The following expressions will be automatically replace within the HTML code:\r
+<ul class="nativeList">\r
+       <li class="jsDefaultItem"><kbd>{literal}{$username}{/literal}</kbd> with the name of the active user or “Guest”</li>\r
+</ul>]]></item>
                <item name="wcf.acp.ad.add"><![CDATA[Add Ad]]></item>
                <item name="wcf.acp.ad.conditions"><![CDATA[Conditions]]></item>
                <item name="wcf.acp.ad.conditions.description"><![CDATA[If no conditions are specified, the ad will display for every user.]]></item>