Skip to content

Commit 667ba02

Browse files
authored
Merge pull request #3902 from crazyserver/MOBILE-4266
MOBILE-4266 site: Add site theme class to html tags
2 parents a8ffee0 + 8b38b54 commit 667ba02

File tree

9 files changed

+408
-246
lines changed

9 files changed

+408
-246
lines changed

src/app/app.component.test.ts

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,37 +13,16 @@
1313
// limitations under the License.
1414

1515
import { AppComponent } from '@/app/app.component';
16-
import { CoreEvents } from '@singletons/events';
17-
import { CoreLang, CoreLangProvider } from '@services/lang';
1816

19-
import { mockSingleton, renderComponent } from '@/testing/utils';
20-
import { CoreNavigator, CoreNavigatorService } from '@services/navigator';
17+
import { renderComponent } from '@/testing/utils';
2118

2219
describe('AppComponent', () => {
2320

24-
let langProvider: CoreLangProvider;
25-
let navigator: CoreNavigatorService;
26-
27-
beforeEach(() => {
28-
navigator = mockSingleton(CoreNavigator, ['navigate']);
29-
langProvider = mockSingleton(CoreLang, ['clearCustomStrings']);
30-
});
31-
3221
it('should render', async () => {
3322
const fixture = await renderComponent(AppComponent);
3423

3524
expect(fixture.debugElement.componentInstance).toBeTruthy();
3625
expect(fixture.nativeElement.querySelector('ion-router-outlet')).toBeTruthy();
3726
});
3827

39-
it('cleans up on logout', async () => {
40-
const fixture = await renderComponent(AppComponent);
41-
42-
fixture.componentInstance.ngOnInit();
43-
CoreEvents.trigger(CoreEvents.LOGOUT);
44-
45-
expect(langProvider.clearCustomStrings).toHaveBeenCalled();
46-
expect(navigator.navigate).toHaveBeenCalledWith('/login/sites', { reset: true });
47-
});
48-
4928
});

src/app/app.component.ts

Lines changed: 2 additions & 216 deletions
Original file line numberDiff line numberDiff line change
@@ -14,33 +14,20 @@
1414

1515
import { AfterViewInit, Component, OnInit, ViewChild } from '@angular/core';
1616
import { IonRouterOutlet } from '@ionic/angular';
17-
import { BackButtonEvent, ScrollDetail } from '@ionic/core';
17+
import { BackButtonEvent } from '@ionic/core';
1818

19-
import { CoreLang } from '@services/lang';
2019
import { CoreLoginHelper } from '@features/login/services/login-helper';
21-
import { CoreEvents } from '@singletons/events';
22-
import { NgZone, SplashScreen } from '@singletons';
23-
import { CoreNetwork } from '@services/network';
20+
import { SplashScreen } from '@singletons';
2421
import { CoreApp } from '@services/app';
25-
import { CoreSites } from '@services/sites';
2622
import { CoreNavigator } from '@services/navigator';
2723
import { CoreSubscriptions } from '@singletons/subscriptions';
2824
import { CoreWindow } from '@singletons/window';
2925
import { CoreUtils } from '@services/utils/utils';
30-
import { CoreConstants } from '@/core/constants';
31-
import { CoreSitePlugins } from '@features/siteplugins/services/siteplugins';
32-
import { CoreDomUtils } from '@services/utils/dom';
33-
import { CoreDom } from '@singletons/dom';
3426
import { CorePlatform } from '@services/platform';
35-
import { CoreUrl } from '@singletons/url';
3627
import { CoreLogger } from '@singletons/logger';
3728
import { CorePromisedValue } from '@classes/promised-value';
3829
import { register } from 'swiper/element/bundle';
3930

40-
const MOODLE_SITE_URL_PREFIX = 'url-';
41-
const MOODLE_VERSION_PREFIX = 'version-';
42-
const MOODLEAPP_VERSION_PREFIX = 'moodleapp-';
43-
4431
register();
4532

