From 6203f795144fad76f9607000b3ad0adf2291efef Mon Sep 17 00:00:00 2001
From: Guillaume Delhumeau <guillaume.delhumeau@xwiki.com>
Date: Mon, 9 Nov 2015 18:06:04 +0100
Subject: [PATCH] XWIKI-12485: Improve the watchlist icons.

---
 .../main/resources/flamingo/menus_content.vm  |  52 --
 .../java/org/xwiki/test/ui/po/BasePage.java   |  16 +-
 .../xwiki-platform-watchlist-ui/pom.xml       |  15 +
 .../XWiki/WatchListNotificationsUIX.xml       | 454 ++++++++++++++++++
 .../main/webapp/resources/js/xwiki/xwiki.js   |  12 +
 5 files changed, 489 insertions(+), 60 deletions(-)
 create mode 100644 xwiki-platform-core/xwiki-platform-watchlist/xwiki-platform-watchlist-ui/src/main/resources/XWiki/WatchListNotificationsUIX.xml

diff --git a/xwiki-platform-core/xwiki-platform-flamingo/xwiki-platform-flamingo-skin/xwiki-platform-flamingo-skin-resources/src/main/resources/flamingo/menus_content.vm b/xwiki-platform-core/xwiki-platform-flamingo/xwiki-platform-flamingo-skin/xwiki-platform-flamingo-skin-resources/src/main/resources/flamingo/menus_content.vm
index 5b96a9b0b22..5509fb35d90 100644
--- a/xwiki-platform-core/xwiki-platform-flamingo/xwiki-platform-flamingo-skin/xwiki-platform-flamingo-skin-resources/src/main/resources/flamingo/menus_content.vm
+++ b/xwiki-platform-core/xwiki-platform-flamingo/xwiki-platform-flamingo-skin/xwiki-platform-flamingo-skin-resources/src/main/resources/flamingo/menus_content.vm
@@ -222,58 +222,6 @@
 #macro(diplayOptionsMenu)
   #set ($staticExtensions = [])
   ##
-  ## WATCH /UNWATCH PAGE
-  ## TODO: the watchlist items will be moved afterwards, so we implement them here as static extensions for now,
-  ## but then we have to implement them as regular UIX in the watchlist module.
-  ##
-  #if (!$doc.isNew() && $hasWatch)
-    #set ($watchClasses = '')
-    #set ($unwatchClasses = 'hidden')
-    #if ($services.watchlist.isWatched("DOCUMENT"))
-      #set ($watchClasses = 'hidden')
-      #set ($unwatchClasses = '')
-    #end
-    #define ($watchPage)
-      #submenuitem("$xwiki.getURL($doc.documentReference, 'view', 'xpage=watch&amp;do=adddocument')&amp;xredirect=$escapetool.url($xwiki.getURL($doc.documentReference))" $services.localization.render('core.menu.watchlist.add.page') 'tmWatchDocument' $watchClasses 'eye-open')
-      #submenuitem("$xwiki.getURL($doc.documentReference, 'view', 'xpage=watch&amp;do=removedocument')&amp;xredirect=$escapetool.url($xwiki.getURL($doc.documentReference))" $services.localization.render('core.menu.watchlist.remove.page') 'tmUnwatchDocument' $unwatchClasses 'eye-close')
-    #end
-    #set ($discard = $staticExtensions.add( { 'content': $watchPage, 'order': 10000}))
-  #end
-  ##
-  ## WATCH /UNWATCH SPACE
-  ## TODO: see watch page
-  ##
-  #if ($hasWatch)
-    #set ($watchClasses = '')
-    #set ($unwatchClasses = 'hidden')
-    #if ($services.watchlist.isWatched("SPACE"))
-      #set ($watchClasses = 'hidden')
-      #set ($unwatchClasses = '')
-    #end
-    #define ($watchSpace)
-      #submenuitem("$doc.getURL('view', 'xpage=watch&amp;do=addspace')&amp;xredirect=$escapetool.url($doc.getURL())" $services.localization.render('core.menu.watchlist.add.space') 'tmWatchSpace', $watchClasses, 'eye-open')
-      #submenuitem("$doc.getURL('view', 'xpage=watch&amp;do=removespace')&amp;xredirect=$escapetool.url($doc.getURL())" $services.localization.render('core.menu.watchlist.remove.space') 'tmUnwatchSpace', $unwatchClasses, 'eye-close')
-    #end
-    #set ($discard = $staticExtensions.add( { 'content': $watchSpace, 'order': 20000}))
-  #end
-  ##
-  ## WATCH /UNWATCH WIKI
-  ## TODO: see watch page
-  ##
-  #if ($hasWatch)
-    #set ($watchClasses = '')
-    #set ($unwatchClasses = 'hidden')
-    #if ($services.watchlist.isWatched("WIKI"))
-      #set ($watchClasses = 'hidden')
-      #set ($unwatchClasses = '')
-    #end
-    #define ($watchWiki)
-      #submenuitem("$doc.getURL('view', 'xpage=watch&amp;do=addwiki')&amp;xredirect=$escapetool.url($doc.getURL())" $services.localization.render('core.menu.watchlist.add.wiki') 'tmWatchWiki', $watchClasses 'eye-open')
-      #submenuitem("$doc.getURL('view', 'xpage=watch&amp;do=removewiki')&amp;xredirect=$escapetool.url($doc.getURL())" $services.localization.render('core.menu.watchlist.remove.wiki') 'tmUnwatchWiki', $unwatchClasses 'eye-close')
-    #end
-    #set ($discard = $staticExtensions.add( { 'content': $watchWiki, 'order': 30000}))
-  #end
-  ##
   ## EXPORT / PRINT / SOURCE / SHARE
   ##
   #if ($canView)
