Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
/**
2
 * Amanote filter script.
3
 *
4
 * @copyright   2020 Amaplex Software
5
 * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
6
 */
7
 
8
define(['jquery', 'core/modal_factory'], ($, modalFactory) =>
9
{
10
  class Main
11
  {
12
    /**
13
     * Init the plugin's scripts. This method is called by AMD.
14
     *
15
     * @param rawUserParams
16
     */
17
    public init(rawUserParams: string): void
18
    {
19
      // Parse the params.
20
      const pluginParams = window['amanote_params'];
21
      const moodleUserParams = Main.parseParams(rawUserParams);
22
 
23
      if (!pluginParams || !moodleUserParams)
24
      {
25
        return;
26
      }
27
 
28
      // Init the Moodle service (Singleton).
29
      MoodleService.init(pluginParams, moodleUserParams, modalFactory);
30
 
31
      // Add Amanote button to each course modules.
32
      const courseModuleFilter = new CourseModuleFilter();
33
      courseModuleFilter.addButtonToCourseModules();
34
    }
35
 
36
    /**
37
     * Parse the given plugin params.
38
     *
39
     * @param rawParams - The serialized params.
40
     *
41
     * @returns The parsed params as an object.
42
     */
43
    private static parseParams(rawParams: string): IMoodleUserParams
44
    {
45
      try
46
      {
47
        return JSON.parse(rawParams);
48
      }
49
      catch (error)
50
      {
51
        console.error(error);
52
 
53
        return null;
54
      }
55
    }
56
  }
57
 
58
  class MoodleService
59
  {
60
    private static instance: MoodleService;
61
 
62
    constructor(private readonly pluginParams: IPluginParams,
63
                private readonly moodleUserParams: IMoodleUserParams,
64
                private readonly modalFactory: any)
65
    {
66
      if (MoodleService.instance)
67
      {
68
        throw new Error("Error - Use MoodleService.getInstance()");
69
      }
70
 
71
      try
72
      {
73
        const userOpeningMode = localStorage.getItem(StorageKeysEnum.OpeningMode);
74
        if (userOpeningMode !== null)
75
        {
76
          this.pluginParams.plugin.openingMode = userOpeningMode as OpeningModeEnum;
77
        }
78
      }
79
      catch (error)
80
      {
81
        console.log(error);
82
      }
83
    }
84
 
85
    /**
86
     * Get the plugin params.
87
     *
88
     * @returns The moodle plugin params.
89
     */
90
    public getPluginParams(): IPluginParams
91
    {
92
      return this.pluginParams;
93
    }
94
 
95
    /**
96
     * Get the user params.
97
     *
98
     * @returns The user params.
99
     */
100
    public getUserParams(): IMoodleUserParams
101
    {
102
      return this.moodleUserParams;
103
    }
104
 
105
    /**
106
     * Get the modal factory.
107
     *
108
     * @returns The modal factory.
109
     */
110
    public getModalFactory(): any
111
    {
112
      return this.modalFactory;
113
    }
114
 
115
    /**
116
     * Get an annotatable by course module id (cmid).
117
     *
118
     * @param cmid - The course module id (cmid).
119
     *
120
     * @returns The annotatable.
121
     */
122
    public getAnnotatableByCmId(cmid: number): IAnnotatable
123
    {
124
      return (this.pluginParams.annotatables || [])
125
        .filter(cm => cm.cmid == cmid).pop();
126
    }
127
 
128
    /**
129
     * Get an annotatable by id.
130
     *
131
     * @param id - The annotatable id.
132
     *
133
     * @returns The annotatable.
134
     */
135
     public getAnnotatableById(id: string): IAnnotatable
136
     {
137
       return (this.pluginParams.annotatables || [])
138
         .filter(a => a.id == id).pop();
139
     }
140
 
141
    /**
142
     * Get a annotatable by the path of the content.
143
     *
144
     * @param path - The path to find.
145
     *
146
     * @returns The annotatable.
147
     */
148
    public getAnnotatableByContentPath(path: string): IAnnotatable
149
    {
150
      const annotatable = this.pluginParams.annotatables || [];
151
 
152
      for (let i = 0; i < annotatable.length; i++)
153
      {
154
        if (annotatable[i].url === path)
155
        {
156
          return annotatable[i];
157
        }
158
        else if (annotatable[i].internal)
159
        {
160
          let path1 = annotatable[i].url;
161
          let path2 = path.split('pluginfile.php')[1]
162
            .split('?')[0]
163
            .replace('intro/0', 'intro')
164
            .replace('content/0/', 'content/1/');
165
 
166
          path1 = decodeURIComponent(path1 || '');
167
          path2 = decodeURIComponent(path2 || '');
168
 
169
          if (path1 && path2 && path1 === path2)
170
          {
171
            return annotatable[i];
172
          }
173
        }
174
      }
175
 
176
      return null;
177
    }
178
 
179
    /**
180
     * Get the filename of the note linked to the annotatable if any.
181
     *
182
     * @param annotatable The annotatable.
183
     *
184
     * @returns The file name if any or null otherwise.
185
     */
186
    public getSavedNoteFilenameForAnnotatable(annotatable: IAnnotatable): string
187
    {
188
      const savedNotes = this.pluginParams.savedNotes || {};
189
 
190
      if (savedNotes[annotatable.id + '.ama'])
191
      {
192
        return savedNotes[annotatable.id + '.ama'].filename;
193
      }
194
      else if (annotatable.legacyid && savedNotes[annotatable.legacyid + '.ama'])
195
      {
196
        return savedNotes[annotatable.legacyid + '.ama'].filename;
197
      }
198
 
199
      return null;
200
    }
201
 
202
    /**
203
     * Get the Amanote logo for a given annotatable.
204
     *
205
     * @param annotatable The annotatable.
206
     *
207
     * @returns The logo depending if the annotatable is annotated or note.
208
     */
209
    public getLogoForAnnotatable(annotatable: IAnnotatable): string
210
    {
211
      if (this.getSavedNoteFilenameForAnnotatable(annotatable))
212
      {
213
        return this.pluginParams.plugin.annotatedLogo;
214
      }
215
 
216
      return this.pluginParams.plugin.logo;
217
    }
218
 
219
    /**
220
     * Generate an URL to open a file in Amanote.
221
     *
222
     * @param annotatable - The annotatable to open.
223
     * @param route - The route.
224
     *
225
     * @returns The generated url.
226
     */
227
    public generateAmanoteURL(annotatable: IAnnotatable, route = 'note-taking'): string
228
    {
229
      if (!annotatable)
230
      {
231
        return '';
232
      }
233
 
234
      if (route === 'note-taking' && this.pluginParams.plugin.target != OpeningTargetEnum.Amanote)
235
      {
236
        return `${this.pluginParams.siteURL}/filter/amanote/annotate.php?annotatableId=${annotatable.id}`;
237
      }
238
 
239
      // Parse the PDF path.
240
      let filePath = annotatable.url;
241
 
242
      if (annotatable.internal && filePath.indexOf('pluginfile.php') >= 0)
243
      {
244
        filePath = filePath.split('pluginfile.php')[1].replace('content/0/', 'content/1/');
245
      }
246
      else
247
      {
248
        filePath = encodeURIComponent(filePath);
249
      }
250
 
251
      // Generate the AMA path.
252
      const noteFilename = this.getSavedNoteFilenameForAnnotatable(annotatable) || `${annotatable.id}.ama`;
253
      const amaPath = this.pluginParams.privateFilePath + noteFilename;
254
 
255
      let protocol = 'https';
256
      if (this.pluginParams.siteURL.indexOf('https') < 0)
257
      {
258
        protocol = 'http';
259
      }
260
 
261
      if (route === 'note-taking' && annotatable.kind === ContentKindEnum.Video)
262
      {
263
        route = `/note-taking/moodle/video/${annotatable.id}`;
264
      }
265
      else
266
      {
267
        route = `/moodle/${route}`;
268
      }
269
 
270
      return protocol + '://app.amanote.com/' + this.pluginParams.language + route + '?' +
271
        'siteURL=' + this.pluginParams.siteURL + '&' +
272
        'accessToken=' + this.moodleUserParams.token.value + '&' +
273
        'tokenExpDate=' + this.moodleUserParams.token.expiration + '&' +
274
        'userId=' + this.moodleUserParams.id + '&' +
275
        'filePath=' + filePath + '&' +
276
        'mimeType='  +  annotatable.mimetype + '&' +
277
        'amaPath=' + amaPath + '&' +
278
        'resourceId=' + annotatable.id + '&' +
279
        'legacyResourceId=' + (annotatable.legacyid || annotatable.id) + '&' +
280
        'saveInProvider=' + (this.pluginParams.plugin.saveInProvider ? '1' : '0') + '&' +
281
        'providerVersion=' + this.pluginParams.moodle.version + '&' +
282
        'pluginVersion=' + this.pluginParams.plugin.version + '&' +
283
        'key=' + this.pluginParams.plugin.key + '&' +
284
        'worksheet=' + (this.pluginParams.plugin.worksheet ? '1' : '0') + '&' +
285
        'anonymous=' + (this.pluginParams.plugin.anonymous ? '1' : '0');
286
    }
287
 
288
    /**
289
     * Init the Singleton.
290
     *
291
     * @param pluginParams - The plugin params.
292
     * @param moodleUserParams - The moodle user params.
293
     * @param modalFactory - THe modal factory.
294
     */
295
    public static init(pluginParams: IPluginParams, moodleUserParams: IMoodleUserParams, modalFactory: any): void
296
    {
297
      MoodleService.instance = new MoodleService(pluginParams, moodleUserParams, modalFactory);
298
    }
299
 
300
    /**
301
     * Get the Singleton instance.
302
     *
303
     * @returns The Singleton instance.
304
     */
305
    public static getInstance(): MoodleService
306
    {
307
      return MoodleService.instance;
308
    }
309
  }
310
 
311
  class CourseModuleFilter
312
  {
313
    private static readonly annotatableIDAttribute = 'annotatable-id';
314
    private static readonly amanoteButtonClass = 'amanote-button';
315
 
316
    private observer: MutationObserver;
317
    private menuModal = new MenuModal();
318
    private moodleService = MoodleService.getInstance();
319
    private params = this.moodleService.getPluginParams();
320
    private userParams = this.moodleService.getUserParams();
321
 
322
    constructor() { }
323
 
324
    /**
325
     * Add the Amanote buttons on each supported module and listen changes.
326
     */
327
    public addButtonToCourseModules(): void
328
    {
329
      this.addAmanoteButtons();
330
 
331
      if (this.observer)
332
      {
333
        this.observer.disconnect();
334
      }
335
 
336
      this.observer = new MutationObserver((mutationsList) =>
337
      {
338
        if (this.doesMutationsContainAnActivity(mutationsList))
339
        {
340
          this.addAmanoteButtons();
341
        }
342
      });
343
 
344
      const targetNode = document.getElementById('page-content');
345
      this.observer.observe(targetNode, { childList: true, subtree: true });
346
    }
347
 
348
    /**
349
     * Check if a given DOM mutations list contains a new activity instance node.
350
     *
351
     * @param mutationsList - The list of mutations.
352
     *
353
     * @returns True if a mutation contains a new activity instance, False otherwise.
354
     */
355
    private doesMutationsContainAnActivity(mutationsList: any[]): boolean
356
    {
357
      for (let i = 0; i < mutationsList.length; i++)
358
      {
359
        const mutation = mutationsList[i];
360
 
361
        if (mutation.type !== 'childList')
362
        {
363
          continue;
364
        }
365
 
366
        for (let j = 0; j < mutation.addedNodes.length; j++)
367
        {
368
          const addedNode = mutation.addedNodes[j];
369
 
370
          if ($(addedNode).find('.activityinstance, .activity-instance').length > 0)
371
          {
372
            return true;
373
          }
374
        }
375
      }
376
 
377
      return false;
378
    }
379
 
380
    /**
381
     * Add the Amanote buttons on each supported module.
382
     */
383
    private addAmanoteButtons(): void
384
    {
385
      this.forEachNewInstances(['modtype_resource', 'modtype_url'], (element) =>
386
      {
387
        const annotatable = this.getAnnotatableFromElement(element);
388
 
389
        if (!annotatable)
390
        {
391
          return;
392
        }
393
 
394
        let activityLink = $(element).find('.activitytitle').find('a').first();
395
        if (activityLink.length === 0)
396
        {
397
          activityLink = $(element).find('a').first();
398
        }
399
 
400
        if (this.openWithButton())
401
        {
402
          const button = this.generateAmanoteButton(annotatable);
403
 
404
          activityLink.css('display', 'inline-block');
405
          activityLink.removeClass('stretched-link');
406
 
407
          if ($(element).find('.activity-instance').length > 0)
408
          {
409
            $(element).find('.activity-instance').find('.activityname').children().first().after(button);
410
          }
411
          else if ($(element).find('.activity-basis').length > 0)
412
          {
413
            $(element).find('.activity-basis').first().children().children().first().after(button);
414
          }
415
          else
416
          {
417
            $(element).find('.activityinstance').first().children().first().after(button);
418
          }
419
        }
420
        else
421
        {
422
          this.replaceLink(activityLink, annotatable);
423
 
424
          // Replace link on activity icon if any.
425
          const iconLink = $(element).find('a.activity-icon').first();
426
          if (iconLink.length > 0)
427
          {
428
            this.replaceLink(iconLink, annotatable);
429
          }
430
        }
431
 
432
        this.addOnDeleteWarning($(element));
433
      });
434
 
435
      this.forEachNewInstances(['fp-filename-icon'], (element) =>
436
      {
437
        // Get file id from file url.
438
        const fileLink = $(element).find('a').first();
439
 
440
        if (fileLink.length !== 1)
441
        {
442
          return;
443
        }
444
 
445
        const filePath = fileLink.attr('href');
446
        const annotatable = this.moodleService.getAnnotatableByContentPath(filePath);
447
 
448
        if (!annotatable)
449
        {
450
          return;
451
        }
452
 
453
        if (this.openWithButton())
454
        {
455
          const button = this.generateAmanoteButton(annotatable);
456
 
457
          fileLink.css('display', 'inline-block');
458
          fileLink.after(button);
459
        }
460
        else
461
        {
462
          this.replaceLink(fileLink, annotatable);
463
        }
464
      });
465
 
466
      this.forEachNewInstances(['modtype_folder'], (element) =>
467
      {
468
        this.addOnDeleteWarning($(element));
469
      });
470
 
471
      this.forEachNewInstances(['modtype_label'], (element) =>
472
      {
473
        const annotatable = this.getAnnotatableFromElement(element);
474
 
475
        if (!annotatable)
476
        {
477
          return;
478
        }
479
 
480
        if (this.openWithButton())
481
        {
482
          const button = this.generateAmanoteButton(annotatable);
483
 
484
          $(element).find('.mediaplugin').first().children().children().first().after(button);
485
        }
486
        else
487
        {
488
          this.replaceLink($(element).find('a').first(), annotatable);
489
        }
490
 
491
        this.addOnDeleteWarning($(element));
492
      });
493
 
494
      // Listen click on amanote button.
495
      setTimeout(() =>
496
      {
497
        $(`.${CourseModuleFilter.amanoteButtonClass}`).on('click', (event) =>
498
        {
499
          event.preventDefault();
500
 
501
          const annotatableId = $(event.currentTarget).attr(CourseModuleFilter.annotatableIDAttribute);
502
          const annotatable = this.moodleService.getAnnotatableById(annotatableId);
503
 
504
          if (this.params.plugin.openingMode === OpeningModeEnum.FileClick)
505
          {
506
            annotatable.openInMoodleURL = event.currentTarget.href;
507
          }
508
 
509
          if ((this.params.plugin.openingMode !== OpeningModeEnum.FileClick || this.params.plugin.preventDownload) && !this.userParams.isTeacher)
510
          {
511
            window.open(this.moodleService.generateAmanoteURL(annotatable, 'note-taking'), 'blank');
512
            return;
513
          }
514
 
515
          this.menuModal.open(annotatable);
516
        });
517
      }, 500);
518
    }
519
 
520
    /**
521
     * Get the annotatable from an element. The element must contains and id property with
522
     * a value of kind "module-xx" where xx is the cmid.
523
     *
524
     * @param element - The element.
525
     *
526
     * @returns The annotatable corresponding to the cmid of the element.
527
     */
528
    private getAnnotatableFromElement(element: HTMLElement): IAnnotatable
529
    {
530
      const elementId = $(element).attr('id');
531
 
532
      if (!elementId || elementId.indexOf('module-') < 0)
533
      {
534
        return;
535
      }
536
 
537
      const courseModuleId = parseInt(elementId.replace('module-', ''), 10);
538
      return this.moodleService.getAnnotatableByCmId(courseModuleId);
539
    }
540
 
541
    /**
542
     * Determine if it should open the menu with a button or by replacing the current link.
543
     *
544
     * @returns True the menu should open with a button.
545
     */
546
    private openWithButton(): boolean
547
    {
548
      return this.params.plugin.openingMode !== OpeningModeEnum.FileClick;
549
    }
550
 
551
    /**
552
     * Apply action to all new course module instance.
553
     *
554
     * @param classNames - The module class names.
555
     * @param action - The action.
556
     */
557
    private forEachNewInstances(classNames: string[], action: (e: HTMLElement) => void): void
558
    {
559
      $('.' + classNames.join(', .')).each((index, element) =>
560
      {
561
        if ($(element).find('.' + CourseModuleFilter.amanoteButtonClass).length > 0)
562
        {
563
          return;
564
        }
565
 
566
        action(element);
567
      });
568
    }
569
 
570
    /**
571
     * Generate a new button for a given annotatable.
572
     *
573
     * @param annotatable - The annotatable for which the button should be created.
574
     *
575
     * @returns The JQuery generate button.
576
     */
577
    private generateAmanoteButton(annotatable: IAnnotatable): JQuery
578
    {
579
      const moodleService = MoodleService.getInstance();
580
      const logo = moodleService.getLogoForAnnotatable(annotatable);
581
 
582
      const widthByMode = {
583
        [OpeningModeEnum.FileClick]: 90,
584
        [OpeningModeEnum.LogoNextToFile]: 90,
585
        [OpeningModeEnum.IconNextToFile]: 40,
586
        [OpeningModeEnum.IconNextToFileWithText]: 130,
587
      };
588
 
589
      const width = widthByMode[this.params.plugin.openingMode] || 90;
590
 
591
      const a = $(`<a class="mx-4 my-2 amanote-button"><img src="${logo}" width="${width}px" alt="Open in Amanote"></a>`);
592
      a.css('display', 'inline-block');
593
      a.css('cursor', 'pointer');
594
      a.css('margin', 'auto');
595
 
596
      if (this.params.plugin.openingMode === OpeningModeEnum.LogoNextToFile)
597
      {
598
        a.css('min-width', '110px');
599
      }
600
 
601
      a.attr(CourseModuleFilter.annotatableIDAttribute, annotatable.id);
602
 
603
      return a;
604
    }
605
 
606
    /**
607
     * Replace a link element with an Amanote button.
608
     *
609
     * @param link - The link to replace.
610
     * @param annotatable - The annotatable for which the button should be created.
611
     */
612
    private replaceLink(link: JQuery, annotatable: IAnnotatable): void
613
    {
614
      link.attr(CourseModuleFilter.annotatableIDAttribute, annotatable.id);
615
      link.addClass('amanote-button');
616
      link.css('cursor', 'pointer');
617
    }
618
 
619
    /**
620
     * Add a warning when the user want to delete a resource.
621
     *
622
     * @param activity - The activity to which the warning should be added.
623
     */
624
    private addOnDeleteWarning(activity: JQuery): void
625
    {
626
      activity.find('.editing_delete').first().on('click', () =>
627
      {
628
        setTimeout(() => { this.menuModal.showDeleteWarning(); }, 500);
629
      });
630
    }
631
 
632
  }
633
 
634
  class MenuModal
635
  {
636
    private moodleService = MoodleService.getInstance();
637
    private modalFactory = this.moodleService.getModalFactory();
638
    private pluginParams = this.moodleService.getPluginParams();
639
    private moodleUserParams = this.moodleService.getUserParams();
640
 
641
    constructor() { }
642
 
643
    /**
644
     * Open the menu modal for a given annotatable.
645
     */
646
    public open(annotatable: IAnnotatable): Promise<void>
647
    {
648
      if (!annotatable)
649
      {
650
        return;
651
      }
652
 
653
      const modalParams = {
654
        title: 'Amanote',
655
        body: this.generateModalBodyHTML(annotatable),
656
        footer: '',
657
      };
658
 
659
      return this.modalFactory.create(modalParams)
660
        .then((modal) =>
661
        {
662
          modal.show();
663
        });
664
    }
665
 
666
    /**
667
     * Show a warning popup before deleting a resource.
668
     */
669
    public showDeleteWarning(): void
670
    {
671
      const hideDeleteWarningExp = localStorage.getItem(StorageKeysEnum.HideDeleteWarningExp);
672
 
673
      if (hideDeleteWarningExp && !isNaN(Date.parse(hideDeleteWarningExp)))
674
      {
675
        const hideDate = new Date(hideDeleteWarningExp);
676
        const now = new Date();
677
 
678
        if ((now.getTime() - hideDate.getTime()) < (30 * 24 * 60 * 60 * 1000))
679
        {
680
          return;
681
        }
682
      }
683
 
684
      const guideLink = 'https://help.amanote.com/en/support/solutions/articles/36000448676';
685
 
686
      var message = `<div class="alert alert-warning">
687
        <strong>Warning</strong>
688
        <p>${this.pluginParams.strings.deletefilewarning}</p>
689
        <p><a href="${guideLink}" target="_blank">${this.pluginParams.strings.seeguide}</a></p>
690
      </div>
691
      <div style="text-align: center; margin-top: 1rem;">
692
        <a class="text-muted" style="cursor: pointer;" data-action="hide"
693
        onclick="localStorage.setItem('${StorageKeysEnum.HideDeleteWarningExp}', new Date().toISOString());">
694
          ${this.pluginParams.strings.stopmodal}
695
        </a>
696
      </div>`;
697
 
698
      const modalParams = {
699
        title: 'Amanote Warning',
700
        body: message,
701
        footer: '',
702
      };
703
 
704
      this.modalFactory.create(modalParams)
705
        .then((modal) =>
706
        {
707
          modal.show();
708
        });
709
    }
710
 
711
    /**
712
     * Generate the modal body for a given annotatable.
713
     *
714
     * @param annotatable - The annotatable.
715
     *
716
     * @returns The modal body in HTML.
717
     */
718
    private generateModalBodyHTML(annotatable: IAnnotatable): string
719
    {
720
      const openInAmanoteURL = this.moodleService.generateAmanoteURL(annotatable, 'note-taking');
721
 
722
      let body = `<p class="mb-0 text-muted">${this.pluginParams.strings.modalDescription}</p>`;
723
 
724
      body += MenuModal.generateButtonHTML(openInAmanoteURL, this.pluginParams.strings.annotateResource, 'fa fa-edit', 'font-weight: 600; background: #2cdf90; color: #03341f; border: none');
725
 
726
      if (this.pluginParams.plugin.openingMode === OpeningModeEnum.FileClick && !this.pluginParams.plugin.preventDownload)
727
      {
728
        body += MenuModal.generateButtonHTML(annotatable.openInMoodleURL, this.pluginParams.strings.viewResource, 'fa fa-eye', 'font-weight: 600;');
729
      }
730
 
731
      if (this.moodleUserParams.isTeacher && annotatable.kind === ContentKindEnum.Document)
732
      {
733
        body += '<hr style="margin-bottom: 0px">';
734
 
735
        // Add Learning Analytics.
736
        const openAnalyticsURL = this.moodleService.generateAmanoteURL(annotatable, `document-analytics/${annotatable.id}/view`);
737
        body += MenuModal.generateButtonHTML(openAnalyticsURL, this.pluginParams.strings.openAnalytics);
738
 
739
        // Add Podcast Creator.
740
        if (this.pluginParams.plugin.key && !this.pluginParams.plugin.anonymous)
741
        {
742
          const openPodcastCreatorURL = this.moodleService.generateAmanoteURL(annotatable, 'podcast/creator');
743
          body += MenuModal.generateButtonHTML(openPodcastCreatorURL, this.pluginParams.strings.openPodcastCreator);
744
        }
745
 
746
        // Add Open student's works.
747
        if (this.pluginParams.plugin.worksheet && !this.pluginParams.plugin.anonymous)
748
        {
749
          const openStudentWorkURL = this.moodleService.generateAmanoteURL(annotatable, `document-analytics/${annotatable.id}/notes`);
750
          body += MenuModal.generateButtonHTML(openStudentWorkURL, this.pluginParams.strings.openStudentsWorks);
751
        }
752
      }
753
 
754
      if (this.pluginParams.plugin.openingMode === OpeningModeEnum.FileClick &&
755
         !this.moodleUserParams.isTeacher &&
756
         !this.pluginParams.plugin.preventDownload)
757
      {
758
        body += `
759
          <div style="text-align: center; margin-top: 1rem;">
760
            <a class="text-muted" style="cursor: pointer;" data-action="hide"
761
            onclick="localStorage.setItem('${StorageKeysEnum.OpeningMode}', '${OpeningModeEnum.LogoNextToFile}'); location.reload()">
762
              ${this.pluginParams.strings.stopmodal}
763
            </a>
764
          </div>`;
765
      }
766
 
767
      return body;
768
    }
769
 
770
    /**
771
    * Generate a button.
772
    *
773
    * @param href - The button's href.
774
    * @param title - The button's title.
775
    *
776
    * @returns The button as HTML string.
777
    */
778
    private static generateButtonHTML(href: string, title: string, faIconClass?: string, style: string = ''): string
779
    {
780
      let faIconHTML = '';
781
 
782
      if (faIconClass)
783
      {
784
        faIconHTML = `<i class="${faIconClass} mr-2"></i> `;
785
      }
786
 
787
      return `<a class="btn btn-secondary" style="width: 100%; margin-top: 1rem; ${style}" href="${href}" target="_blank">${faIconHTML}${title}</a>`;
788
    }
789
  }
790
 
791
  return new Main();
792
});
793
 
