Skip to content

Commit 5899e03

Browse files
committed
MOBILE-3546 login: Add options to customize site listing
1 parent a394955 commit 5899e03

File tree

4 files changed

+121
-64
lines changed

4 files changed

+121
-64
lines changed

src/config.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
"siteurl": "",
8282
"sitename": "",
8383
"multisitesdisplay": "",
84+
"sitefindersettings": {},
8485
"onlyallowlistedsites": false,
8586
"skipssoconfirmation": false,
8687
"forcedefaultlanguage": false,

src/core/login/pages/site/site.html

Lines changed: 45 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -14,77 +14,72 @@
1414
<div text-center padding margin-bottom [class.hidden]="hasSites || enteredSiteUrl" class="core-login-site-logo">
1515
<img src="assets/img/login_logo.png" class="avatar-full login-logo" role="presentation">
1616
</div>
17-
<form ion-list [formGroup]="siteForm" (ngSubmit)="connect($event, siteForm.value.siteUrl)" *ngIf="!fixedSites || siteSelector == 'select'" #siteFormEl>
17+
<form ion-list [formGroup]="siteForm" (ngSubmit)="connect($event, siteForm.value.siteUrl)" *ngIf="!fixedSites" #siteFormEl>
1818
<!-- Form to input the site URL if there are no fixed sites. -->
19-
<ng-container *ngIf="!fixedSites">
20-
<ng-container *ngIf="siteSelector == 'url'">
21-
<ion-item>
22-
<ion-label stacked><h2>{{ 'core.login.siteaddress' | translate }}</h2></ion-label>
23-
<ion-input name="url" type="url" placeholder="{{ 'core.login.siteaddressplaceholder' | translate }}" formControlName="siteUrl" [core-auto-focus]="showKeyboard && !showScanQR"></ion-input>
24-
</ion-item>
25-
</ng-container>
26-
<ng-container *ngIf="siteSelector != 'url'">
27-
<ion-item>
28-
<ion-label stacked><h2>{{ 'core.login.siteaddress' | translate }}</h2></ion-label>
29-
<ion-input name="url" placeholder="{{ 'core.login.siteaddressplaceholder' | translate }}" formControlName="siteUrl" [core-auto-focus]="showKeyboard && !showScanQR" (ionChange)="searchSite($event, siteForm.value.siteUrl)"></ion-input>
30-
</ion-item>
19+
<ng-container *ngIf="siteSelector == 'url'">
20+
<ion-item>
21+
<ion-label stacked><h2>{{ 'core.login.siteaddress' | translate }}</h2></ion-label>
22+
<ion-input name="url" type="url" placeholder="{{ 'core.login.siteaddressplaceholder' | translate }}" formControlName="siteUrl" [core-auto-focus]="showKeyboard && !showScanQR"></ion-input>
23+
</ion-item>
24+
</ng-container>
25+
<ng-container *ngIf="siteSelector != 'url'">
26+
<ion-item>
27+
<ion-label stacked><h2>{{ 'core.login.siteaddress' | translate }}</h2></ion-label>
28+
<ion-input name="url" placeholder="{{ 'core.login.siteaddressplaceholder' | translate }}" formControlName="siteUrl" [core-auto-focus]="showKeyboard && !showScanQR" (ionChange)="searchSite($event, siteForm.value.siteUrl)"></ion-input>
29+
</ion-item>
30+
31+
<ion-list [class.hidden]="!hasSites && !enteredSiteUrl" class="core-login-site-list">
32+
<ion-item no-lines class="core-login-site-list-title"><h2 class="item-heading">{{ 'core.login.selectsite' | translate }}</h2></ion-item>
33+
<button ion-item *ngIf="enteredSiteUrl" (click)="connect($event, enteredSiteUrl.url)" [attr.aria-label]="'core.login.connect' | translate" detail-push class="core-login-entered-site">
34+
<ion-thumbnail item-start>
35+
<core-icon name="fa-pencil"></core-icon>
36+
</ion-thumbnail>
37+
<h2 text-wrap>{{ 'core.login.yourenteredsite' | translate }}</h2>
38+
<p>{{enteredSiteUrl.noProtocolUrl}}</p>
39+
</button>
3140