diff --git a/xwiki-platform-core/xwiki-platform-test/xwiki-platform-test-ui/src/main/java/org/xwiki/test/ui/po/BasePage.java b/xwiki-platform-core/xwiki-platform-test/xwiki-platform-test-ui/src/main/java/org/xwiki/test/ui/po/BasePage.java
index ae65f9c6404..1b17e0f8c68 100644
--- a/xwiki-platform-core/xwiki-platform-test/xwiki-platform-test-ui/src/main/java/org/xwiki/test/ui/po/BasePage.java
+++ b/xwiki-platform-core/xwiki-platform-test/xwiki-platform-test-ui/src/main/java/org/xwiki/test/ui/po/BasePage.java
@@ -65,7 +65,7 @@ public class BasePage extends BaseElement
     @FindBy(id = "tmActionDelete")
     private WebElement deletePageLink;
 
-    @FindBy(id = "tmWatchDocument")
+    @FindBy(xpath = "//input[@id='tmWatchDocument']/../span[contains(@class, 'bootstrap-switch-label')]")
     private WebElement watchDocumentLink;
 
     @FindBy(id = "tmPage")
@@ -86,10 +86,10 @@ public class BasePage extends BaseElement
     @FindBy(id = "document-title")
     private WebElement documentTitle;
 
-    @FindBy(id = "tmWatchSpace")
+    @FindBy(xpath = "//input[@id='tmWatchSpace']/../span[contains(@class, 'bootstrap-switch-label')]")
     private WebElement watchSpaceLink;
 
-    @FindBy(id = "tmWatchWiki")
+    @FindBy(xpath = "//input[@id='tmWatchWiki']/../span[contains(@class, 'bootstrap-switch-label')]")
     private WebElement watchWikiLink;
 
     @FindBy(css = "#tmMoreActions a[title='Children']")
@@ -397,7 +397,7 @@ public boolean canDelete()
      */
     public void watchDocument()
     {
-        toggleActionMenu();
+        toggleNotificationsMenu();
         this.watchDocumentLink.click();
         toggleActionMenu();
     }
