Skip to content

Commit 24a4ac0

Browse files
authored
Merge branch 'master' into nivogt/people-picker-bugs
2 parents 0244d93 + 4ab79c8 commit 24a4ac0

File tree

8 files changed

+174
-32
lines changed

8 files changed

+174
-32
lines changed
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
<html>
2+
<head>
3+
<script type="module" src="../../dist/es6/index.js"></script>
4+
</head>
5+
<body>
6+
<mgt-msal-provider client-id="a974dfa0-9f57-49b9-95db-90f04ce2111a"></mgt-msal-provider>
7+
<mgt-login></mgt-login>
8+
9+
<mgt-get resource="/me/messages" version="beta" scopes="mail.read" max-pages="2">
10+
<template data-type="value">
11+
<div class="email">
12+
<h4>
13+
<mgt-person person-query="[[sender.emailAddress.address]]" view="oneline"></mgt-person>
14+
</h4>
15+
<h3>
16+
[[ subject ]]
17+
</h3>
18+
<div
19+
data-if="bodyPreview"
20+
class="preview"
21+
data-props="[[innerHTML: body.content, @click: toggleExpand]]"
22+
></div>
23+
<div data-else class="preview">
24+
email body is empty
25+
</div>
26+
</div>
27+
</template>
28+
<template data-type="loading">
29+
loading
30+
</template>
31+
<template data-type="error">
32+
[[ this ]]
33+
</template>
34+
</mgt-get>
35+
36+
<style>
37+
.email {
38+
box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
39+
padding: 10px;
40+
margin: 8px 4px;
41+
font-family: Segoe UI, Frutiger, Frutiger Linotype, Dejavu Sans, Helvetica Neue, Arial, sans-serif;
42+
}
43+
44+
.email:hover {
45+
box-shadow: 0 3px 14px rgba(0, 0, 0, 0.3);
46+
padding: 10px;
47+
margin: 8px 4px;
48+
}
49+
50+
.email h3 {
51+
font-size: 12px;
52+
margin-top: 4px;
53+
}
54+
55+
.email h4 {
56+
font-size: 10px;
57+
margin-top: 0px;
58+
margin-bottom: 0px;
59+
}
60+
61+
.email mgt-person {
62+
--font-size: 10px;
63+
--avatar-size-s: 12px;
64+
}
65+
66+
.email .preview {
67+
font-size: 13px;
68+
text-overflow: ellipsis;
69+
word-wrap: break-word;
70+
overflow: hidden;
71+
max-height: 2.8em;
72+
line-height: 1.4em;
73+
}
74+
75+
.expanded .email .preview {
76+
max-height: unset;
77+
}
78+
</style>
79+
80+
<script type="module">
81+
import { TemplateHelper } from '../../dist/es6/index.js';
82+
83+
TemplateHelper.setBindingSyntax('[[', ']]');
84+
85+
TemplateHelper.globalContext.toggleExpand = (e, context, root) => {
86+
root.classList.toggle('expanded');
87+
};
88+
</script>
89+
</body>
90+
</html>

src/components/mgt-person-card/mgt-person-card.scss

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ $person-card-background-color: var(--person-card-background-color, #ffffff);
4040
display: grid;
4141
position: relative;
4242
overflow: hidden;
43-
text-overflow: ellipse;
43+
text-overflow: ellipsis;
4444
white-space: nowrap;
4545
background-color: transparent;
4646
width: 100%;
@@ -54,12 +54,12 @@ $person-card-background-color: var(--person-card-background-color, #ffffff);
5454
height: 100%;
5555
top: 0;
5656
right: 0;
57-
background: linear-gradient(left, transparent, transparent 80%, $person-card-background-color);
58-
background: -moz-linear-gradient(left, transparent, transparent 80%, $person-card-background-color);
59-
background: -o-linear-gradient(left, transparent, transparent 80%, $person-card-background-color);
60-
background: -ms-linear-gradient(left, transparent, transparent 80%, $person-card-background-color);
61-
background: -webkit-linear-gradient(left, transparent, transparent 80%, $person-card-background-color);
62-
}
57+
background-image: linear-gradient(to right, rgba(255,255,255,0) 0%,rgba(255,255,255,0) 80%,$person-card-background-color 100%);
58+
background-image: -moz-linear-gradient(left, rgba(255,255,255,0) 0%,rgba(255,255,255,0) 80%,$person-card-background-color 100%);
59+
background-image: -o-linear-gradient(left, rgba(255,255,255,0) 0%,rgba(255,255,255,0) 80%,$person-card-background-color 100%);
60+
background-image: -ms-linear-gradient(left right, rgba(255,255,255,0) 0%,rgba(255,255,255,0) 80%,$person-card-background-color 100%);
61+
background-image: -webkit-linear-gradient(left, rgba(255,255,255,0) 0%,rgba(255,255,255,0) 80%,$person-card-background-color 100%);
62+
}
6363
}
6464

