[TASK] Migrate cshmanual javascript to AMD module 37/37837/8
authorFrank Nägler <typo3@naegler.net>
Sat, 14 Mar 2015 00:01:00 +0000 (01:01 +0100)
committerWouter Wolters <typo3@wouterwolters.nl>
Thu, 19 Mar 2015 22:47:33 +0000 (23:47 +0100)
This patch remove the old contexthelp.js and introduce a new AMD
module. With the new ContextHelp we introduce bootstraps popover.

Resolves: #65735
Releases: master
Change-Id: If44dc2ed1301cbef10ce33100c4a2c6a1cbf73f3
Reviewed-on: http://review.typo3.org/37837
Reviewed-by: Markus Klein <klein.t3@reelworx.at>
Tested-by: Markus Klein <klein.t3@reelworx.at>
Reviewed-by: Wouter Wolters <typo3@wouterwolters.nl>
Tested-by: Wouter Wolters <typo3@wouterwolters.nl>
12 files changed:
typo3/sysext/backend/Classes/Controller/BackendController.php
typo3/sysext/backend/Classes/Template/DocumentTemplate.php
typo3/sysext/backend/Resources/Public/JavaScript/ContextHelp.js [new file with mode: 0644]
typo3/sysext/backend/Resources/Public/JavaScript/Popover.js [new file with mode: 0644]
typo3/sysext/backend/Resources/Public/JavaScript/contexthelp.js [deleted file]
typo3/sysext/backend/Resources/Public/JavaScript/notifications.js
typo3/sysext/context_help/Classes/Controller/ContextHelpAjaxController.php [new file with mode: 0644]
typo3/sysext/context_help/ext_tables.php
typo3/sysext/t3skin/Resources/Private/Styles/TYPO3/_element_csh.less
typo3/sysext/t3skin/Resources/Private/Styles/TYPO3/_element_popover.less [new file with mode: 0644]
typo3/sysext/t3skin/Resources/Private/Styles/t3skin.less
typo3/sysext/t3skin/Resources/Public/Css/visual/t3skin.css

index 38675e1..618bb50 100644 (file)
@@ -248,9 +248,9 @@ class BackendController {
                        TYPO3.Backend = new TYPO3.Viewport(TYPO3.Viewport.configuration);
                        if (typeof console === "undefined") {
                                console = TYPO3.Backend.DebugConsole;
-                       }
-                       TYPO3.ContextHelpWindow.init(' . GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('help_cshmanual')) . ');';
+                       }';
                $this->pageRenderer->addExtOnReadyCode($extOnReadyCode);
+               $this->pageRenderer->addInlineSetting('ContextHelp', 'moduleUrl', BackendUtility::getModuleUrl('help_cshmanual'));
                // Set document title:
                $title = $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'] ? $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'] . ' [TYPO3 CMS ' . TYPO3_version . ']' : 'TYPO3 CMS ' . TYPO3_version;
                // Renders the module page