4633
@Component({
@@ -59,43 +46,6 @@ export class AppComponent implements OnInit, AfterViewInit {
5946
ngOnInit(): void {
6047
// eslint-disable-next-line @typescript-eslint/no-explicit-any
6148
const win = <any> window;
62-
CoreDomUtils.toggleModeClass('ionic7', true, { includeLegacy: true });
63-
CoreDomUtils.toggleModeClass('development', CoreConstants.BUILD.isDevelopment);
64-
this.addVersionClass(MOODLEAPP_VERSION_PREFIX, CoreConstants.CONFIG.versionname.replace('-dev', ''));
65-
66-
CoreEvents.on(CoreEvents.LOGOUT, async () => {
67-
// Unload lang custom strings.
68-
CoreLang.clearCustomStrings();
69-
70-
// Remove version classes from body.
71-
this.removeModeClasses([MOODLE_VERSION_PREFIX, MOODLE_SITE_URL_PREFIX]);
72-
73-
// Go to sites page when user is logged out.
74-
await CoreNavigator.navigate('/login/sites', { reset: true });
75-
76-
if (CoreSitePlugins.hasSitePluginsLoaded) {
77-
// Temporary fix. Reload the page to unload all plugins.
78-
window.location.reload();
79-
}
80-
});
81-
82-
// Listen to scroll to add style when scroll is not 0.
83-
win.addEventListener('ionScroll', async ({ detail, target }: CustomEvent<ScrollDetail>) => {
84-
if ((target as HTMLElement).tagName != 'ION-CONTENT') {
85-
return;
86-
}
87-
const content = (target as HTMLIonContentElement);
88-
89-
const page = content.closest('.ion-page');
90-
if (!page) {
91-
return;
92-
}
93-
94-
page.querySelector<HTMLIonHeaderElement>('ion-header')?.classList.toggle('core-header-shadow', detail.scrollTop > 0);
95-
96-
const scrollElement = await content.getScrollElement();
97-
content.classList.toggle('core-footer-shadow', !CoreDom.scrollIsBottom(scrollElement));
98-
});
9949

10050
CorePlatform.resume.subscribe(() => {
10151
// Wait a second before setting it to false since in iOS there could be some frozen WS calls.
@@ -117,53 +67,6 @@ export class AppComponent implements OnInit, AfterViewInit {
11767
CoreWindow.open(url);
11868
};
11969

120-
CoreEvents.on(CoreEvents.LOGIN, async (data) => {
121-
if (data.siteId) {
122-
const site = await CoreSites.getSite(data.siteId);
123-
const info = site.getInfo();
124-
if (info) {
125-
// Add version classes to body.
126-
this.removeModeClasses([MOODLE_VERSION_PREFIX, MOODLE_SITE_URL_PREFIX]);
127-
128-
this.addVersionClass(MOODLE_VERSION_PREFIX, CoreSites.getReleaseNumber(info.release || ''));
129-
this.addSiteUrlClass(info.siteurl);
130-
}
131-
}
132-
133-
this.loadCustomStrings();
134-
});
135-
136-
// Site config is checked in login.
137-
CoreEvents.on(CoreEvents.LOGIN_SITE_CHECKED, (data) => {
138-
this.addSiteUrlClass(data.config.httpswwwroot);
139-
});
140-
141-
CoreEvents.on(CoreEvents.SITE_UPDATED, async (data) => {
142-
if (data.siteId === CoreSites.getCurrentSiteId()) {
143-
this.loadCustomStrings();
144-
145-
// Add version classes to body.
146-
this.removeModeClasses([MOODLE_VERSION_PREFIX, MOODLE_SITE_URL_PREFIX]);
147-
148-
this.addVersionClass(MOODLE_VERSION_PREFIX, CoreSites.getReleaseNumber(data.release || ''));
149-
this.addSiteUrlClass(data.siteurl);
150-
}
151-
});
152-
153-
CoreEvents.on(CoreEvents.SITE_ADDED, (data) => {
154-
if (data.siteId === CoreSites.getCurrentSiteId()) {
155-
this.loadCustomStrings();
156-
157-
// Add version classes to body.
158-
this.removeModeClasses([MOODLE_VERSION_PREFIX, MOODLE_SITE_URL_PREFIX]);
159-
160-
this.addVersionClass(MOODLE_VERSION_PREFIX, CoreSites.getReleaseNumber(data.release || ''));
161-
this.addSiteUrlClass(data.siteurl);
162-
}
163-
});
164-
165-
this.onPlatformReady();
166-
16770
// Quit app with back button.
16871
document.addEventListener('ionBackButton', (event: BackButtonEvent) => {
16972
// This callback should have the lowest priority in the app.
@@ -244,121 +147,4 @@ export class AppComponent implements OnInit, AfterViewInit {
244147
return promise;
245148
}
246149

247-
/**
248-
* Async init function on platform ready.
249-
*/
250-
protected async onPlatformReady(): Promise<void> {
251-
await CorePlatform.ready();
252-
253-
this.logger.debug('Platform is ready');
254-
255-
// Refresh online status when changes.
256-
CoreNetwork.onChange().subscribe(() => {
257-
// Execute the callback in the Angular zone, so change detection doesn't stop working.
258-
NgZone.run(() => {
259-
const isOnline = CoreNetwork.isOnline();
260-
const hadOfflineMessage = CoreDomUtils.hasModeClass('core-offline');
261-
262-
CoreDomUtils.toggleModeClass('core-offline', !isOnline, { includeLegacy: true });
263-
264-
if (isOnline && hadOfflineMessage) {
265-
CoreDomUtils.toggleModeClass('core-online', true, { includeLegacy: true });
266-
267-
setTimeout(() => {
268-
CoreDomUtils.toggleModeClass('core-online', false, { includeLegacy: true });
269-
}, 3000);
270-
} else if (!isOnline) {
271-
CoreDomUtils.toggleModeClass('core-online', false, { includeLegacy: true });
272-
}
273-
});
274-
});
275-
276-
const isOnline = CoreNetwork.isOnline();
277-
CoreDomUtils.toggleModeClass('core-offline', !isOnline, { includeLegacy: true });
278-
}
279-
280-
/**
281-
* Load custom lang strings. This cannot be done inside the lang provider because it causes circular dependencies.
282-
*/
283-
protected loadCustomStrings(): void {
284-
const currentSite = CoreSites.getCurrentSite();
285-
286-
if (currentSite) {
287-
CoreLang.loadCustomStringsFromSite(currentSite);
288-
}
289-
}
290-
291-
/**
292-
* Convenience function to add version to html classes.
293-
*
294-
* @param prefix Prefix to add to the class.
295-
* @param release Current release number of the site.
296-
*/
297-
protected addVersionClass(prefix: string, release: string): void {
298-
const parts = release.split('.', 3);
299-
300-
parts[1] = parts[1] || '0';
301-
parts[2] = parts[2] || '0';
302-
303-
CoreDomUtils.toggleModeClass(prefix + parts[0], true, { includeLegacy: true });
304-
CoreDomUtils.toggleModeClass(prefix + parts[0] + '-' + parts[1], true, { includeLegacy: true });
305-
CoreDomUtils.toggleModeClass(prefix + parts[0] + '-' + parts[1] + '-' + parts[2], true, { includeLegacy: true });
306-
}
307-
308-
/**
309-
* Convenience function to remove all mode classes form body.
310-
*
311-
* @param prefixes Prefixes of the class mode to be removed.
312-
*/
313-
protected removeModeClasses(prefixes: string[]): void {
314-
for (const modeClass of CoreDomUtils.getModeClasses()) {
315-
if (!prefixes.some((prefix) => modeClass.startsWith(prefix))) {
316-
continue;
317-
}
318-
319-
CoreDomUtils.toggleModeClass(modeClass, false, { includeLegacy: true });
320-
}
321-
}
322-
323-
/**
324-
* Converts the provided URL into a CSS class that be used within the page.
325-
* This is primarily used to add the siteurl to the body tag as a CSS class.
326-
* Extracted from LMS url_to_class_name function.
327-
*
328-
* @param url Url.
329-
* @returns Class name
330-
*/
331-
protected urlToClassName(url: string): string {
332-
const parsedUrl = CoreUrl.parse(url);
333-
334-
if (!parsedUrl) {
335-
return '';
336-
}
337-
338-
let className = parsedUrl.domain?.replace(/\./g, '-') || '';
339-
340-
if (parsedUrl.port) {
341-
className += `--${parsedUrl.port}`;
342-
}
343-
if (parsedUrl.path) {
344-
const leading = new RegExp('^/+');
345-
const trailing = new RegExp('/+$');
346-
const path = parsedUrl.path.replace(leading, '').replace(trailing, '');
347-
if (path) {
348-
className += '--' + path.replace(/\//g, '-') || '';
349-
}
350-
}
351-
352-
return className;
353-
}
354-
355-
/**
356-
* Convenience function to add site url to html classes.
357-
*/
358-
protected addSiteUrlClass(siteUrl: string): void {
359-
const className = this.urlToClassName(siteUrl);
360-
361-
CoreDomUtils.toggleModeClass(MOODLE_SITE_URL_PREFIX + className, true);
362-
}
363-
364150
}

src/core/features/courses/services/courses.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1402,7 +1402,7 @@ export type CoreCourseSearchedData = CoreCourseBasicSearchedData & {
14021402
enablecompletion?: number; // Completion enabled? 1: yes 0: no.
14031403
completionnotify?: number; // 1: yes 0: no.
14041404
lang?: string; // Forced course language.
1405-
theme?: string; // Fame of the forced theme.
1405+
theme?: string; // Name of the forced theme.
14061406
marker?: number; // Current course marker.
14071407
legacyfiles?: number; // If legacy files are enabled.
14081408
calendartype?: string; // Calendar type.

src/core/initializers/app.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// (C) Copyright 2015 Moodle Pty Ltd.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import { CoreHTMLClasses } from '@singletons/html-classes';
16+
17+
/**
18+
* General App initializer.
19+
*/
20+
export default async function(): Promise<void> {
21+
CoreHTMLClasses.initialize();
22+
}

src/core/services/lang.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import { AddonFilterMultilangHandler } from '@addons/filter/multilang/services/h
2828
import { AddonFilterMultilang2Handler } from '@addons/filter/multilang2/services/handlers/multilang2';
2929
import { firstValueFrom } from 'rxjs';
3030
import { CoreLogger } from '@singletons/logger';
31+
import { CoreSites } from './sites';
3132

3233
/*
3334
* Service to handle language features, like changing the current language.
@@ -380,14 +381,22 @@ export class CoreLangProvider {
380381
/**
381382
* Loads custom strings obtained from site.
382383
*
383-
* @param currentSite Current site object.
384+
* @param currentSite Current site object. If not defined, use current site.
384385
*/
385-
loadCustomStringsFromSite(currentSite: CoreSite): void {
386+
loadCustomStringsFromSite(currentSite?: CoreSite): void {
387+
currentSite = currentSite ?? CoreSites.getCurrentSite();
388+
389+
if (!currentSite) {
390+
return;
391+
}
392+
386393
const customStrings = currentSite.getStoredConfig('tool_mobile_customlangstrings');
387394

388-
if (customStrings !== undefined) {
389-
this.loadCustomStrings(customStrings);
395+
if (customStrings === undefined) {
396+
return;
390397
}
398+
399+
this.loadCustomStrings(customStrings);
391400
}
392401

393402
/**

0 commit comments

Comments
 (0)