6565
.job-title {

src/components/mgt-person/mgt-person.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ export class MgtPerson extends MgtTemplatedComponent {
192192
return;
193193
}
194194

195+
this._isInvalidImageSrc = !!value;
195196
const oldValue = this._personImage;
196197
this._personImage = value;
197198
this.requestUpdate('personImage', oldValue);
@@ -307,9 +308,10 @@ export class MgtPerson extends MgtTemplatedComponent {
307308
})
308309
public view: PersonViewType;
309310

310-
@internalProperty() private _personCardShouldRender: boolean;
311-
@internalProperty() private _fetchedPresence: MicrosoftGraphBeta.Presence;
312311
@internalProperty() private _fetchedImage: string;
312+
@internalProperty() private _fetchedPresence: MicrosoftGraphBeta.Presence;
313+
@internalProperty() private _isInvalidImageSrc: boolean;
314+
@internalProperty() private _personCardShouldRender: boolean;
313315

314316
private _personDetails: IDynamicPerson;
315317
private _personAvatarBg: string;
@@ -328,6 +330,7 @@ export class MgtPerson extends MgtTemplatedComponent {
328330
this.line2Property = 'email';
329331
this.view = PersonViewType.avatar;
330332
this.avatarSize = 'auto';
333+
this._isInvalidImageSrc = false;
331334
}
332335