index a739f34..ea365a7 100644 (file)
@@ -1512,9 +1512,7 @@ function jumpToUrl(URL) {
         * @return void
         */
        protected function loadCshJavascript() {
-               $this->pageRenderer->loadExtJS();
-               $this->pageRenderer->addJsFile($this->backPath . 'sysext/backend/Resources/Public/JavaScript/contexthelp.js');
-               $this->pageRenderer->addExtDirectCode();
+               $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/ContextHelp');
        }
 
        /**
diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/ContextHelp.js b/typo3/sysext/backend/Resources/Public/JavaScript/ContextHelp.js
new file mode 100644 (file)
index 0000000..9ac191d
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * API for context help.
+ */
+define('TYPO3/CMS/Backend/ContextHelp', ['jquery', 'TYPO3/CMS/Backend/Popover'], function($) {
+
+       /**
+        * The main ContextHelp object
+        *
+        * @type {{ajaxUrl: *, localCache: {}, openContext: null}}
+        */
+       var ContextHelp = {
+               ajaxUrl: TYPO3.settings.ajaxUrls['ContextHelpAjaxController::dispatch'],
+               localCache: {},
+               helpModuleUrl: '',
+               trigger: 'click',
+               placement: 'auto',
+               selector: '.t3-help-link'
+       };
+
+       /**
+        * Initialize context help trigger
+        */
+       ContextHelp.initialize = function() {
+               ContextHelp.helpModuleUrl = top.TYPO3.settings.ContextHelp.moduleUrl;
+               var title = '&nbsp;';
+               if (typeof(top.TYPO3.LLL) !== 'undefined') {
+                       title = top.TYPO3.LLL.core.csh_tooltip_loading;
+               } else if (opener && typeof(opener.top.TYPO3.LLL) !== 'undefined') {
+                       title = opener.top.TYPO3.LLL.core.csh_tooltip_loading;
+               }
+               var $element = $(this.selector);
+               $element
+                       .attr('data-loaded', 'false')
+                       .attr('data-html', true)
+                       .attr('data-original-title', title)
+                       .attr('data-placement', this.placement)
+                       .attr('data-trigger', this.trigger);
+               TYPO3.Popover.popover($element);
+
+               $(document).on('show.bs.popover', ContextHelp.selector, function(evt) {
+                       if ($(this).attr('data-loaded') === 'false' && $(this).data('table')) {
+                               ContextHelp.loadHelp($(this));
+                       }
+               });
+               $(document).on('shown.bs.popover', ContextHelp.selector, function(evt) {
+                       var $popover = $(evt.target).data('bs.popover').$tip;
+                       if (!$popover.find('.popover-title').is(':visible')) {
+                               $popover.addClass('no-title');
+                       }
+               });
+               $(document).on('click', '.tipIsLinked', function(e) {
+                       $('.popover').each(function() {
+                               if ($(this).has(e.target).length) {
+                                       ContextHelp.showHelpPopup($(this).data('bs.popover').$element);
+                               }
+                       });
+               });
+               $(document).on('click', 'body', function (e) {
+                       $(ContextHelp.selector).each(function () {
+                               var $triggerElement = $(this);
+                               // the 'is' for buttons that trigger popups
+                               // the 'has' for icons within a button that triggers a popup
+                               if (!$triggerElement.is(e.target) && $triggerElement.has(e.target).length === 0 && $('.popover').has(e.target).length === 0) {
+                                       TYPO3.Popover.hide($triggerElement);
+                               }
+                       });
+               });
+       };
+
+       /**
+        * Open the help popup
+        *
+        * @param {object} $trigger
+        */
+       ContextHelp.showHelpPopup = function($trigger) {
+               var identifier = $trigger.data('table') + '.' + $trigger.data('field');
+               try {
+                       var cshWindow = window.open(
+                               top.TYPO3.configuration.PATH_typo3 + ContextHelp.helpModuleUrl + '&tfID=' + identifier,
+                               'ContextHelpWindow',
+                               'height=' + top.TYPO3.configuration.ContextHelpWindows.height + ',width=' + top.TYPO3.configuration.ContextHelpWindows.width + ',status=0,menubar=0,scrollbars=1'
+                       );
+                       cshWindow.focus();
+                       TYPO3.Popover.hide($trigger);
+                       return cshWindow;
+               } catch(e) {
+                       // do nothing
+               }
+       };
+
+       /**
+        * Load help data
+        *
+        * @param {object} $trigger
+        */
+       ContextHelp.loadHelp = function($trigger) {
+               var table = $trigger.data('table');
+               var field = $trigger.data('field');
+               // If a table is defined, use ajax call to get the tooltip's content
+               if (table) {
+                       // Load content
+                       $.getJSON(ContextHelp.ajaxUrl, {
+                               params: {
+                                       action: 'getContextHelp',
+                                       table: table,
+                                       field: field
+                               }
+                       }).done(function(data) {
+                               var title = data.title || '';
+                               var content = data.content || '<p></p>';
+                               TYPO3.Popover.setOptions($trigger, {
+                                       'title': title,
+                                       'content': content
+                               });
+                               $trigger
+                                       .attr('data-loaded', 'true')
+                                       .one('hidden.bs.popover', function() {
+                                               TYPO3.Popover.show($trigger);
+                                       });
+                               TYPO3.Popover.hide($trigger);
+                       });
+               }
+       };
+
+       ContextHelp.initialize();
+       TYPO3.ContextHelp = ContextHelp;
+       return ContextHelp;
+});
diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/Popover.js b/typo3/sysext/backend/Resources/Public/JavaScript/Popover.js
new file mode 100644 (file)
index 0000000..c705e9d
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * API for popover windows powered by Twitter Bootstrap.
+ */
+define('TYPO3/CMS/Backend/Popover', ['jquery'], function($) {
+
+       /**
+        * the main popover object
+        *
+        * @type {{}}
+        */
+       var Popover = {
+       };
+
+       /**
+        * Initialize
+        */
+       Popover.initialize = function(selector) {
+               selector = selector || '[data-toggle="popover"]';
+               $(selector).popover();
+       };
+
+       /**
+        * popover wrapper function
+        *
+        * @param $element
+        */
+       Popover.popover = function($element) {
+               $element.popover();
+       };
+
+       /**
+        * Set popover options on $element
+        *
+        * @param {object} $element
+        * @param {object} options
+        */
+       Popover.setOptions = function($element, options) {
+               options = options || {};
+               var title = options.title || '';
+               var content = options.content || ' ';
+               $element
+                       .attr('data-original-title', title)
+                       .attr('data-content', content)
+                       .attr('data-placement', 'auto')
+                       .popover(options);
+       };
+
+       /**
+        * Show popover with title and content on $element
+        *
+        * @param {object} $element
+        */
+       Popover.show = function($element) {
+               $element.popover('show');
+       };
+
+       /**
+        * Hide popover on $element
+        *
+        * @param $element
+        */
+       Popover.hide = function($element) {
+               $element.popover('hide');
+       };
+
+       /**
+        * Destroy popover on $element
+        *
+        * @param $element
+        */
+       Popover.destroy = function($element) {
+               $element.popover('destroy');
+       };
+
+       /**
+        * Toggle popover on $element
+        *
+        * @param $element
+        */
+       Popover.toggle = function($element) {
+               $element.popover('toggle');
+       };
+
+       Popover.initialize();
+       TYPO3.Popover = Popover;
+       return Popover;
+});
diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/contexthelp.js b/typo3/sysext/backend/Resources/Public/JavaScript/contexthelp.js
deleted file mode 100644 (file)
index 7087c8f..0000000
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-Ext.ns('TYPO3', 'TYPO3.CSH.ExtDirect');
-
-/**
- * Class to show tooltips for links that have the css t3-help-link
- * need the tags data-table and data-field (HTML5)
- *
- * @todo #1: rewrite it on jQuery base, or look for great alternatives
- * @todo #2: make it so flexible that any extension register the JS code in backend.php and the rest should be handled via Data attributes
- * @private please note that this javascript private API, don't depend on this code nor use it as blueprint
- */
-TYPO3.ContextHelp = function() {
-
-       /**
-        * Cache for CSH
-        * @type {Ext.util.MixedCollection}
-        */
-       var cshHelp = new Ext.util.MixedCollection(true),
-       tip;
-
-       /**
-        * Shows the tooltip, triggered from mouseover event handler
-        *
-        */
-       function showToolTipHelp() {
-               var link = tip.triggerElement;
-               if (!link) {
-                       return false;
-               }
-               var table = link.getAttribute('data-table');
-               var field = link.getAttribute('data-field');
-               var key = table + '.' + field;
-               var response = cshHelp.key(key);
-               tip.target = tip.triggerElement;
-               if (response) {
-                       updateTip(response);
-               } else {
-                               // If a table is defined, use ExtDirect call to get the tooltip's content
-                       if (table) {
-                               var description = '';
-                               if (typeof(top.TYPO3.LLL) !== 'undefined') {
-                                       description = top.TYPO3.LLL.core.csh_tooltip_loading;
-                               } else if (opener && typeof(opener.top.TYPO3.LLL) !== 'undefined') {
-                                       description = opener.top.TYPO3.LLL.core.csh_tooltip_loading;
-                               }
-
-                                       // Clear old tooltip contents
-                               updateTip({
-                                       description: description,
-                                       cshLink: '',
-                                       moreInfo: '',
-                                       title: ''
-                               });
-                                       // Load content
-                               TYPO3.CSH.ExtDirect.getTableContextHelp(table, function(response, options) {
-                                       Ext.iterate(response, function(key, value){
-                                               cshHelp.add(value);
-                                               if (key === field) {
-                                                       updateTip(value);
-                                                               // Need to re-position because the height may have increased
-                                                       tip.show();
-                                               }
-                                       });
-                               }, this);
-
-                               // No table was given, use directly title and description
-                       } else {
-                               updateTip({
-                                       description: link.getAttribute('data-description'),
-                                       cshLink: '',
-                                       moreInfo: '',
-                                       title: link.getAttribute('data-title')
-                               });
-                       }
-               }
-       }
-
-       /**
-        * Update tooltip message
-        *
-        * @param {Object} response
-        */
-       function updateTip(response) {
-               tip.body.dom.innerHTML = response.description;
-               tip.cshLink = response.id;
-               tip.moreInfo = response.moreInfo;
-               if (tip.moreInfo) {
-                       tip.addClass('tipIsLinked');
-               }
-               tip.setTitle(response.title);
-               tip.doAutoWidth();
-       }
-
-       return {
-               /**
-                * Constructor
-                */
-               init: function() {
-                       tip = new Ext.ToolTip({
-                               title: 'CSH', // needs a title for init because of the markup
-                               html: '',
-                                       // The tooltip will appear above the label, if viewport allows
-                               anchor: 'bottom',
-                               minWidth: 160,
-                               maxWidth: 240,
-                               target: Ext.getBody(),
-                               delegate: 'span.t3-help-link',
-                               renderTo: Ext.getBody(),
-                               cls: 'typo3-csh-tooltip',
-                               shadow: false,
-                               dismissDelay: 0, // tooltip stays while mouse is over target
-                               autoHide: true,
-                               showDelay: 1000, // show after 1 second
-                               hideDelay: 300, // hide after 0.3 seconds
-                               closable: true,
-                               isMouseOver: false,
-                               listeners: {
-                                       beforeshow: showToolTipHelp,
-                                       render: function(tip) {
-                                               tip.body.on({
-                                                       'click': {
-                                                               fn: function(event) {
-                                                                       event.stopEvent();
-                                                                       if (tip.moreInfo) {
-                                                                               try {
-                                                                                       top.TYPO3.ContextHelpWindow.open(tip.cshLink);
-                                                                               } catch(e) {
-                                                                                       // do nothing
-                                                                               }
-                                                                       }
-                                                                       tip.hide();
-                                                               }
-                                                       }
-                                               });
-                                               tip.el.on({
-                                                       'mouseover': {
-                                                               fn: function() {
-                                                                       if (tip.moreInfo) {
-                                                                               tip.isMouseOver = true;
-                                                                       }
-                                                               }
-                                                       },
-                                                       'mouseout': {
-                                                               fn: function() {
-                                                                       if (tip.moreInfo) {
-                                                                               tip.isMouseOver = false;
-                                                                               tip.hide.defer(tip.hideDelay, tip, []);
-                                                                       }
-                                                               }
-                                                       }
-                                               });
-                                       },
-                                       hide: function(tip) {
-                                               tip.setTitle('');
-                                               tip.body.dom.innerHTML = '';
-                                       },
-                                       beforehide: function(tip) {
-                                               return !tip.isMouseOver;
-                                       },
-                                       scope: this
-                               }
-                       });
-
-                       Ext.getBody().on({
-                               'keydown': {
-                                       fn: function() {
-                                               tip.hide();
-                                       }
-                               },
-                               'click': {
-                                       fn: function() {
-                                               tip.hide();
-                                       }
-                               }
-                       });
-
-                       /**
-                        * Adds a sequence to Ext.TooltTip::showAt so as to increase vertical offset when anchor position is 'bottom'
-                        * This positions the tip box closer to the target element when the anchor is on the bottom side of the box
-                        * When anchor position is 'top' or 'bottom', the anchor is pushed slightly to the left in order to align with the help icon, if any
-                        *
-                        */
-                       Ext.ToolTip.prototype.showAt = Ext.ToolTip.prototype.showAt.createSequence(
-                               function() {
-                                       var ap = this.getAnchorPosition().charAt(0);
-                                       if (this.anchorToTarget && !this.trackMouse) {
-                                               switch (ap) {
-                                                       case 'b':
-                                                               var xy = this.getPosition();
-                                                               this.setPagePosition(xy[0]-10, xy[1]+5);
-                                                               break;
-                                                       case 't':
-                                                               var xy = this.getPosition();
-                                                               this.setPagePosition(xy[0]-10, xy[1]);
-                                                               break;
-                                               }
-                                       }
-                               }
-                       );
-
-               },
-
-               /**
-                * Opens the help window, triggered from click event handler
-                *
-                * @param {Event} event
-                * @param {Node} link
-                */
-               openHelpWindow: function(event, link) {
-                       var id = link.getAttribute('data-table') + '.' + link.getAttribute('data-field');
-                       event.stopEvent();
-                       top.TYPO3.ContextHelpWindow.open(id);
-               }
-       }
-}();
-
-/**
- * Calls the init on Ext.onReady
- */
-Ext.onReady(TYPO3.ContextHelp.init, TYPO3.ContextHelp);
index e609fd1..07ee30a 100644 (file)
@@ -247,87 +247,3 @@ TYPO3.Dialog = function() {
                }
        }
 }();
