From f0c5e8b65792e9f991bf006a3e1d03cfd2c80c24 Mon Sep 17 00:00:00 2001
From: Chocobozzz <me@florianbigard.com>
Date: Tue, 16 Jul 2019 16:09:58 +0200
Subject: [PATCH] Add client helpers to plugins

---
 .../plugin-search/plugin-search.component.ts  |  7 ++-
 client/src/app/app.component.html             |  2 +-
 client/src/app/app.component.scss             |  5 +-
 client/src/app/core/plugins/plugin.service.ts | 51 +++++++++++++++----
 client/src/app/core/theme/theme.service.ts    |  2 +-
 5 files changed, 52 insertions(+), 15 deletions(-)

diff --git a/client/src/app/+admin/plugins/plugin-search/plugin-search.component.ts b/client/src/app/+admin/plugins/plugin-search/plugin-search.component.ts
index 0058fa691d..a6fbeed842 100644
--- a/client/src/app/+admin/plugins/plugin-search/plugin-search.component.ts
+++ b/client/src/app/+admin/plugins/plugin-search/plugin-search.component.ts
@@ -92,7 +92,12 @@ export class PluginSearchComponent implements OnInit {
             this.pagination.totalItems = res.total
           },
 
-          err => this.notifier.error(err.message)
+          err => {
+            console.error(err)
+
+            const message = this.i18n('The plugin index is not available. Please retry later.')
+            this.notifier.error(message)
+          }
         )
   }
 
diff --git a/client/src/app/app.component.html b/client/src/app/app.component.html
index d398d4f351..07a576083c 100644
--- a/client/src/app/app.component.html
+++ b/client/src/app/app.component.html
@@ -8,7 +8,7 @@
     <div class="top-left-block" [ngClass]="{ 'border-bottom': isMenuDisplayed === false }">
       <span class="icon icon-menu" (click)="toggleMenu()"></span>
 
-      <a id="peertube-title" [routerLink]="defaultRoute" title="Homepage">
+      <a class="peertube-title" [routerLink]="defaultRoute" title="Homepage">
         <span class="icon icon-logo"></span>
         <span class="instance-name">{{ instanceName }}</span>
       </a>
diff --git a/client/src/app/app.component.scss b/client/src/app/app.component.scss
index 3f8b9777af..c95b21ca37 100644
--- a/client/src/app/app.component.scss
+++ b/client/src/app/app.component.scss
@@ -38,8 +38,9 @@
       }
     }
 