333336
/**
@@ -452,11 +455,13 @@ export class MgtPerson extends MgtTemplatedComponent {
452455
*/
453456
protected renderImage(personDetails: IDynamicPerson, imageSrc: string) {
454457
const title =
455-
personDetails && this.personCardInteraction === PersonCardInteraction.none ? personDetails.displayName : '';
458+
personDetails && this.personCardInteraction === PersonCardInteraction.none
459+
? personDetails.displayName || getEmailFromGraphEntity(personDetails) || ''
460+
: '';
456461

457-
if (imageSrc) {
462+
if (imageSrc && !this._isInvalidImageSrc) {
458463
return html`
459-
<img alt=${title} src=${imageSrc} />
464+
<img alt=${title} src=${imageSrc} @error=${() => (this._isInvalidImageSrc = true)} />
460465
`;
461466
} else if (personDetails) {
462467
const initials = this.getInitials(personDetails);
@@ -596,12 +601,12 @@ export class MgtPerson extends MgtTemplatedComponent {
596601
: '';
597602

598603
const imageClasses = {
599-
initials: !image,
604+
initials: !image || this._isInvalidImageSrc,
600605
small: !this.isLargeAvatar(),
601606
'user-avatar': true
602607
};
603608

604-
if (!image && this.personDetails) {
609+
if ((!image || this._isInvalidImageSrc) && this.personDetails) {
605610
// add avatar background color
606611
imageClasses[this._personAvatarBg] = true;
607612
}

src/components/mgt-teams-channel-picker/mgt-teams-channel-picker.scss

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,10 +120,9 @@ $dropdown-item-selected-background: var(--dropdown-item-selected-background, #de
120120
.close-icon {
121121
display: inline-block;
122122
position: absolute;
123-
right: 0;
123+
right: 10px;
124124
line-height: normal;
125125
font-family: 'FabricMDL2Icons';
126-
padding: 8px 10px 10px 8px;
127126
margin-bottom: 1px;
128127
cursor: pointer;
129128
color: $placeholder-default-color;

src/components/mgt-teams-channel-picker/mgt-teams-channel-picker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -551,7 +551,7 @@ export class MgtTeamsChannelPicker extends MgtTemplatedComponent {
551551
const batch = provider.graph.createBatch();
552552

553553
for (const [i, team] of teams.entries()) {
554-
batch.get(`${i}`, `teams/${team.id}/channels`, ['user.read.all']);
554+
batch.get(`${i}`, `teams/${team.id}/channels`, ['group.read.all']);
555555
}
556556
const response = await batch.execute();
557557
this.items = teams.map(t => {

src/components/templateHelper.ts

Lines changed: 60 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,53 @@ export class TemplateHelper {
6060
}
6161
}
6262

63-
private static _expression = /{{+\s*[$\w\.()\[\]]+\s*}}+/g;
63+
/**
64+
* Set an alternative binding syntax. Default is {{ <value> }}
65+
*
66+
* @static
67+
* @param {string} startStr start of binding syntax
68+
* @param {string} endStr end of binding syntax
69+
* @memberof TemplateHelper
70+
*/
71+
public static setBindingSyntax(startStr: string, endStr: string) {
72+
this._startExpression = startStr;
73+
this._endExpression = endStr;
74+
75+
const start = this.escapeRegex(this._startExpression);
76+
const end = this.escapeRegex(this._endExpression);
77+
78+
this._expression = new RegExp(`${start}\\s*\([$\\w\\.()\\[\\]]+\)\\s*${end}`, 'g');
79+
}
80+
81+
/**
82+
* Global context containing data or functions available to
83+
* all templates for binding
84+
*
85+
* @readonly
86+
* @static
87+
* @memberof TemplateHelper
88+
*/
89+
public static get globalContext() {
90+
return this._globalContext;
91+
}
92+
93+
private static _globalContext = {};
94+
95+
private static get expression() {
96+
if (!this._expression) {
97+
this.setBindingSyntax('{{', '}}');
98+
}
99+
100+
return this._expression;
101+
}
102+
103+
private static _startExpression: string;
104+
private static _endExpression: string;
105+
private static _expression: RegExp;
106+
107+
private static escapeRegex(string) {
108+
return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
109+
}
64110

65111
// simple implementation of deep cloneNode
66112
// required for nested templates in polyfilled browsers
@@ -83,8 +129,8 @@ export class TemplateHelper {
83129
}
84130

85131
private static expandExpressionsAsString(str: string, context: object, additionalContext: object) {
86-
return str.replace(this._expression, match => {
87-
const value = this.evalInContext(this.trimExpression(match), { ...context, ...additionalContext });
132+
return str.replace(this.expression, (match, p1) => {
133+
const value = this.evalInContext(p1 || this.trimExpression(match), { ...context, ...additionalContext });
88134
if (value) {
89135
if (typeof value === 'object') {
90136
return JSON.stringify(value);
@@ -238,10 +284,12 @@ export class TemplateHelper {
238284
}
239285

240286
private static evalBoolInContext(expression, context) {
287+
context = { ...context, ...this.globalContext };
241288
return new Function('with(this) { return !!(' + expression + ')}').call(context);
242289
}
243290

244291
private static evalInContext(expression, context) {
292+
context = { ...context, ...this.globalContext };
245293
const func = new Function('with(this) { return ' + expression + ';}');
246294
let result;
247295
try {
@@ -252,17 +300,16 @@ export class TemplateHelper {
252300
}
253301

254302
private static trimExpression(expression: string) {
255-
let start = 0;
256-
let end = expression.length - 1;
257-
258-
while (expression[start] === '{' && start < end) {
259-
start++;
260-
}
261-
262-
while (expression[end] === '}' && start <= end) {
263-
end--;
303+
expression = expression.trim();
304+
305+
if (expression.startsWith(this._startExpression) && expression.endsWith(this._endExpression)) {
306+
expression = expression.substr(
307+
this._startExpression.length,
308+
expression.length - this._startExpression.length - this._endExpression.length
309+
);
310+
expression = expression.trim();
264311
}
265312

266-
return expression.substring(start, end + 1).trim();
313+
return expression;
267314
}
268315
}

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ export * from './providers/providers';
1212
export * from './graph/types';
1313
export { TeamsHelper } from './utils/TeamsHelper';
1414
export { prepScopes } from './utils/GraphHelpers';
15+
export { TemplateHelper } from './components/templateHelper';

stories/components/login.stories.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ export const Templates = () => html`
3636
</template>
3737
<template data-type="flyout-commands">
3838
<div>
39-
<button data-props="{@click: handleSignOut}">Sign Out</button>
39+
<button data-props="@click: handleSignOut">Sign Out</button>
4040
<button>Go to my profile</button>
4141
</div>
4242
</template>
4343
</mgt-login>
44-
`;
44+
`;

0 commit comments

Comments
 (0)