-
-/**
- * Helper class for dialog windows
- *
- * Example usage:
- *
- * TYPO3.ContextHelpWindow.open(identifier);
- */
-TYPO3.ContextHelpWindow = function() {
-       /**
-        * Path to typo3 directory
-        *
-        * @type {String}
-        * @private
-       */
-       var typo3Path = '';
-
-       /**
-        * Context for open a window
-        * "window" - open a new window
-        * "inline" - open a TYPO3.Window (not currently implementy)
-        *
-        * @type {String}
-        * @private
-       */
-       var openContext;
-
-       /**
-        * Width for the window
-        *
-        * @type {Number}
-        * @private
-       */
-       var width;
-
-       /**
-        * Height of the window
-        *
-        * @type {Number}
-        * @private
-       */
-       var height;
-
-       /**
-        * Token for help module
-        *
-        * @type {String}
-        * @private
-        */
-       var helpModuleUrl;
-
-       return {
-               /**
-                * init class vars
-                *
-                * @return void
-                */
-               init: function(helpModuleUrl) {
-                       this.helpModuleUrl = helpModuleUrl;
-                       this.typo3Path = top.TYPO3.configuration.PATH_typo3;
-                       this.openContext = 'window';
-                       this.width = top.TYPO3.configuration.ContextHelpWindows.width;
-                       this.height = top.TYPO3.configuration.ContextHelpWindows.height;
-               },
-
-               /**
-                * Open window for TYPO3 inline help
-                *
-                * @param {String} help identifier
-                * @return {Object} window
-                */
-               open: function(helpIdentifier) {
-                       if (this.openContext === 'window') {
-                               var cshWindow = window.open(
-                                       this.typo3Path + this.helpModuleUrl + '&tfID=' + helpIdentifier,
-                                       'ContextHelpWindow',
-                                       'height=' + this.height + ',width=' + this.width + ',status=0,menubar=0,scrollbars=1'
-                               );
-                               cshWindow.focus();
-                               return cshWindow;
-                       }
-               }
-       }
-}();
diff --git a/typo3/sysext/context_help/Classes/Controller/ContextHelpAjaxController.php b/typo3/sysext/context_help/Classes/Controller/ContextHelpAjaxController.php
new file mode 100644 (file)
index 0000000..ee8f61c
--- /dev/null
@@ -0,0 +1,55 @@
+<?php
+namespace TYPO3\CMS\ContextHelp\Controller;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\ContextHelp\ExtDirect\ContextHelpDataProvider;
+use TYPO3\CMS\Core\Http\AjaxRequestHandler;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+
+/**
+ * Class ContextHelpAjaxController
+ */
+class ContextHelpAjaxController {
+
+       /**
+        * The main dispatcher function. Collect data and prepare HTML output.
+        *
+        * @param array $params array of parameters, currently unused
+        * @param AjaxRequestHandler $ajaxObj object of type AjaxRequestHandler
+        * @return void
+        */
+       public function dispatch($params = array(), AjaxRequestHandler $ajaxObj = NULL) {
+               $params = GeneralUtility::_GP('params');
+               if ($params['action'] === 'getContextHelp') {
+                       $result = $this->getContextHelp($params['table'], $params['field']);
+                       $ajaxObj->addContent('title', $result['title']);
+                       $ajaxObj->addContent('content', $result['description']);
+                       $ajaxObj->addContent('link', $result['moreInfo']);
+                       $ajaxObj->setContentFormat('json');
+               }
+       }
+
+       /**
+        * Fetch the context help for the given table/field parameters
+        *
+        * @param string $table Table identifier
+        * @param string $field Field identifier
+        * @return array complete Help information
+        */
+       protected function getContextHelp($table, $field) {
+               $dataProvider = GeneralUtility::makeInstance(ContextHelpDataProvider::class);
+               return $dataProvider->getContextHelp($table, $field);
+       }
+}
index 8dc8e9e..ff2f45d 100644 (file)
@@ -13,3 +13,9 @@ defined('TYPO3_MODE') or die();
 // Labels for TYPO3 4.5 and greater.  These labels override the ones set above, while still falling back to the original labels if no translation is available.
 $GLOBALS['TYPO3_CONF_VARS']['SYS']['locallangXMLOverride']['EXT:context_help/locallang_csh_pages.xlf'][] = 'EXT:context_help/4.5/locallang_csh_pages.xlf';
 $GLOBALS['TYPO3_CONF_VARS']['SYS']['locallangXMLOverride']['EXT:context_help/locallang_csh_ttcontent.xlf'][] = 'EXT:context_help/4.5/locallang_csh_ttcontent.xlf';
