Notification.ts 7.29 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
/*
 * 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!
 */

14
import $ from 'jquery';
15
16
// @todo Importing bootstrap here, to have jQuery.fn.alert applied
import 'bootstrap';
17
import {AbstractAction} from './ActionButton/AbstractAction';
18
19
20
import {SeverityEnum} from './Enum/Severity';
import Severity = require('./Severity');

21
22
interface Action {
  label: string;
23
  action: AbstractAction;
24
25
}

26
27
28
29
30
31
32
33
34
35
36
37
38
39
/**
 * Module: TYPO3/CMS/Backend/Notification
 * Notification API for the TYPO3 backend
 */
class Notification {
  private static duration: number = 5;
  private static messageContainer: JQuery = null;

  /**
   * Show a notice notification
   *
   * @param {string} title
   * @param {string} message
   * @param {number} duration
40
   * @param {Action[]} actions
41
   */
42
43
  public static notice(title: string, message?: string, duration?: number, actions?: Array<Action>): void {
    Notification.showMessage(title, message, SeverityEnum.notice, duration, actions);
44
45
46
47
48
49
50
51
  }

  /**
   * Show a info notification
   *
   * @param {string} title
   * @param {string} message
   * @param {number} duration
52
   * @param {Action[]} actions
53
   */
54
55
  public static info(title: string, message?: string, duration?: number, actions?: Array<Action>): void {
    Notification.showMessage(title, message, SeverityEnum.info, duration, actions);
56
57
58
59
60
61
62
63
  }

  /**
   * Show a success notification
   *
   * @param {string} title
   * @param {string} message
   * @param {number} duration
64
   * @param {Action[]} actions
65
   */
66
67
  public static success(title: string, message?: string, duration?: number, actions?: Array<Action>): void {
    Notification.showMessage(title, message, SeverityEnum.ok, duration, actions);
68
69
70
71
72
73
74
75
  }

  /**
   * Show a warning notification
   *
   * @param {string} title
   * @param {string} message
   * @param {number} duration
76
   * @param {Action[]} actions
77
   */
78
79
  public static warning(title: string, message?: string, duration?: number, actions?: Array<Action>): void {
    Notification.showMessage(title, message, SeverityEnum.warning, duration, actions);
80
81
82
83
84
85
86
87
  }

  /**
   * Show a error notification
   *
   * @param {string} title
   * @param {string} message
   * @param {number} duration
88
   * @param {Action[]} actions
89
   */
90
91
  public static error(title: string, message?: string, duration: number = 0, actions?: Array<Action>): void {
    Notification.showMessage(title, message, SeverityEnum.error, duration, actions);
92
93
94
95
96
97
98
  }

  /**
   * @param {string} title
   * @param {string} message
   * @param {SeverityEnum} severity
   * @param {number} duration
99
   * @param {Action[]} actions
100
   */
101
102
103
104
105
106
107
  public static showMessage(
    title: string,
    message?: string,
    severity: SeverityEnum = SeverityEnum.info,
    duration: number | string = this.duration,
    actions: Array<Action> = [],
  ): void {
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
    const className = Severity.getCssClass(severity);
    let icon = '';
    switch (severity) {
      case SeverityEnum.notice:
        icon = 'lightbulb-o';
        break;
      case SeverityEnum.ok:
        icon = 'check';
        break;
      case SeverityEnum.warning:
        icon = 'exclamation';
        break;
      case SeverityEnum.error:
        icon = 'times';
        break;
      case SeverityEnum.info:
      default:
        icon = 'info';
    }

    duration = (typeof duration === 'undefined')
      ? this.duration
      : (
        typeof duration === 'string'
          ? parseFloat(duration)
          : duration
      );

136
    if (this.messageContainer === null || document.getElementById('alert-container') === null) {
137
      this.messageContainer = $('<div>', {'id': 'alert-container'}).appendTo('body');
138
    }
139
140
141

    const notificationId = 'notification-' + Math.random().toString(36).substr(2, 5);

142
    const $box = $(
143
      '<div id="' + notificationId + '" class="alert alert-' + className + ' alert-dismissible fade" role="alert">' +
144
        '<button type="button" class="close" data-bs-dismiss="alert">' +
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
          '<span aria-hidden="true"><i class="fa fa-times-circle"></i></span>' +
          '<span class="sr-only">Close</span>' +
        '</button>' +
        '<div class="media">' +
          '<div class="media-left">' +
            '<span class="fa-stack fa-lg">' +
              '<i class="fa fa-circle fa-stack-2x"></i>' +
              '<i class="fa fa-' + icon + ' fa-stack-1x"></i>' +
            '</span>' +
          '</div>' +
          '<div class="media-body">' +
            '<h4 class="alert-title"></h4>' +
            '<p class="alert-message text-pre-wrap"></p>' +
          '</div>' +
        '</div>' +
160
161
        '<div class="alert-actions">' +
        '</div>' +
162
      '</div>',
163
164
165
    );
    $box.find('.alert-title').text(title);
    $box.find('.alert-message').text(message);
166
167
168
169
170
171
172
173
174

    const $actionButtonContainer = $box.find('.alert-actions');
    if (actions.length > 0) {
      for (let action of actions) {
        const $actionButton = $('<a />', {
          href: '#',
          title: action.label,
        });
        $actionButton.text(action.label);
175
        $actionButton.on('click', (e: JQueryEventObject): void => {
176
177
178
179
180
181
          // Remove potentially set timeout
          $box.clearQueue();

          const target = <HTMLAnchorElement>e.currentTarget;
          target.classList.add('executing');

182
183
          $actionButtonContainer.find('a').not(target).addClass('disabled');
          action.action.execute(target).then((): void => {
184
185
186
187
188
189
190
191
192
193
            $box.alert('close');
          });
        });

        $actionButtonContainer.append($actionButton);
      }
    } else {
      $actionButtonContainer.remove();
    }

194
195
196
197
198
199
200
201
202
    $box.on('close.bs.alert', (e: Event) => {
      e.preventDefault();
      const $me = $(e.currentTarget);
      $me
        .clearQueue()
        .queue((next: any): void => {
          $me.removeClass('in');
          next();
        })
203
204
205
206
        .slideUp({
          complete: (): void => {
            $me.remove();
          },
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
        });
    });
    $box.appendTo(this.messageContainer);
    $box.delay(200)
      .queue((next: any): void => {
        $box.addClass('in');
        next();
      });

    if (duration > 0) {
      // if duration > 0 dismiss alert
      $box.delay(duration * 1000)
        .queue((next: any): void => {
          $box.alert('close');
          next();
        });
    }
  }
}

227
let notificationObject: any;
228
229
230
231
232
233
234
235
236
237
238

try {
  // fetch from parent
  if (parent && parent.window.TYPO3 && parent.window.TYPO3.Notification) {
    notificationObject = parent.window.TYPO3.Notification;
  }

  // fetch object from outer frame
  if (top && top.TYPO3.Notification) {
    notificationObject = top.TYPO3.Notification;
  }
239
} catch {
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
  // This only happens if the opener, parent or top is some other url (eg a local file)
  // which loaded the current window. Then the browser's cross domain policy jumps in
  // and raises an exception.
  // For this case we are safe and we can create our global object below.
}

if (!notificationObject) {
  notificationObject = Notification;

  // attach to global frame
  if (typeof TYPO3 !== 'undefined') {
    TYPO3.Notification = notificationObject;
  }
}
export = notificationObject;