-    #peertube-title {
+    .peertube-title {
       @include disable-default-a-behaviour;
+
       font-size: 20px;
       font-weight: $font-bold;
       color: inherit !important;
@@ -64,7 +65,7 @@
     @media screen and (max-width: 500px) {
       width: 70px;
 
-      #peertube-title {
+      .peertube-title {
         display: none;
       }
     }
diff --git a/client/src/app/core/plugins/plugin.service.ts b/client/src/app/core/plugins/plugin.service.ts
index c6ba3dd17b..525740a01b 100644
--- a/client/src/app/core/plugins/plugin.service.ts
+++ b/client/src/app/core/plugins/plugin.service.ts
@@ -14,12 +14,19 @@ interface HookStructValue extends RegisterHookOptions {
   clientScript: ClientScript
 }
 
+type PluginInfo = {
+  plugin: ServerConfigPlugin
+  clientScript: ClientScript
+  isTheme: boolean
+}
+
 @Injectable()
 export class PluginService {
   pluginsLoaded = new ReplaySubject<boolean>(1)
 
   private plugins: ServerConfigPlugin[] = []
-  private scopes: { [ scopeName: string ]: { plugin: ServerConfigPlugin, clientScript: ClientScript }[] } = {}
+  private scopes: { [ scopeName: string ]: PluginInfo[] } = {}
+  private loadedPlugins: { [ name: string ]: boolean } = {}
   private loadedScripts: { [ script: string ]: boolean } = {}
   private loadedScopes: PluginScope[] = []
 
@@ -49,7 +56,7 @@ export class PluginService {
   }
 
   addPlugin (plugin: ServerConfigPlugin, isTheme = false) {
-    const pathPrefix = isTheme ? '/themes' : '/plugins'
+    const pathPrefix = this.getPluginPathPrefix(isTheme)
 
     for (const key of Object.keys(plugin.clientScripts)) {
       const clientScript = plugin.clientScripts[key]
@@ -62,7 +69,8 @@ export class PluginService {
           clientScript: {
             script: environment.apiUrl + `${pathPrefix}/${plugin.name}/${plugin.version}/client-scripts/${clientScript.script}`,
             scopes: clientScript.scopes
-          }
+          },
+          isTheme
         })
 
         this.loadedScripts[clientScript.script] = false
@@ -78,24 +86,26 @@ export class PluginService {
 
   async reloadLoadedScopes () {
     for (const scope of this.loadedScopes) {
-      await this.loadPluginsByScope(scope)
+      await this.loadPluginsByScope(scope, true)
     }
   }
 
-  async loadPluginsByScope (scope: PluginScope) {
+  async loadPluginsByScope (scope: PluginScope, isReload = false) {
     try {
       await this.ensurePluginsAreLoaded()
 
-      this.loadedScopes.push(scope)
+      if (!isReload) this.loadedScopes.push(scope)
 
       const toLoad = this.scopes[ scope ]
       if (!Array.isArray(toLoad)) return
 
       const promises: Promise<any>[] = []
-      for (const { plugin, clientScript } of toLoad) {
+      for (const pluginInfo of toLoad) {
+        const clientScript = pluginInfo.clientScript
+
         if (this.loadedScripts[ clientScript.script ]) continue
 
-        promises.push(this.loadPlugin(plugin, clientScript))
+        promises.push(this.loadPlugin(pluginInfo))
 
         this.loadedScripts[ clientScript.script ] = true
       }
@@ -109,6 +119,8 @@ export class PluginService {
   async runHook (hookName: string, param?: any) {
     let result = param
 
+    if (!this.hooks[hookName]) return result
+
     const wait = hookName.startsWith('static:')
 
     for (const hook of this.hooks[hookName]) {
@@ -123,7 +135,9 @@ export class PluginService {
     return result
   }
 
-  private loadPlugin (plugin: ServerConfigPlugin, clientScript: ClientScript) {
+  private loadPlugin (pluginInfo: PluginInfo) {
+    const { plugin, clientScript } = pluginInfo
+
     const registerHook = (options: RegisterHookOptions) => {
       if (!this.hooks[options.target]) this.hooks[options.target] = []
 
@@ -136,10 +150,12 @@ export class PluginService {
       })
     }
 
+    const peertubeHelpers = this.buildPeerTubeHelpers(pluginInfo)
+
     console.log('Loading script %s of plugin %s.', clientScript.script, plugin.name)
 
     return import(/* webpackIgnore: true */ clientScript.script)
-      .then(script => script.register({ registerHook }))
+      .then(script => script.register({ registerHook, peertubeHelpers }))
       .then(() => this.sortHooksByPriority())
   }
 
@@ -156,4 +172,19 @@ export class PluginService {
       })
     }
   }
+
+  private buildPeerTubeHelpers (pluginInfo: PluginInfo) {
+    const { plugin } = pluginInfo
+
+    return {
+      getBaseStaticRoute: () => {
+        const pathPrefix = this.getPluginPathPrefix(pluginInfo.isTheme)
+        return environment.apiUrl + `${pathPrefix}/${plugin.name}/${plugin.version}/static`
+      }
+    }
+  }
+
+  private getPluginPathPrefix (isTheme: boolean) {
+    return isTheme ? '/themes' : '/plugins'
+  }
 }
diff --git a/client/src/app/core/theme/theme.service.ts b/client/src/app/core/theme/theme.service.ts
index 76199d1cc0..0124880751 100644
--- a/client/src/app/core/theme/theme.service.ts
+++ b/client/src/app/core/theme/theme.service.ts
@@ -87,7 +87,7 @@ export class ThemeService {
     const theme = this.getTheme(currentTheme)
     if (theme) {
       console.log('Adding scripts of theme %s.', currentTheme)
-      this.pluginService.addPlugin(theme)
+      this.pluginService.addPlugin(theme, true)
 
       this.pluginService.reloadLoadedScopes()
     }
-- 
GitLab