+
+if (TYPO3_MODE === 'BE') {
+       // Register AJAX Controller
+       \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::registerAjaxHandler('ContextHelpAjaxController::dispatch',
+               \TYPO3\CMS\ContextHelp\Controller\ContextHelpAjaxController::class . '->dispatch');
+}
index ff3afc8..781efeb 100644 (file)
@@ -2,6 +2,13 @@
 // Context sensitive help jij
 //
 
+.t3-help-link {
+       // Hotfix to prevent prototype / scriptaculous hiding the links
+       // this can be removed after prototype / scriptaculous removed completely.
+       // at the moment prototype / scriptaculous hide link after popover was closed.
+       display: inline!important;
+}
+
 .typo3-csh-inline {
        padding: 4px;
 }
diff --git a/typo3/sysext/t3skin/Resources/Private/Styles/TYPO3/_element_popover.less b/typo3/sysext/t3skin/Resources/Private/Styles/TYPO3/_element_popover.less
new file mode 100644 (file)
index 0000000..685e1cc
--- /dev/null
@@ -0,0 +1,30 @@
+//
+// Popover
+//
+
+.popover {
+       padding: 0;
+
+       &-title {
+               font-size: 15px;
+               border-bottom: 0;
+               padding: 12px 14px;
+       }
+
+       &-content p {
+               margin: 0;
+       }
+
+       .close {
+               margin-right: 10px;
+               margin-top: 10px;
+       }
+
+       &.bottom .arrow:after {
+               border-bottom-color: @popover-title-bg;
+       }
+
+       &.no-title .arrow:after {
+               border-bottom-color: @popover-bg;
+       }
+}
index 0995c76..3789700 100644 (file)
@@ -61,7 +61,7 @@
 // Components w/ JavaScript
 @import "@{composer-package-directory-prefix}/twbs/bootstrap/less/modals.less";
 // @import "@{composer-package-directory-prefix}/twbs/bootstrap/less/tooltip.less";