32-
<ion-list [class.hidden]="!hasSites && !enteredSiteUrl" class="core-login-site-list">
33-
<ion-item no-lines class="core-login-site-list-title"><h2 class="item-heading">{{ 'core.login.selectsite' | translate }}</h2></ion-item>
34-
<button ion-item *ngIf="enteredSiteUrl" (click)="connect($event, enteredSiteUrl.url)" [attr.aria-label]="'core.login.connect' | translate" detail-push class="core-login-entered-site">
35-
<ion-thumbnail item-start>
36-
<core-icon name="fa-pencil"></core-icon>
41+
<div class="core-login-site-list-found" [class.hidden]="!hasSites" [class.dimmed]="loadingSites">
42+
<div *ngIf="loadingSites" class="core-login-site-list-loading"><ion-spinner></ion-spinner></div>
43+
<button ion-item *ngFor="let site of sites" (click)="connect($event, site.url, site)" [attr.aria-label]="site.name" detail-push>
44+
<ion-thumbnail item-start *ngIf="siteFinderSettings.displayimage">
45+
<img [src]="site.imageurl" *ngIf="site.imageurl" onError="this.src='assets/icon/icon.png'">
46+
<img src="assets/icon/icon.png" *ngIf="!site.imageurl" class="core-login-default-icon">
3747
</ion-thumbnail>
38-
<h2 text-wrap>{{ 'core.login.yourenteredsite' | translate }}</h2>
39-
<p>{{enteredSiteUrl.noProtocolUrl}}</p>
48+
<h2 *ngIf="site.title" text-wrap>{{site.title}}</h2>
49+
<p *ngIf="site.noProtocolUrl">{{site.noProtocolUrl}}</p>
50+
<p *ngIf="site.location">{{site.location}}</p>
4051
</button>
52+
</div>
53+
</ion-list>
4154

42-
<div class="core-login-site-list-found" [class.hidden]="!hasSites" [class.dimmed]="loadingSites">
43-
<div *ngIf="loadingSites" class="core-login-site-list-loading"><ion-spinner></ion-spinner></div>
44-
<button ion-item *ngFor="let site of sites" (click)="connect($event, site.url, site)" [attr.aria-label]="site.name" detail-push>
45-
<ion-thumbnail item-start>
46-
<img [src]="site.imageurl" *ngIf="site.imageurl" onError="this.src='assets/icon/icon.png'">
47-
<img src="assets/icon/icon.png" *ngIf="!site.imageurl" class="core-login-default-icon">
48-
</ion-thumbnail>
49-
<h2 text-wrap>{{site.name}}<ng-container *ngIf="site.alias"> ({{site.alias}})</ng-container></h2>
50-
<p>{{site.noProtocolUrl}}</p>
51-
<p *ngIf="site.country || site.city" text-wrap><ng-container *ngIf="site.city">{{site.city}} - </ng-container>{{site.country}}</p>
52-
</button>
53-
</div>
54-
</ion-list>
55-
56-
<div *ngIf="!hasSites && loadingSites" class="core-login-site-nolist-loading"><ion-spinner></ion-spinner></div>
57-
</ng-container>
55+
<div *ngIf="!hasSites && loadingSites" class="core-login-site-nolist-loading"><ion-spinner></ion-spinner></div>
5856
</ng-container>
5957

60-
<!-- Pick the site from a list of fixed sites. -->
61-
<ion-item *ngIf="fixedSites && siteSelector == 'select'" margin-vertical text-wrap>
62-
<ion-label stacked for="siteSelect">{{ 'core.login.selectsite' | translate }}</ion-label>
63-
<ion-select formControlName="siteUrl" name="url" placeholder="{{ 'core.login.siteaddress' | translate }}" interface="action-sheet">
64-
<ion-option *ngFor="let site of fixedSites" [value]="site.url">{{site.name}}</ion-option>
65-
</ion-select>
66-
</ion-item>
67-
68-
<ion-item *ngIf="(fixedSites && siteSelector == 'select') || (!fixedSites && siteSelector == 'url')" no-lines>
58+
<ion-item *ngIf="siteSelector == 'url'" no-lines>
6959
<button ion-button block [disabled]="!siteForm.valid" text-wrap>{{ 'core.login.connect' | translate }}</button>
7060
</ion-item>
7161
</form>
7262

