[BUGFIX] Prevent loading jsfunc.inline.js twice
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Resources / Private / TypeScript / ContextHelp.ts
1 /*
2  * This file is part of the TYPO3 CMS project.
3  *
4  * It is free software; you can redistribute it and/or modify it under
5  * the terms of the GNU General Public License, either version 2
6  * of the License, or any later version.
7  *
8  * For the full copyright and license information, please read the
9  * LICENSE.txt file that was distributed with this source code.
10  *
11  * The TYPO3 project - inspiring people to share!
12  */
13
14 import 'bootstrap';
15 import * as $ from 'jquery';
16 import Popover = require('./Popover');
17
18 interface HelpData {
19   title: string;
20   content: string;
21 }
22
23 /**
24  * Module: TYPO3/CMS/Backend/ContextHelp
25  * API for context help.
26  * @exports TYPO3/CMS/Backend/ContextHelp
27  */
28 class ContextHelp {
29   private ajaxUrl: string = TYPO3.settings.ajaxUrls.context_help;
30   private helpModuleUrl: string;
31   private trigger: string = 'click';
32   private placement: string = 'auto';
33   private selector: string = '.t3-help-link';
34
35   /**
36    * @return {Window}
37    */
38   private static resolveBackend(): Window {
39     if (typeof window.opener !== 'undefined' && window.opener !== null) {
40       return window.opener.top;
41     } else {
42       return top;
43     }
44   }
45
46   constructor() {
47     this.initialize();
48   }
49
50   public initialize(): void {
51     const backendWindow = ContextHelp.resolveBackend();
52     if (typeof backendWindow.TYPO3.settings.ContextHelp !== 'undefined') {
53       this.helpModuleUrl = backendWindow.TYPO3.settings.ContextHelp.moduleUrl;
54     }
55
56     if (typeof TYPO3.ShortcutMenu === 'undefined' && typeof backendWindow.TYPO3.ShortcutMenu === 'undefined') {
57       // @FIXME: if we are in the popup... remove the bookmark / shortcut button
58       // @TODO: make it possible to use the bookmark button also in popup mode
59       $('.icon-actions-system-shortcut-new').closest('.btn').hide();
60     }
61
62     let title = ' ';
63     if (typeof backendWindow.TYPO3.lang !== 'undefined') {
64       title = backendWindow.TYPO3.lang.csh_tooltip_loading;
65     }
66     const $element = $(this.selector);
67     $element
68       .attr('data-loaded', 'false')
69       .attr('data-html', 'true')
70       .attr('data-original-title', title)
71       .attr('data-placement', this.placement)
72       .attr('data-trigger', this.trigger);
73     Popover.popover($element);
74
75     $(document).on('show.bs.popover', this.selector, (e: Event): void => {
76       const $me = $(e.currentTarget);
77       const description = $me.data('description');
78       if (typeof description !== 'undefined' && description !== '') {
79         Popover.setOptions($me, {
80           title: $me.data('title'),
81           content: description
82         });
83       } else if ($me.attr('data-loaded') === 'false' && $me.data('table')) {
84         this.loadHelp($me);
85       }
86
87       // if help icon is in DocHeader, force open to bottom
88       if ($me.closest('.t3js-module-docheader').length) {
89         Popover.setOption($me, 'placement', 'bottom');
90       }
91     }).on('shown.bs.popover', this.selector, (e: Event): void => {
92       const $popover = $(e.target).data('bs.popover').$tip;
93       if (!$popover.find('.popover-title').is(':visible')) {
94         $popover.addClass('no-title');
95       }
96     }).on('click', '.tipIsLinked', (e: any): void => {
97       $('.popover').each((index: number, popover: Element): void => {
98         const $popover = $(popover);
99         if ($popover.has(e.target).length) {
100           console.log($popover.data('bs.popover'));
101           this.showHelpPopup($popover.data('bs.popover').$element);
102         }
103       });
104     }).on('click', 'body', (e: any): void => {
105       $(this.selector).each((index: number, triggerElement: Element): void => {
106         const $triggerElement = $(triggerElement);
107         // the 'is' for buttons that trigger popups
108         // the 'has' for icons within a button that triggers a popup
109         if (!$triggerElement.is(e.target)
110           && $triggerElement.has(e.target).length === 0
111           && $('.popover').has(e.target).length === 0
112         ) {
113           Popover.hide($triggerElement);
114         }
115       });
116     });
117   }
118
119   /**
120    * Open the help popup
121    *
122    * @param {JQuery} $trigger
123    */
124   private showHelpPopup($trigger: JQuery): any {
125     try {
126       const cshWindow = window.open(
127         this.helpModuleUrl +
128         '&table=' + $trigger.data('table') +
129         '&field=' + $trigger.data('field'),
130         'ContextHelpWindow',
131         'height=400,width=600,status=0,menubar=0,scrollbars=1'
132       );
133       cshWindow.focus();
134       Popover.hide($trigger);
135       return cshWindow;
136     } catch (e) {
137       // do nothing
138     }
139   }
140
141   /**
142    * Load help data
143    *
144    * @param {JQuery} $trigger
145    */
146   private loadHelp($trigger: JQuery): void {
147     const table = $trigger.data('table');
148     const field = $trigger.data('field');
149     // If a table is defined, use ajax call to get the tooltip's content
150     if (table) {
151       // Load content
152       $.getJSON(this.ajaxUrl, {
153         params: {
154           action: 'getContextHelp',
155           table: table,
156           field: field
157         }
158       }).done((data: HelpData): void => {
159         const title = data.title || '';
160         const content = data.content || '<p></p>';
161         Popover.setOptions($trigger, {
162           title: title,
163           content: content
164         });
165         $trigger
166           .attr('data-loaded', 'true')
167           .one('hidden.bs.popover', (): void => {
168             Popover.show($trigger);
169           });
170         Popover.hide($trigger);
171       });
172     }
173   }
174 }
175
176 export = new ContextHelp();