-// @import "@{composer-package-directory-prefix}/twbs/bootstrap/less/popovers.less";
+@import "@{composer-package-directory-prefix}/twbs/bootstrap/less/popovers.less";
 // @import "@{composer-package-directory-prefix}/twbs/bootstrap/less/carousel.less";
 
 // Utility classes
 @import "TYPO3/_element_tab.less";
 @import "TYPO3/_element_table.less";
 @import "TYPO3/_element_panel.less";
+@import "TYPO3/_element_popover.less";
 @import "TYPO3/_element_tceforms.less";
 @import "TYPO3/_element_tree.less";
 @import "TYPO3/_element_pagination.less";
 @import "TYPO3/visual/_element_version.less";
 @import "TYPO3/visual/_module_file_list.less";
 @import "TYPO3/visual/_module_file_upload.less";
-@import "TYPO3/visual/_module_web_page.less";
\ No newline at end of file
+@import "TYPO3/visual/_module_web_page.less";
index c9de946..bb481a0 100644 (file)
@@ -4846,6 +4846,127 @@ button.close {
     width: 900px;
   }
 }
+.popover {
+  position: absolute;
+  top: 0;
+  left: 0;
+  z-index: 1060;
+  display: none;
+  max-width: 276px;
+  padding: 1px;
+  font-family: Verdana, Arial, Helvetica, sans-serif;
+  font-size: 12px;
+  font-weight: normal;
+  line-height: 1.5;
+  text-align: left;
+  background-color: #ffffff;
+  background-clip: padding-box;
+  border: 1px solid #cccccc;
+  border: 1px solid rgba(0, 0, 0, 0.2);
+  border-radius: 2px;
+  -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
+  box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
+  white-space: normal;
+}
+.popover.top {
+  margin-top: -10px;
+}
+.popover.right {
+  margin-left: 10px;
+}
+.popover.bottom {
+  margin-top: 10px;
+}
+.popover.left {
+  margin-left: -10px;
+}
+.popover-title {
+  margin: 0;
+  padding: 8px 14px;
+  font-size: 12px;
+  background-color: #f7f7f7;
+  border-bottom: 1px solid #ebebeb;
+  border-radius: 1px 1px 0 0;
+}
+.popover-content {
+  padding: 9px 14px;
+}
+.popover > .arrow,
+.popover > .arrow:after {
+  position: absolute;
+  display: block;
+  width: 0;
+  height: 0;
+  border-color: transparent;
+  border-style: solid;
+}
+.popover > .arrow {
+  border-width: 11px;
+}
+.popover > .arrow:after {
+  border-width: 10px;
+  content: "";
+}
+.popover.top > .arrow {
+  left: 50%;
+  margin-left: -11px;
+  border-bottom-width: 0;
+  border-top-color: #999999;
+  border-top-color: rgba(0, 0, 0, 0.25);
+  bottom: -11px;
+}
+.popover.top > .arrow:after {
+  content: " ";
+  bottom: 1px;
+  margin-left: -10px;
+  border-bottom-width: 0;
+  border-top-color: #ffffff;
+}
+.popover.right > .arrow {
+  top: 50%;
+  left: -11px;
+  margin-top: -11px;
+  border-left-width: 0;
+  border-right-color: #999999;
+  border-right-color: rgba(0, 0, 0, 0.25);
+}
+.popover.right > .arrow:after {
+  content: " ";
+  left: 1px;
+  bottom: -10px;
+  border-left-width: 0;
+  border-right-color: #ffffff;
+}
+.popover.bottom > .arrow {
+  left: 50%;
+  margin-left: -11px;
+  border-top-width: 0;
+  border-bottom-color: #999999;
+  border-bottom-color: rgba(0, 0, 0, 0.25);
+  top: -11px;
+}
+.popover.bottom > .arrow:after {
+  content: " ";
+  top: 1px;
+  margin-left: -10px;
+  border-top-width: 0;
+  border-bottom-color: #ffffff;
+}
+.popover.left > .arrow {
+  top: 50%;
+  right: -11px;
+  margin-top: -11px;
+  border-right-width: 0;
+  border-left-color: #999999;
+  border-left-color: rgba(0, 0, 0, 0.25);
+}
+.popover.left > .arrow:after {
+  content: " ";
+  right: 1px;
+  border-right-width: 0;
+  border-left-color: #ffffff;
+  bottom: -10px;
+}
 .clearfix:before,
 .clearfix:after,
 .dl-horizontal dd:before,
@@ -7550,6 +7671,9 @@ table#typo3-clipboard tr.bgColor5 td a {
 table#typo3-clipboard tr.bgColor5 td img {
   vertical-align: middle;
 }
+.t3-help-link {
+  display: inline!important;
+}
 .typo3-csh-inline {
   padding: 4px;
 }
@@ -8903,6 +9027,27 @@ fieldset[disabled] .table .btn-default.active {
 .tab-pane > .panel-tab:first-child {
   border-top: none;
 }
+.popover {
+  padding: 0;
+}
+.popover-title {
+  font-size: 15px;
+  border-bottom: 0;
+  padding: 12px 14px;
+}
+.popover-content p {
+  margin: 0;
+}
+.popover .close {
+  margin-right: 10px;
+  margin-top: 10px;
+}
+.popover.bottom .arrow:after {
+  border-bottom-color: #f7f7f7;
+}
+.popover.no-title .arrow:after {
+  border-bottom-color: #ffffff;
+}
 img.t3-TCEforms-reqImg {
   display: block;
   position: absolute;