@@ -472,9 +472,9 @@ public String getDocumentTitle()
      */
     public void watchSpace()
     {
-        toggleActionMenu();
+        toggleNotificationsMenu();
         this.watchSpaceLink.click();
-        toggleActionMenu();
+        toggleNotificationsMenu();
     }
 
     /**
@@ -482,9 +482,9 @@ public void watchSpace()
      */
     public void watchWiki()
     {
-        toggleActionMenu();
+        toggleNotificationsMenu();
         this.watchWikiLink.click();
-        toggleActionMenu();
+        toggleNotificationsMenu();
     }
 
     /**
diff --git a/xwiki-platform-core/xwiki-platform-watchlist/xwiki-platform-watchlist-ui/pom.xml b/xwiki-platform-core/xwiki-platform-watchlist/xwiki-platform-watchlist-ui/pom.xml
index e286ac49c29..5dd64e81aa3 100644
--- a/xwiki-platform-core/xwiki-platform-watchlist/xwiki-platform-watchlist-ui/pom.xml
+++ b/xwiki-platform-core/xwiki-platform-watchlist/xwiki-platform-watchlist-ui/pom.xml
@@ -67,5 +67,20 @@
       <scope>runtime</scope>
       <type>xar</type>
     </dependency>
+    <!-- Needed to have the notifications menu. -->
+    <dependency>
+      <groupId>org.xwiki.platform</groupId>
+      <artifactId>xwiki-platform-notifications-ui</artifactId>
+      <version>${project.version}</version>
+      <scope>runtime</scope>
+      <type>xar</type>
+    </dependency>
+    <!-- Needed to have a nice toggle buttons on watchlist notifications area. -->
+    <dependency>
+      <groupId>org.webjars</groupId>
+      <artifactId>bootstrap-switch</artifactId>
+      <version>3.3.2</version>
+      <scope>runtime</scope>
+    </dependency>
   </dependencies>
 </project>
diff --git a/xwiki-platform-core/xwiki-platform-watchlist/xwiki-platform-watchlist-ui/src/main/resources/XWiki/WatchListNotificationsUIX.xml b/xwiki-platform-core/xwiki-platform-watchlist/xwiki-platform-watchlist-ui/src/main/resources/XWiki/WatchListNotificationsUIX.xml
new file mode 100644
index 00000000000..09b39615e86
--- /dev/null
+++ b/xwiki-platform-core/xwiki-platform-watchlist/xwiki-platform-watchlist-ui/src/main/resources/XWiki/WatchListNotificationsUIX.xml
@@ -0,0 +1,454 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ * See the NOTICE file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+-->
+
+<xwikidoc version="1.2" reference="XWiki.WatchListNotificationsUIX" locale="">
+  <web>XWiki</web>
+  <name>WatchListNotificationsUIX</name>
+  <language/>
+  <defaultLanguage/>
+  <translation>0</translation>
+  <creator>xwiki:XWiki.Admin</creator>
+  <creationDate>1446468725000</creationDate>
+  <parent>XWiki.WatchListMacro</parent>
+  <author>xwiki:XWiki.Admin</author>
+  <contentAuthor>xwiki:XWiki.Admin</contentAuthor>
+  <date>1447083576000</date>
+  <contentUpdateDate>1447068415000</contentUpdateDate>
+  <version>1.1</version>
+  <title/>
+  <comment/>
+  <minorEdit>false</minorEdit>
+  <syntaxId>xwiki/2.1</syntaxId>
+  <hidden>true</hidden>
+  <content/>
+  <object>
+    <name>XWiki.WatchListNotificationsUIX</name>
+    <number>0</number>
+    <className>XWiki.JavaScriptExtension</className>
+    <guid>5f5a2c84-f31f-4e63-a7cc-69cf394427c8</guid>
+    <class>
+      <name>XWiki.JavaScriptExtension</name>
+      <customClass/>
+      <customMapping/>
+      <defaultViewSheet/>
+      <defaultEditSheet/>
+      <defaultWeb/>
+      <nameField/>
+      <validationScript/>
+      <cache>
+        <cache>0</cache>
+        <disabled>0</disabled>
+        <displayType>select</displayType>
+        <multiSelect>0</multiSelect>
+        <name>cache</name>
+        <number>5</number>
+        <prettyName>Caching policy</prettyName>
+        <relationalStorage>0</relationalStorage>
+        <separator> </separator>
+        <separators>|, </separators>
+        <size>1</size>
+        <unmodifiable>0</unmodifiable>
+        <values>long|short|default|forbid</values>
+        <classType>com.xpn.xwiki.objects.classes.StaticListClass</classType>
+      </cache>
+      <code>
+        <disabled>0</disabled>
+        <name>code</name>
+        <number>2</number>
+        <prettyName>Code</prettyName>
+        <rows>20</rows>
+        <size>50</size>
+        <unmodifiable>0</unmodifiable>
+        <classType>com.xpn.xwiki.objects.classes.TextAreaClass</classType>
+      </code>
+      <name>
+        <disabled>0</disabled>
+        <name>name</name>
+        <number>1</number>
+        <prettyName>Name</prettyName>
+        <size>30</size>
+        <unmodifiable>0</unmodifiable>
+        <classType>com.xpn.xwiki.objects.classes.StringClass</classType>
+      </name>
+      <parse>
+        <disabled>0</disabled>
+        <displayFormType>select</displayFormType>
+        <displayType>yesno</displayType>
+        <name>parse</name>
+        <number>4</number>
+        <prettyName>Parse content</prettyName>
+        <unmodifiable>0</unmodifiable>
+        <classType>com.xpn.xwiki.objects.classes.BooleanClass</classType>
+      </parse>
+      <use>
+        <cache>0</cache>
+        <disabled>0</disabled>
+        <displayType>select</displayType>
+        <multiSelect>0</multiSelect>
+        <name>use</name>
+        <number>3</number>
+        <prettyName>Use this extension</prettyName>
+        <relationalStorage>0</relationalStorage>
+        <separator> </separator>
+        <separators>|, </separators>
+        <size>1</size>
+        <unmodifiable>0</unmodifiable>
+        <values>currentPage|onDemand|always</values>
+        <classType>com.xpn.xwiki.objects.classes.StaticListClass</classType>
+      </use>
+    </class>
+    <property>
+      <cache>long</cache>
+    </property>
+    <property>
+      <code>'use strict';
+## We handle the ability to disable the minification, by choosing the file extension to add to the script paths.
+#set ($jsExtension = '.min.js')
+#if (!$services.debug.minify)
+  #set ($jsExtension = '.js')
+#end
+///
+/// Start the requirejs config.
+///
+require.config({
+  paths: {
+    'bootstrap-switch': '$services.webjars.url('bootstrap-switch', "js/bootstrap-switch${jsExtension}")'
+  },
+  shim: {
+    'bootstrap-switch' : ['jquery']
+  }
+});
+///
+/// Start the real script
+///
+require(['jquery', 'bootstrap', 'bootstrap-switch'], function($) {
+  $(document).ready(function () {
+  
+    ///
+    /// Get the watchlist inputs for future usage
+    ///
+    var watchPageSwitch  = $('#tmWatchDocument');
+    var watchSpaceSwitch = $('#tmWatchSpace');
+    var watchWikiSwitch  = $('#tmWatchWiki');
+  
+    ///
+    /// Apply the bootstrap switch plugin to the watchlist inputs
+    ///
+    $('notifications-watchlist-item input').each(function() {
+      var input = $(this);
+      input.bootstrapSwitch('onColor', 'success');
+      input.bootstrapSwitch('offColor', 'danger');
+      input.bootstrapSwitch('onText', 'ON');
+      input.bootstrapSwitch('offText', 'OFF');
+      input.bootstrapSwitch('size', 'small');
+    });
+    
+    ///
+    /// Set the icon corresponding to each switch
+    ///
+    watchPageSwitch.bootstrapSwitch('labelText', '$escapetool.javascript($services.icon.renderHTML('page'))');
+    watchSpaceSwitch.bootstrapSwitch('labelText', '$escapetool.javascript($services.icon.renderHTML('chart-organisation'))');
+    watchWikiSwitch.bootstrapSwitch('labelText', '$escapetool.javascript($services.icon.renderHTML('wiki'))');
+    
+    ///
+    /// Add a tooltip to each switch
+    ///
+    $('.bootstrap-switch-id-tmWatchDocument').tooltip({title: 'Watch this page', placement: 'bottom'});
+    $('.bootstrap-switch-id-tmWatchSpace').tooltip({title: 'Watch this page and children', placement: 'bottom'});
+    $('.bootstrap-switch-id-tmWatchWiki').tooltip({title: 'Watch this wiki', placement: 'bottom'});
+    
+    /**
+     * Change the watchlist status of a document/space/wiki.
+     * @param action the action to execute ('adddocument', 'removedocument', 'addspace', 'removespace', 'addwiki'
+     * or 'removewiki').
+     */
+    var changeWatchListStatus = function (action) {
+      var url = XWiki.currentDocument.getURL('get', 'xpage=watch');
+      $.ajax(url, { 'data': { 'do': action } } )
+        .fail (function() {
+          new XWiki.widgets.Notification('Failed to change the status of the WatchList.', 'error');
+        });
+    }
+    
+    ///
+    /// Change the watchlist status when the switched are manipulated by the user
+    ///
+    watchPageSwitch.bootstrapSwitch('onSwitchChange', function (event, status) {
+      changeWatchListStatus(status ? 'adddocument' : 'removedocument');
+    });
+    watchSpaceSwitch.bootstrapSwitch('onSwitchChange', function (event, status) {
+      changeWatchListStatus(status ? 'addspace' : 'removespace');
+    });
+    watchWikiSwitch.bootstrapSwitch('onSwitchChange', function (event, status) {
+      changeWatchListStatus(status ? 'addwiki' : 'removewiki');
+    });
+
+    ///
+    /// Avoid the dropdown menu to be closed when the user click on the bootstrap switch
+    ///
+    $('.bootstrap-switch').click(function(event) {
+      event.stopImmediatePropagation();
+    });
+    
+  });
+});
+</code>
+    </property>
+    <property>
+      <name>JS</name>
+    </property>
+    <property>
+      <parse>1</parse>
+    </property>
+    <property>
+      <use>currentPage</use>
+    </property>
+  </object>
+  <object>
+    <name>XWiki.WatchListNotificationsUIX</name>
+    <number>0</number>
+    <className>XWiki.StyleSheetExtension</className>
+    <guid>9e56d70c-43b0-4008-9cce-ef2db85c0e64</guid>
+    <class>
+      <name>XWiki.StyleSheetExtension</name>
+      <customClass/>
+      <customMapping/>
+      <defaultViewSheet/>
+      <defaultEditSheet/>
+      <defaultWeb/>
+      <nameField/>
+      <validationScript/>
+      <cache>
+        <cache>0</cache>
+        <disabled>0</disabled>
+        <displayType>select</displayType>
+        <multiSelect>0</multiSelect>
+        <name>cache</name>
+        <number>6</number>
+        <prettyName>Caching policy</prettyName>
+        <relationalStorage>0</relationalStorage>
+        <separator> </separator>
+        <separators>|, </separators>
+        <size>1</size>
+        <unmodifiable>0</unmodifiable>
+        <values>long|short|default|forbid</values>
+        <classType>com.xpn.xwiki.objects.classes.StaticListClass</classType>
+      </cache>
+      <code>
+        <disabled>0</disabled>
+        <name>code</name>
+        <number>3</number>
+        <prettyName>Code</prettyName>
+        <rows>20</rows>
+        <size>50</size>
+        <unmodifiable>0</unmodifiable>
+        <classType>com.xpn.xwiki.objects.classes.TextAreaClass</classType>
+      </code>
+      <contentType>
+        <cache>0</cache>
+        <disabled>0</disabled>
+        <displayType>select</displayType>
+        <multiSelect>0</multiSelect>
+        <name>contentType</name>
+        <number>1</number>
+        <prettyName>Content Type</prettyName>
+        <relationalStorage>0</relationalStorage>
+        <separator> </separator>
+        <separators>|, </separators>
+        <size>1</size>
+        <unmodifiable>0</unmodifiable>
+        <values>CSS|LESS</values>
+        <classType>com.xpn.xwiki.objects.classes.StaticListClass</classType>
+      </contentType>
+      <name>
+        <disabled>0</disabled>
+        <name>name</name>
+        <number>2</number>
+        <prettyName>Name</prettyName>
+        <size>30</size>
+        <unmodifiable>0</unmodifiable>
+        <classType>com.xpn.xwiki.objects.classes.StringClass</classType>
+      </name>
+      <parse>
+        <disabled>0</disabled>
+        <displayFormType>select</displayFormType>
+        <displayType>yesno</displayType>
+        <name>parse</name>
+        <number>5</number>
+        <prettyName>Parse content</prettyName>
+        <unmodifiable>0</unmodifiable>
+        <classType>com.xpn.xwiki.objects.classes.BooleanClass</classType>
+      </parse>
+      <use>
+        <cache>0</cache>
+        <disabled>0</disabled>
+        <displayType>select</displayType>
+        <multiSelect>0</multiSelect>
+        <name>use</name>
+        <number>4</number>
+        <prettyName>Use this extension</prettyName>
+        <relationalStorage>0</relationalStorage>
+        <separator> </separator>
+        <separators>|, </separators>
+        <size>1</size>
+        <unmodifiable>0</unmodifiable>
+        <values>currentPage|onDemand|always</values>
+        <classType>com.xpn.xwiki.objects.classes.StaticListClass</classType>
+      </use>
+    </class>
+    <property>
+      <cache>long</cache>
+    </property>
+    <property>
+      <code>/* TODO: replace with @import statement when XWIKI-12788 is closed. Reason: http://www.stevesouders.com/blog/2009/04/09/dont-use-import/ */
+@import url("$services.webjars.url('bootstrap-switch', 'css/bootstrap3/bootstrap-switch.min.css')");
+
+.notifications-watchlist-item {
+  margin: 0;
+  padding: 5px;
+  text-align: center;
+  text-transform: uppercase;
+}
+
+.notifications-watchlist-item pre {
+  margin: 0;
+}
+
+.notifications-watchlist-item .bootstrap-switch .bootstrap-switch-label {
+  /* TODO: use color theme */
+  background-image: linear-gradient(#FFF, #ECECEC 50%, #DFDFDF);
+}
+</code>
+    </property>
+    <property>
+      <contentType>CSS</contentType>
+    </property>
+    <property>
+      <name>CSS</name>
+    </property>
+    <property>
+      <parse>1</parse>
+    </property>
+    <property>
+      <use>currentPage</use>
+    </property>
+  </object>
+  <object>
+    <name>XWiki.WatchListNotificationsUIX</name>
+    <number>0</number>
+    <className>XWiki.UIExtensionClass</className>
+    <guid>684dc8f1-fa89-4748-b9f0-2e83295dfa22</guid>
+    <class>
+      <name>XWiki.UIExtensionClass</name>
+      <customClass/>
+      <customMapping/>
+      <defaultViewSheet/>
+      <defaultEditSheet/>
+      <defaultWeb/>
+      <nameField/>
+      <validationScript/>
+      <content>
+        <disabled>0</disabled>
+        <name>content</name>
+        <number>3</number>
+        <prettyName>Extension Content</prettyName>
+        <rows>10</rows>
+        <size>40</size>
+        <unmodifiable>0</unmodifiable>
+        <classType>com.xpn.xwiki.objects.classes.TextAreaClass</classType>
+      </content>
+      <extensionPointId>
+        <disabled>0</disabled>
+        <name>extensionPointId</name>
+        <number>1</number>
+        <prettyName>Extension Point ID</prettyName>
+        <size>30</size>
+        <unmodifiable>0</unmodifiable>
+        <classType>com.xpn.xwiki.objects.classes.StringClass</classType>
+      </extensionPointId>
+      <name>
+        <disabled>0</disabled>
+        <name>name</name>
+        <number>2</number>
+        <prettyName>Extension ID</prettyName>
+        <size>30</size>
+        <unmodifiable>0</unmodifiable>
+        <classType>com.xpn.xwiki.objects.classes.StringClass</classType>
+      </name>
+      <parameters>
+        <disabled>0</disabled>
+        <name>parameters</name>
+        <number>4</number>
+        <prettyName>Extension Parameters</prettyName>
+        <rows>10</rows>
+        <size>40</size>
+        <unmodifiable>0</unmodifiable>
+        <classType>com.xpn.xwiki.objects.classes.TextAreaClass</classType>
+      </parameters>
+      <scope>
+        <cache>0</cache>
+        <disabled>0</disabled>
+        <displayType>select</displayType>
+        <multiSelect>0</multiSelect>
+        <name>scope</name>
+        <number>5</number>
+        <prettyName>Extension Scope</prettyName>
+        <relationalStorage>0</relationalStorage>
+        <separator> </separator>
+        <separators>|, </separators>
+        <size>1</size>
+        <unmodifiable>0</unmodifiable>
+        <values>wiki=Current Wiki|user=Current User|global=Global</values>
+        <classType>com.xpn.xwiki.objects.classes.StaticListClass</classType>
+      </scope>
+    </class>
+    <property>
+      <content>{{velocity}}{{html clean="false"}} ## we need clean="false" because we want to display the raw content of #submenuitem()
+##
+## Enable SSX and JSX
+##
+#set ($discard = $xwiki.ssx.use('XWiki.WatchListNotificationsUIX'))
+#set ($discard = $xwiki.jsx.use('XWiki.WatchListNotificationsUIX'))
+##
+## Display the 3 toggle buttons
+##
+&lt;li class="notifications-watchlist-item"&gt;
+  #macro(displayCheckedIfWatched $scope)#if($services.watchlist.isWatched($scope))checked="checked"#end#end
+  &lt;pre&gt;&lt;input type="checkbox" id="tmWatchDocument" #displayCheckedIfWatched('DOCUMENT')/&gt; &lt;input type="checkbox" id="tmWatchSpace" displayCheckedIfWatched('SPACE')/&gt; &lt;input type="checkbox" id="tmWatchWiki" displayCheckedIfWatched('WIKI')/&gt;&lt;/pre&gt;
+&lt;/li&gt;
+</content>
+    </property>
+    <property>
+      <extensionPointId>org.xwiki.platform.notifications</extensionPointId>
+    </property>
+    <property>
+      <name>org.xwiki.platform.watchlist.ui.watchlistNotificationUix</name>
+    </property>
+    <property>
+      <parameters>order:10000
+separator:true</parameters>
+    </property>
+    <property>
+      <scope>wiki</scope>
+    </property>
+  </object>
+</xwikidoc>
diff --git a/xwiki-platform-core/xwiki-platform-web/src/main/webapp/resources/js/xwiki/xwiki.js b/xwiki-platform-core/xwiki-platform-web/src/main/webapp/resources/js/xwiki/xwiki.js
index fe6587d6f45..41b09bff8ea 100644
--- a/xwiki-platform-core/xwiki-platform-web/src/main/webapp/resources/js/xwiki/xwiki.js
+++ b/xwiki-platform-core/xwiki-platform-web/src/main/webapp/resources/js/xwiki/xwiki.js
@@ -411,6 +411,9 @@ Object.extend(XWiki, {
 
   /**
    * Watchlist methods.
+   * 
+   * @deprecated Since XWiki 7.4, the watchlist UI is implemented in a UI extension. This code is still there to not 
+   * break the retro-compatibility but we can consider removing it.
    */
   watchlist : {
 
@@ -474,6 +477,15 @@ Object.extend(XWiki, {
             if (element.nodeName != 'A') {
               element = $(button).down('A');
             }
+            
+            if (!element) {
+              // This is supposed to happen every time since the watchlist icons are implemented in the notifications
+              // menu. The watchlist icons are now implemented as a UI extension, and the inputs are handled with a 
+              // custom solution (bootstrap-switch).
+              // For these reasons, we stop the initialization here.
+              // We keep this function for old skins (like Colibri), that still have the old-fashioned watchlist icons.
+              return;
+            }
 
             // unregister previously registered handler if any
             element.stopObserving('click');
-- 
GitLab