7363
<ng-container *ngIf="fixedSites">
7464
<!-- Pick the site from a list of fixed sites. -->
75-
<ion-list *ngIf="siteSelector == 'list' || siteSelector == 'listnourl'">
65+
<ion-list *ngIf="siteSelector == 'list'">
7666
<ion-item no-lines><h2 class="item-heading">{{ 'core.login.selectsite' | translate }}</h2></ion-item>
7767
<ion-searchbar *ngIf="fixedSites.length > 4" [(ngModel)]="filter" (ionInput)="filterChanged($event)" (ionCancel)="filterChanged()" [placeholder]="'core.login.findyoursite' | translate"></ion-searchbar>
78-
<ion-item *ngFor="let site of filteredSites" (click)="connect($event, site.url)" [title]="site.name" detail-push text-wrap>
79-
<h2>{{site.name}}</h2>
80-
<p *ngIf="siteSelector == 'list'">{{site.url}}</p>
68+
<ion-item *ngFor="let site of filteredSites" (click)="connect($event, site.url)" [title]="site.name" detail-push>
69+
<ion-thumbnail item-start *ngIf="siteFinderSettings.displayimage">
70+
<img [src]="site.imageurl" *ngIf="site.imageurl" onError="this.src='assets/icon/icon.png'">
71+
<img src="assets/icon/icon.png" *ngIf="!site.imageurl" class="core-login-default-icon">
72+
</ion-thumbnail>
73+
<h2 *ngIf="site.title" text-wrap>{{site.title}}</h2>
74+
<p *ngIf="site.noProtocolUrl">{{site.noProtocolUrl}}</p>
75+
<p *ngIf="site.location">{{site.location}}</p>
8176
</ion-item>
8277
</ion-list>
8378

8479
<!-- Display them using buttons. -->
8580
<div *ngIf="siteSelector == 'buttons'">
8681
<p class="padding no-padding-bottom">{{ 'core.login.selectsite' | translate }}</p>
87-
<a *ngFor="let site of fixedSites" ion-button block (click)="connect($event, site.url)" [title]="site.name" margin-bottom>{{site.name}}</a>
82+
<a *ngFor="let site of fixedSites" text-wrap ion-button block (click)="connect($event, site.url)" [title]="site.name" margin-bottom>{{site.title}}</a>
8883
</div>
8984
</ng-container>
9085

src/core/login/pages/site/site.ts

Lines changed: 73 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,17 @@ import { TranslateService } from '@ngx-translate/core';
3535
*/
3636
type CoreLoginSiteInfoExtended = CoreLoginSiteInfo & {
3737
noProtocolUrl?: string; // Url wihtout protocol.
38-
country?: string; // Based on countrycode.
38+
location?: string; // City + country.
39+
title?: string; // Name + alias.
40+
};
41+
42+
type SiteFinderSettings = {
43+
displayalias: boolean,
44+
displaycity: boolean,
45+
displaycountry: boolean,
46+
displayimage: boolean,
47+
displaysitename: boolean,
48+
displayurl: boolean
3949
};
4050

