Added privacy settings for social networks
authorAlexander Ebert <ebert@woltlab.com>
Mon, 21 Jul 2014 13:10:57 +0000 (15:10 +0200)
committerAlexander Ebert <ebert@woltlab.com>
Mon, 21 Jul 2014 13:10:57 +0000 (15:10 +0200)
com.woltlab.wcf/templates/shareButtons.tpl
com.woltlab.wcf/templates/shareButtonsPrivacySettings.tpl [new file with mode: 0644]
wcfsetup/install/files/js/WCF.Message.js
wcfsetup/install/files/lib/data/user/User.class.php
wcfsetup/install/files/lib/data/user/UserAction.class.php
wcfsetup/install/files/style/message.less
wcfsetup/install/lang/de.xml
wcfsetup/install/lang/en.xml
wcfsetup/setup/db/install.sql

index 1369f32420d99c402611fab8f7f0b2749b23be94..218de9447717573fb65b5a0e0d5508f689d39269 100644 (file)
                                'wcf.message.share.facebook': '{lang}wcf.message.share.facebook{/lang}',
                                'wcf.message.share.google': '{lang}wcf.message.share.google{/lang}',
                                'wcf.message.share.reddit': '{lang}wcf.message.share.reddit{/lang}',
-                               'wcf.message.share.twitter': '{lang}wcf.message.share.twitter{/lang}'
+                               'wcf.message.share.twitter': '{lang}wcf.message.share.twitter{/lang}',
+                               'wcf.message.share.privacy': '{lang}wcf.message.share.privacy{/lang}'
                        });
-                       
-                       new WCF.Message.Share.Page({if SHARE_BUTTONS_SHOW_COUNT}true{else}false{/if});
+                       var $privacySettings = { {implode from=$__wcf->getUser()->getSocialNetworkPrivacySettings() key=provider item=value}'{$provider}': {if $value}true{else}false{/if}{/implode} };
+                       new WCF.Message.Share.Page({if SHARE_BUTTONS_SHOW_COUNT}true{else}false{/if}, $privacySettings);
                });
                //]]>
        </script>
