]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - client/src/app/core/theme/theme.service.ts
video description/account alignment, watch view basic tooltips
[github/Chocobozzz/PeerTube.git] / client / src / app / core / theme / theme.service.ts
CommitLineData
1a00c561 1import { Injectable } from '@angular/core'
ffb321be
C
2import { AuthService } from '@app/core/auth'
3import { ServerService } from '@app/core/server'
4import { environment } from '../../../environments/environment'
5import { PluginService } from '@app/core/plugins/plugin.service'
6import { ServerConfigTheme } from '@shared/models'
88a7f93f 7import { peertubeLocalStorage } from '@app/shared/misc/peertube-web-storage'
1a00c561
RK
8
9@Injectable()
10export class ThemeService {
ffb321be 11
a2ffd046
C
12 private static KEYS = {
13 LAST_ACTIVE_THEME: 'last_active_theme'
14 }
15
ffb321be
C
16 private oldThemeName: string
17 private themes: ServerConfigTheme[] = []
18
a2ffd046
C
19 private themeFromLocalStorage: ServerConfigTheme
20 private themeDOMLinksFromLocalStorage: HTMLLinkElement[] = []
21
ffb321be
C
22 constructor (
23 private auth: AuthService,
24 private pluginService: PluginService,
25 private server: ServerService
26 ) {}
27
28 initialize () {
a2ffd046
C
29 // Try to load from local storage first, so we don't have to wait network requests
30 this.loadAndSetFromLocalStorage()
31
ffb321be
C
32 this.server.configLoaded
33 .subscribe(() => {
a2ffd046
C
34 const themes = this.server.getConfig().theme.registered
35
36 this.removeThemeFromLocalStorageIfNeeded(themes)
37 this.injectThemes(themes)
ffb321be
C
38
39 this.listenUserTheme()
40 })
41 }
42
a2ffd046
C
43 private injectThemes (themes: ServerConfigTheme[], fromLocalStorage = false) {
44 this.themes = themes
ffb321be
C
45
46 console.log('Injecting %d themes.', this.themes.length)
47
a2ffd046 48 const head = this.getHeadElement()
ffb321be
C
49
50 for (const theme of this.themes) {
a2ffd046
C
51 // Already added this theme?
52 if (fromLocalStorage === false && this.themeFromLocalStorage && this.themeFromLocalStorage.name === theme.name) continue
ffb321be
C
53
54 for (const css of theme.css) {
55 const link = document.createElement('link')
56
57 const href = environment.apiUrl + `/themes/${theme.name}/${theme.version}/css/${css}`
58 link.setAttribute('href', href)
59 link.setAttribute('rel', 'alternate stylesheet')
60 link.setAttribute('type', 'text/css')
61 link.setAttribute('title', theme.name)
62 link.setAttribute('disabled', '')
63
a2ffd046
C
64 if (fromLocalStorage === true) this.themeDOMLinksFromLocalStorage.push(link)
65
ffb321be
C
66 head.appendChild(link)
67 }
68 }
69 }
70
71 private getCurrentTheme () {
a2ffd046
C
72 if (this.themeFromLocalStorage) return this.themeFromLocalStorage.name
73
ffb321be
C
74 if (this.auth.isLoggedIn()) {
75 const theme = this.auth.getUser().theme
76 if (theme !== 'instance-default') return theme
77 }
78
79 return this.server.getConfig().theme.default
1a00c561
RK
80 }
81
ffb321be
C
82 private loadTheme (name: string) {
83 const links = document.getElementsByTagName('link')
84 for (let i = 0; i < links.length; i++) {
85 const link = links[ i ]
86 if (link.getAttribute('rel').indexOf('style') !== -1 && link.getAttribute('title')) {
87 link.disabled = link.getAttribute('title') !== name
88 }
89 }
90 }
91
92 private updateCurrentTheme () {
a2ffd046 93 if (this.oldThemeName) this.removeThemePlugins(this.oldThemeName)
ffb321be
C
94
95 const currentTheme = this.getCurrentTheme()
96
97 console.log('Enabling %s theme.', currentTheme)
98
99 this.loadTheme(currentTheme)
d00dc28d 100
ffb321be
C
101 const theme = this.getTheme(currentTheme)
102 if (theme) {
103 console.log('Adding scripts of theme %s.', currentTheme)
f0c5e8b6 104 this.pluginService.addPlugin(theme, true)
ffb321be
C
105
106 this.pluginService.reloadLoadedScopes()
a2ffd046
C
107
108 peertubeLocalStorage.setItem(ThemeService.KEYS.LAST_ACTIVE_THEME, JSON.stringify(theme))
109 } else {
110 peertubeLocalStorage.removeItem(ThemeService.KEYS.LAST_ACTIVE_THEME)
e3f7f600 111 }
ffb321be
C
112
113 this.oldThemeName = currentTheme
114 }
115
116 private listenUserTheme () {
a2ffd046
C
117 // We don't need them anymore
118 this.themeFromLocalStorage = undefined
119 this.themeDOMLinksFromLocalStorage = []
120
d00dc28d
C
121 if (!this.auth.isLoggedIn()) {
122 this.updateCurrentTheme()
123 }
124
ffb321be
C
125 this.auth.userInformationLoaded
126 .subscribe(() => this.updateCurrentTheme())
1a00c561
RK
127 }
128
a2ffd046
C
129 private loadAndSetFromLocalStorage () {
130 const lastActiveThemeString = peertubeLocalStorage.getItem(ThemeService.KEYS.LAST_ACTIVE_THEME)
131 if (!lastActiveThemeString) return
132
133 try {
134 const lastActiveTheme = JSON.parse(lastActiveThemeString)
135 this.themeFromLocalStorage = lastActiveTheme
136
137 this.injectThemes([ lastActiveTheme ], true)
138 this.updateCurrentTheme()
139 } catch (err) {
140 console.error('Cannot parse last active theme.', err)
141 return
142 }
143 }
144
145 private removeThemePlugins (themeName: string) {
146 const oldTheme = this.getTheme(themeName)
147 if (oldTheme) {
148 console.log('Removing scripts of old theme %s.', themeName)
149 this.pluginService.removePlugin(oldTheme)
150 }
151 }
152
153 private removeThemeFromLocalStorageIfNeeded (themes: ServerConfigTheme[]) {
154 if (!this.themeFromLocalStorage) return
155
156 const loadedTheme = themes.find(t => t.name === this.themeFromLocalStorage.name)
157 if (!loadedTheme || loadedTheme.version !== this.themeFromLocalStorage.version) {
158 // Need to remove this theme: we loaded an old version or a theme that does not exist anymore
159 this.removeThemePlugins(this.themeFromLocalStorage.name)
160 this.oldThemeName = undefined
161
162 const head = this.getHeadElement()
163 for (const htmlLinkElement of this.themeDOMLinksFromLocalStorage) {
164 head.removeChild(htmlLinkElement)
165 }
166
167 this.themeFromLocalStorage = undefined
168 this.themeDOMLinksFromLocalStorage = []
169 }
170 }
171
172 private getHeadElement () {
173 return document.getElementsByTagName('head')[0]
174 }
175
ffb321be
C
176 private getTheme (name: string) {
177 return this.themes.find(t => t.name === name)
1a00c561
RK
178 }
179}