4151
/**
@@ -51,8 +61,8 @@ export class CoreLoginSitePage {
5161
@ViewChild('siteFormEl') formElement: ElementRef;
5262

5363
siteForm: FormGroup;
54-
fixedSites: CoreLoginSiteInfo[];
55-
filteredSites: CoreLoginSiteInfo[];
64+
fixedSites: CoreLoginSiteInfoExtended[];
65+
filteredSites: CoreLoginSiteInfoExtended[];
5666
siteSelector = 'sitefinder';
5767
showKeyboard = false;
5868
filter = '';
@@ -62,6 +72,7 @@ export class CoreLoginSitePage {
6272
searchFnc: Function;
6373
showScanQR: boolean;
6474
enteredSiteUrl: CoreLoginSiteInfoExtended;
75+
siteFinderSettings: SiteFinderSettings;
6576

6677
constructor(navParams: NavParams,
6778
protected navCtrl: NavController,
@@ -84,13 +95,37 @@ export class CoreLoginSitePage {
8495
let url = '';
8596
this.siteSelector = CoreConfigConstants.multisitesdisplay;
8697

98+
const siteFinderSettings: Partial<SiteFinderSettings> = CoreConfigConstants['sitefindersettings'] || {};
99+
this.siteFinderSettings = {
100+
displaysitename: true,
101+
displayimage: true,
102+
displayalias: true,
103+
displaycity: true,
104+
displaycountry: true,
105+
displayurl: true,
106+
...siteFinderSettings
107+
};
108+
87109
// Load fixed sites if they're set.
88110
if (this.loginHelper.hasSeveralFixedSites()) {
89-
this.fixedSites = <any[]> this.loginHelper.getFixedSites();
111+
// Deprecate listnourl on 3.9.3, remove this block on the following release.
112+
if (this.siteSelector == 'listnourl') {
113+
this.siteSelector = 'list';
114+
this.siteFinderSettings.displayurl = false;
115+
}
116+
117+
this.fixedSites = this.extendCoreLoginSiteInfo(<CoreLoginSiteInfoExtended[]> this.loginHelper.getFixedSites());
118+
119+
// Do not show images if none are set.
120+
if (!this.fixedSites.some((site) => !!site.imageurl)) {
121+
this.siteFinderSettings.displayimage = false;
122+
}
123+
90124
// Autoselect if not defined.
91-
if (['list', 'listnourl', 'select', 'buttons'].indexOf(this.siteSelector) < 0) {
92-
this.siteSelector = this.fixedSites.length > 8 ? 'list' : (this.fixedSites.length > 3 ? 'select' : 'buttons');
125+
if (this.siteSelector != 'list' && this.siteSelector != 'buttons') {
126+
this.siteSelector = this.fixedSites.length > 3 ? 'list' : 'buttons';
93127
}
128+
94129
this.filteredSites = this.fixedSites;
95130
url = this.fixedSites[0].url;
96131
} else if (CoreConfigConstants.enableonboarding && !this.appProvider.isIOS() && !this.appProvider.isMac()) {
@@ -116,11 +151,8 @@ export class CoreLoginSitePage {
116151
// Update the sites list.
117152
this.sites = await this.sitesProvider.findSites(search);
118153

119-
// UI tweaks.
120-
this.sites.forEach((site) => {
121-
site.noProtocolUrl = CoreUrl.removeProtocol(site.url);
122-
site.country = this.utils.getCountryName(site.countrycode);
123-
});
154+
// Add UI tweaks.
155+
this.sites = this.extendCoreLoginSiteInfo(this.sites);
124156

125157
this.hasSites = !!this.sites.length;
126158
} else {
@@ -132,6 +164,34 @@ export class CoreLoginSitePage {
132164
}, 1000);
133165
}
134166

167+
/**
168+
* Extend info of Login Site Info to get UI tweaks.
169+
*
170+
* @param sites Sites list.
171+
* @return Sites list with extended info.
172+
*/
173+
protected extendCoreLoginSiteInfo(sites: CoreLoginSiteInfoExtended[]): CoreLoginSiteInfoExtended[] {
174+
return sites.map((site) => {
175+
site.noProtocolUrl = this.siteFinderSettings.displayurl && site.url ? CoreUrl.removeProtocol(site.url) : '';
176+
177+
const name = this.siteFinderSettings.displaysitename ? site.name : '';
178+
const alias = this.siteFinderSettings.displayalias && site.alias ? site.alias : '';
179+
180+
// Set title with parenthesis if both name and alias are present.
181+
site.title = name && alias ? name + ' (' + alias + ')' : name + alias;
182+
183+
const country = this.siteFinderSettings.displaycountry && site.countrycode ?
184+
this.utils.getCountryName(site.countrycode) : '';
185+
const city = this.siteFinderSettings.displaycity && site.city ?
186+
site.city : '';
187+
188+
// Separate location with hiphen if both country and city are present.
189+
site.location = city && country ? city + ' - ' + country : city + country;
190+
191+
return site;
192+
});
193+
}
194+
135195
/**
136196
* Try to connect to a site.
137197
*
@@ -224,7 +284,8 @@ export class CoreLoginSitePage {
224284
this.filteredSites = this.fixedSites;
225285
} else {
226286
this.filteredSites = this.fixedSites.filter((site) => {
227-
return site.name.toLowerCase().indexOf(newValue) > -1 || site.url.toLowerCase().indexOf(newValue) > -1;
287+
return site.title.toLowerCase().indexOf(newValue) > -1 || site.noProtocolUrl.toLowerCase().indexOf(newValue) > -1 ||
288+
site.location.toLowerCase().indexOf(newValue) > -1;
228289
});
229290
}
230291
}

src/core/login/providers/helper.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { CoreConfigProvider } from '@providers/config';
2121
import { CoreEventsProvider } from '@providers/events';
2222
import { CoreInitDelegate } from '@providers/init';
2323
import { CoreLoggerProvider } from '@providers/logger';
24-
import { CoreSitesProvider } from '@providers/sites';
24+
import { CoreSitesProvider, CoreLoginSiteInfo } from '@providers/sites';
2525
import { CoreWSProvider } from '@providers/ws';
2626
import { CoreDomUtilsProvider } from '@providers/utils/dom';
2727
import { CoreTextUtilsProvider } from '@providers/utils/text';
@@ -464,7 +464,7 @@ export class CoreLoginHelperProvider {
464464
*
465465
* @return Fixed site or list of fixed sites.
466466
*/
467-
getFixedSites(): string | any[] {
467+
getFixedSites(): string | CoreLoginSiteInfo[] {
468468
return CoreConfigConstants.siteurl;
469469
}
470470

0 commit comments

Comments
 (0)