794
 
795
enum OpeningModeEnum
796
{
797
  FileClick = '0',
798
  LogoNextToFile = '1',
799
  IconNextToFile = '2',
800
  IconNextToFileWithText = '3',
801
}
802
 
803
enum OpeningTargetEnum
804
{
805
  Amanote = '0',
806
  MoodleFullscreen = '1',
807
  MoodleEmbedded = '2',
808
}
809
 
810
enum ContentKindEnum
811
{
812
  Document = 'document',
813
  Video = 'video',
814
}
815
 
816
enum StorageKeysEnum
817
{
818
  OpeningMode = 'amanote.preferences.openingMode',
819
  HideDeleteWarningExp = 'amanote.preferences.hideDeleteWarningExp',
820
}
821
 
822
interface IAnnotatable
823
{
824
  id: string;
825
  legacyid: string;
826
  cmid: number;
827
  mimetype: string;
828
  url: string;
829
  internal: boolean;
830
  kind: ContentKindEnum;
831
  openInMoodleURL: string;
832
}
833
 
834
interface IMoodleUserParams
835
{
836
  id: string;
837
  token: {
838
    value: string;
839
    expiration: number;
840
  },
841
  isTeacher: boolean;
842
}
843
 
844
interface IPluginSettings
845
{
846
  version: string;
847
  saveInProvider: boolean;
848
  openingMode: OpeningModeEnum;
849
  target: OpeningTargetEnum;
850
  preventDownload: boolean;
851
  anonymous: boolean;
852
  key: string;
853
  logo: string;
854
  annotatedLogo: string;
855
  worksheet: boolean;
856
}
857
 
858
interface IPluginParams
859
{
860
  siteURL: string;
861
  language: string;
862
  privateFilePath: string;
863
  annotatables: IAnnotatable[];
864
  savedNotes: { [filename: string]: { filename: string}};
865
  moodle: {
866
    version: string;
867
  }
868
  plugin: IPluginSettings,
869
  strings: {
870
    modalDescription: string;
871
    annotateResource: string;
872
    viewResource: string;
873
    downloadNotes: string;
874
    openAnalytics: string;
875
    openPodcastCreator: string;
876
    openStudentsWorks: string;
877
    teacher: string;
878
    deletefilewarning: string;
879
    seeguide: string;
880
    stopmodal: string;
881
  }
882
}