diff --git a/com.woltlab.wcf/templates/shareButtonsPrivacySettings.tpl b/com.woltlab.wcf/templates/shareButtonsPrivacySettings.tpl
new file mode 100644 (file)
index 0000000..97e138a
--- /dev/null
@@ -0,0 +1,25 @@
+<fieldset>
+       <legend>{lang}wcf.message.share.privacy{/lang}</legend>
+       <small style="max-width: 500px;">{lang}wcf.message.share.privacy.description{/lang}</small>
+       
+       <dl class="wide">
+               <dt></dt>
+               <dd><label><input type="checkbox" name="facebook" value="1"{if $settings[facebook]} checked="checked"{/if} /> {lang}wcf.message.share.facebook{/lang}</label></dd>
+       </dl>
+       <dl class="wide">
+               <dt></dt>
+               <dd><label><input type="checkbox" name="twitter" value="1"{if $settings[twitter]} checked="checked"{/if} /> {lang}wcf.message.share.twitter{/lang}</label></dd>
+       </dl>
+       <dl class="wide">
+               <dt></dt>
+               <dd><label><input type="checkbox" name="google" value="1"{if $settings[google]} checked="checked"{/if} /> {lang}wcf.message.share.google{/lang}</label></dd>
+       </dl>
+       <dl class="wide">
+               <dt></dt>
+               <dd><label><input type="checkbox" name="reddit" value="1"{if $settings[reddit]} checked="checked"{/if} /> {lang}wcf.message.share.reddit{/lang}</label></dd>
+       </dl>
+</fieldset>
+
+<div class="formSubmit">
+       <input type="submit" value="{lang}wcf.global.button.submit{/lang}" accesskey="s" />
+</div>
index 5128ef800b7a2947bc59b2850abf02e65035b1a2..1b3e56c2742779e81ae074e61fc97d6f0cd627ba 100644 (file)
@@ -2976,13 +2976,20 @@ WCF.Message.Share.Content = Class.extend({
  * Provides buttons to share a page through multiple social community sites.
  * 
  * @param      boolean         fetchObjectCount
+ * @param      object          privacySettings
  */
 WCF.Message.Share.Page = Class.extend({
        /**
-        * list of share buttons
-        * @var object
+        * dialog overlay
+        * @var jQuery
+        */
+       _dialog: null,
+       
+       /**
+        * true if share count should be fetched
+        * @var boolean
         */
-       _ui: { },
+       _fetchObjectCount: false,
        
        /**
         * page description
@@ -2996,72 +3003,228 @@ WCF.Message.Share.Page = Class.extend({
         */
        _pageURL: '',
        
+       /**
+        * list of privacy settings per social media site
+        */
+       _privacySettings: { },
+       
+       /**
+        * list of provider links and share callback
+        * @var object<object>
+        */
+       _provider: { },
+       
+       /**
+        * action proxy
+        * @var WCF.Action.Proxy
+        */
+       _proxy: null,
+       
        /**
         * Initializes the WCF.Message.Share.Page class.
         * 
         * @param       boolean         fetchObjectCount
+        * @param       object          privacySettings
         */
-       init: function(fetchObjectCount) {
+       init: function(fetchObjectCount, privacySettings) {
+               this._dialog = null;
+               this._fetchObjectCount = (fetchObjectCount === true) ? true : false;
                this._pageDescription = encodeURIComponent($('meta[property="og:title"]').prop('content'));
                this._pageURL = encodeURIComponent($('meta[property="og:url"]').prop('content'));
+               this._privacySettings = $.extend({
+                       facebook: false,
+                       google: false,
+                       twitter: false,
+                       reddit: false
+               }, privacySettings || { });
+               this._proxy = null;
                
+               this._initProvider();
+       },
+       
+       /**
+        * Initializes all social media providers.
+        */
+       _initProvider: function() {
                var $container = $('.messageShareButtons');
-               this._ui = {
-                       facebook: $container.find('.jsShareFacebook'),
-                       google: $container.find('.jsShareGoogle'),
-                       reddit: $container.find('.jsShareReddit'),
-                       twitter: $container.find('.jsShareTwitter')
+               var self = this;
+               this._provider = {
+                       facebook: {
+                               fetch: function() { self._fetchFacebook(); },
+                               link: $container.find('.jsShareFacebook'),
+                               share: function() { self._share('facebook', 'https://www.facebook.com/sharer.php?u={pageURL}&t={text}', true); }
+                       },
+                       google: {
+                               fetch: undefined,
+                               link: $container.find('.jsShareGoogle'),
+                               share: function() { self._share('google', 'https://plus.google.com/share?url={pageURL}', true); }
+                       },
+                       reddit: {
+                               fetch: function() { self._fetchReddit(); },
+                               link:$container.find('.jsShareReddit'),
+                               share: function() { self._share('reddit', 'https://ssl.reddit.com/submit?url={pageURL}', true); }
+                       },
+                       twitter: {
+                               fetch: function() { self._fetchTwitter(); },
+                               link: $container.find('.jsShareTwitter'),
+                               share: function() { self._share('twitter', 'https://twitter.com/share?url={pageURL}&text={text}', false); }
+                       }
                };
                
-               this._ui.facebook.children('a').click($.proxy(this._shareFacebook, this));
-               this._ui.google.children('a').click($.proxy(this._shareGoogle, this));
-               this._ui.reddit.children('a').click($.proxy(this._shareReddit, this));
-               this._ui.twitter.children('a').click($.proxy(this._shareTwitter, this));
+               $.each(this._provider, function(provider, data) {
+                       if (self._privacySettings[provider]) {
+                               if (self._fetchObjectCount && data.fetch) {
+                                       data.fetch();
+                               }
+                       }
+                       else {
+                               data.link.addClass('disabled');
+                       }
+                       
+                       data.link.data('provider', provider).click($.proxy(self._click, self));
+               });
                
-               if (fetchObjectCount === true) {
-                       this._fetchFacebook();
-                       this._fetchTwitter();
-                       this._fetchReddit();
+               if (WCF.User.userID) {
+                       var $openSettings = $('<li class="jsShowPrivacySettings"><a><span class="icon icon32 fa-gear jsTooltip" title="' + WCF.Language.get('wcf.message.share.privacy') + '" /></a></li>');
+                       $openSettings.appendTo($container.children('ul')).children('a').click($.proxy(this._openPrivacySettings, this));
                }
        },
        
        /**
-        * Shares current page to selected social community site.
+        * Handles clicks on a social media provider link.
         * 
-        * @param       string          objectName
-        * @param       string          url
-        * @param       boolean         appendURL
+        * @param       object          event
         */
-       _share: function(objectName, url, appendURL) {
-               window.open(url.replace(/{pageURL}/, this._pageURL).replace(/{text}/, this._pageDescription + (appendURL ? " " + this._pageURL : "")), 'height=600,width=600');
+       _click: function(event) {
+               var $link = $(event.currentTarget);
+               var $provider = $link.data('provider');
+               
+               if ($link.hasClass('disabled')) {
+                       if (WCF.User.userID) {
+                               this._openPrivacySettings();
+                       }
+                       else {
+                               // guest => enable button
+                               $link.removeClass('disabled');
+                       }
+               }
+               else {
+                       this._provider[$provider].share();
+               }
+       },
+       
+       /**
+        * Opens the privacy settings dialog.
+        */
+       _openPrivacySettings: function() {
+               if (this._proxy === null) {
+                       this._proxy = new WCF.Action.Proxy({
+                               success: $.proxy(this._success, this)
+                       });
+               }
+               
+               this._proxy.setOption('data', {
+                       actionName: 'getSocialNetworkPrivacySettings',
+                       className: 'wcf\\data\\user\\UserAction'
+               });
+               this._proxy.sendRequest();
+       },
+       
+       /**
+        * Handles successful AJAX requests.
+        * 
+        * @param       object          data
+        * @param       string          textStatus
+        * @param       jQuery          jqXHR
+        */
+       _success: function(data, textStatus, jqXHR) {
+               switch (data.actionName) {
+                       case 'getSocialNetworkPrivacySettings':
+                               this._renderDialog(data);
+                       break;
+                       
+                       case 'saveSocialNetworkPrivacySettings':
+                               this._updatePrivacySettings(data);
+                       break;
+               }
        },
        
        /**
-        * Shares current page with Facebook.
+        * Renders the settings dialog.
+        * 
+        * @param       object          data
         */
-       _shareFacebook: function() {
-               this._share('facebook', 'https://www.facebook.com/sharer.php?u={pageURL}&t={text}', true);
+       _renderDialog: function(data) {
+               if (this._dialog === null) {
+                       this._dialog = $('<div />').hide().appendTo(document.body);
+                       this._dialog.html(data.returnValues.template);
+                       this._dialog.wcfDialog({
+                               title: WCF.Language.get('wcf.message.share.privacy')
+                       });
+               }
+               else {
+                       this._dialog.html(data.returnValues.template);
+                       this._dialog.wcfDialog('open');
+               }
+               
+               this._dialog.find('input[type=submit]').click($.proxy(this._save, this));
        },
        
        /**
-        * Shares current page with Google Plus.
+        * Saves settings.
         */
-       _shareGoogle: function() {
-               this._share('google', 'https://plus.google.com/share?url={pageURL}', true);
+       _save: function() {
+               this._proxy.setOption('data', {
+                       actionName: 'saveSocialNetworkPrivacySettings',
+                       className: 'wcf\\data\\user\\UserAction',
+                       parameters: {
+                               facebook: (this._dialog.find('input[name=facebook]').is(':checked')),
+                               google: (this._dialog.find('input[name=google]').is(':checked')),
+                               reddit: (this._dialog.find('input[name=reddit]').is(':checked')),
+                               twitter: (this._dialog.find('input[name=twitter]').is(':checked'))
+                       }
+               });
+               this._proxy.sendRequest();
+               
+               this._dialog.wcfDialog('close');
        },
        
        /**
-        * Shares current page with Reddit.
+        * Updates the internal privacy settings.
+        * 
+        * @param       object          data
         */
-       _shareReddit: function() {
-               this._share('reddit', 'https://ssl.reddit.com/submit?url={pageURL}', true);
+       _updatePrivacySettings: function(data) {
+               this._privacySettings = $.extend(this._privacySettings, data.returnValues.settings);
+               
+               var self = this;
+               $.each(data.returnValues.settings, function(provider, status) {
+                       self._privacySettings[provider] = (status) ? true : false;
+                       
+                       if (status) {
+                               self._provider[provider].link.removeClass('disabled');
+                               
+                               if (self._fetchObjectCount && self._provider[provider].fetch) {
+                                       self._provider[provider].fetch();
+                               }
+                       }
+                       else {
+                               self._provider[provider].link.addClass('disabled');
+                       }
+               });
+               
+               new WCF.System.Notification().show();
        },
        
        /**
-        * Shares current page with Twitter.
+        * Shares current page to selected social community site.
+        * 
+        * @param       string          objectName
+        * @param       string          url
+        * @param       boolean         appendURL
         */
-       _shareTwitter: function() {
-               this._share('twitter', 'https://twitter.com/share?url={pageURL}&text={text}', false);
+       _share: function(objectName, url, appendURL) {
+               window.open(url.replace(/{pageURL}/, this._pageURL).replace(/{text}/, this._pageDescription + (appendURL ? " " + this._pageURL : "")), 'height=600,width=600');
        },
        
        /**
@@ -3094,7 +3257,7 @@ WCF.Message.Share.Page = Class.extend({
        _fetchFacebook: function() {
                this._fetchCount('https://graph.facebook.com/?id={pageURL}', $.proxy(function(data) {
                        if (data.shares) {
-                               this._ui.facebook.children('span.badge').show().text(data.shares);
+                               this._provider.facebook.link.children('span.badge').show().text(data.shares);
                        }
                }, this));
        },
@@ -3107,7 +3270,7 @@ WCF.Message.Share.Page = Class.extend({
                
                this._fetchCount('http://urls.api.twitter.com/1/urls/count.json?url={pageURL}', $.proxy(function(data) {
                        if (data.count) {
-                               this._ui.twitter.children('span.badge').show().text(data.count);
+                               this._provider.twitter.link.children('span.badge').show().text(data.count);
                        }
                }, this));
        },
@@ -3120,7 +3283,7 @@ WCF.Message.Share.Page = Class.extend({
                
                this._fetchCount('http://www.reddit.com/api/info.json?url={pageURL}', $.proxy(function(data) {
                        if (data.data.children.length) {
-                               this._ui.reddit.children('span.badge').show().text(data.data.children[0].data.score);
+                               this._provider.reddit.link.children('span.badge').show().text(data.data.children[0].data.score);
                        }
                }, this), 'jsonp');
        }
index 6d3a69be8e2cb8f4c365587498ddf57156f58eaa..6a0fe802a296d045aca4b864c98aabd947876b5e 100644 (file)
@@ -463,4 +463,22 @@ final class User extends DatabaseObject implements IRouteController, IUserConten
                        'forceFrontend' => true
                ));
        }
+       
+       public function getSocialNetworkPrivacySettings() {
+               $settings = false;
+               if ($this->userID && WCF::getUser()->socialNetworkPrivacySettings) {
+                       $settings = @unserialize(WCF::getUser()->socialNetworkPrivacySettings);
+               }
+               
+               if ($settings === false) {
+                       $settings = array(
+                               'facebook' => false,
+                               'google' => false,
+                               'reddit' => false,
+                               'twitter' => false
+                       );
+               }
+               
+               return $settings;
+       }
 }
index c0cc84c35b745819bb48232f5f0c5944e3d7b72e..b46b66804ef250a4c8023f0800f66796fdc2dfe8 100644 (file)
@@ -16,6 +16,8 @@ use wcf\system\mail\Mail;
 use wcf\system\request\RequestHandler;
 use wcf\system\WCF;
 use wcf\util\UserRegistrationUtil;
+use wcf\util\JSON;
+use wcf\system\exception\SystemException;
 
 /**
  * Executes user-related actions.
@@ -744,4 +746,59 @@ class UserAction extends AbstractDatabaseObjectAction implements IClipboardActio
                        ));
                }
        }
+       
+       /**
+        * Validates parameters to retrieve the social network privacy settings.
+        */
+       public function validateGetSocialNetworkPrivacySettings() { /* does nothing */ }
+       
+       /**
+        * Returns the social network privacy settings.
+        * 
+        * @return      array<string>
+        */
+       public function getSocialNetworkPrivacySettings() {
+               $settings = @unserialize(WCF::getUser()->socialNetworkPrivacySettings);
+               if (!is_array($settings)) {
+                       $settings = array(
+                               'facebook' => false,
+                               'google' => false,
+                               'reddit' => false,
+                               'twitter' => false
+                       );
+               }
+               
+               WCF::getTPL()->assign(array(
+                       'settings' => $settings
+               ));
+               
+               return array(
+                       'template' => WCF::getTPL()->fetch('shareButtonsPrivacySettings')
+               );
+       }
+       
+       public function validateSaveSocialNetworkPrivacySettings() {
+               $this->readBoolean('facebook', true);
+               $this->readBoolean('google', true);
+               $this->readBoolean('reddit', true);
+               $this->readBoolean('twitter', true);
+       }
+       
+       public function saveSocialNetworkPrivacySettings() {
+               $settings = array(
+                       'facebook' => $this->parameters['facebook'],
+                       'google' => $this->parameters['google'],
+                       'reddit' => $this->parameters['reddit'],
+                       'twitter' => $this->parameters['twitter']
+               );
+               
+               $userEditor = new UserEditor(WCF::getUser());
+               $userEditor->update(array(
+                       'socialNetworkPrivacySettings' => serialize($settings)
+               ));
+               
+               return array(
+                       'settings' => $settings
+               );
+       }
 }
index 7ff9317bc7bfbdd49cf21ba2d5bfb6133020097e..da8066cfebdb19f17e03c02c4f2f11daa83f1b86 100644 (file)
@@ -891,34 +891,27 @@ li:nth-child(2n+1) .message {
                }
        }
        
-       .jsShareFacebook {
+       .jsShareFacebook:not(.disabled) {
                > a > .icon {
                        color: rgb(59, 89, 152);
                }
        }
        
-       .jsShareTwitter {
+       .jsShareTwitter:not(.disabled) {
                > a > .icon {
                        color: rgb(64, 153, 255);
                }
        }
        
-       .jsShareGoogle {
+       .jsShareGoogle:not(.disabled) {
                > a > .icon {
                        color: rgb(211, 72, 54);
                }
        }
        
-       .jsShareReddit {
-               > a > img {
-                       width: 24px;
-                       height: 24px;
-                       margin: 0 4px 4px;
-                       box-shadow: 0 1px 0 rgba(255, 255, 255, .8);
-                       border-radius: 3px;
-                       
-                       /* smooth fixes */
-                       background-color: rgba(255, 255, 255, .8);
+       .jsShareReddit:not(.disabled) {
+               > a > .icon {
+                       color: rgb(95, 153, 207);
                }
        }
 }
index e878c771d8f4823db328cbafd2b9d5d2abdebd4b..daf77c55a670e5937c5b5c953af3036d635e0a1c 100644 (file)
@@ -2166,6 +2166,8 @@ Fehler sind beispielsweise:
                <item name="wcf.message.share.permalink.html"><![CDATA[HTML]]></item>
                <item name="wcf.message.share.reddit"><![CDATA[Reddit]]></item>
                <item name="wcf.message.share.twitter"><![CDATA[Twitter]]></item>
+               <item name="wcf.message.share.privacy"><![CDATA[Einstellungen zum Teilen]]></item>
+               <item name="wcf.message.share.privacy.description"><![CDATA[Die Anzahl der Teilungen auf der jeweiligen Plattform werden nur bei aktivierten Anbietern ermittelt, diese Angaben werden durch Ihren Browser direkt vom Anbieter abgefragt.]]></item>
                <item name="wcf.message.smilies"><![CDATA[Smileys]]></item>
                <item name="wcf.message.button.extendedReply"><![CDATA[Erweiterte Antwort]]></item>
                <item name="wcf.message.button.extendedEdit"><![CDATA[Erweiterte Bearbeitung]]></item>
index 01c8cbcbb6719b68633f3fd327dadba366e3ab3f..71c87749e337dad8abd0b5570b4d15a59e96a2f5 100644 (file)
@@ -2134,6 +2134,8 @@ Errors are:
                <item name="wcf.message.share.permalink.html"><![CDATA[HTML]]></item>
                <item name="wcf.message.share.reddit"><![CDATA[Reddit]]></item>
                <item name="wcf.message.share.twitter"><![CDATA[Twitter]]></item>
+               <item name="wcf.message.share.privacy"><![CDATA[Privacy Settings]]></item>
+               <item name="wcf.message.share.privacy.description"><![CDATA[Displaying the number of shares is only available for enabled providers, data will be fetched directly using your browser.]]></item>
                <item name="wcf.message.smilies"><![CDATA[Smilies]]></item>
                <item name="wcf.message.button.extendedReply"><![CDATA[More Options]]></item>
                <item name="wcf.message.button.extendedEdit"><![CDATA[More Options]]></item>
index 9075e2585aa1951edf9c20ad66e394fb3e8c800d..2b285a5f179aa9320b327961e17a9013a2eb4652 100644 (file)
@@ -1091,6 +1091,7 @@ CREATE TABLE wcf1_user (
        notificationMailToken VARCHAR(20) NOT NULL DEFAULT '',
        authData VARCHAR(255) NOT NULL DEFAULT '',
        likesReceived MEDIUMINT(7) NOT NULL DEFAULT 0,
+       socialNetworkPrivacySettings TEXT,
        
        KEY username (username),
        KEY registrationDate (registrationDate),