Skip to content

Commit d15d356

Browse files
committed
Locale strings + TermSet selection (#64)
1 parent 6461e31 commit d15d356

File tree

9 files changed

+151
-56
lines changed

9 files changed

+151
-56
lines changed

src/controls/taxonomyPicker/ITaxonomyPicker.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ export interface ITaxonomyPickerProps {
3535
* Id of a child term in the termset where to be able to selected and search the terms from
3636
*/
3737
ancoreId?: string;
38+
/**
39+
* Specify if the term set itself is selectable in the tree view
40+
*/
41+
isTermSetSelectable?: boolean;
3842
/**
3943
* Whether the property pane field is enabled or not.
4044
*/
@@ -80,9 +84,12 @@ export interface ITermChanges {
8084

8185
export interface ITermParentProps extends ITermChanges {
8286
termset: ITermSet;
83-
autoExpand: () => void;
8487
multiSelection: boolean;
8588
anchorId? : string;
89+
isTermSetSelectable?: boolean;
90+
91+
autoExpand: () => void;
92+
termSetSelectedChange?: (termSet: ITermSet, isChecked: boolean) => void;
8693
}
8794

8895
export interface ITermParentState {

src/controls/taxonomyPicker/TaxonomyPicker.module.scss

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,17 @@
3434
margin-left: 15px;
3535
}
3636

37+
.termSetSelectable {
38+
height: 50px;
39+
line-height: 50px;
40+
}
41+
42+
.termSetSelector {
43+
display: inline-block;
44+
margin: 0 8px 0 4px;
45+
vertical-align: middle;
46+
}
47+
3748
.term {
3849
padding-left: 20px;
3950

@@ -72,8 +83,8 @@
7283
width: 100%;
7384
text-align: left;
7485
cursor: pointer;
75-
76-
86+
87+
7788
.termSuggestionSubTitle
7889
{
7990
font-size: 12px;
@@ -129,7 +140,7 @@
129140
display: flex;
130141
align-items: center;
131142
}
132-
143+
133144
.errorIcon {
134145
font-size: 14px;
135146
margin-right: 5px;

src/controls/taxonomyPicker/TaxonomyPicker.tsx

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import * as React from 'react';
22
import { IWebPartContext } from '@microsoft/sp-webpart-base';
3-
import { Async } from 'office-ui-fabric-react/lib/Utilities';
43
import { PrimaryButton, DefaultButton, IconButton, IButtonProps } from 'office-ui-fabric-react/lib/Button';
54
import { Panel, PanelType } from 'office-ui-fabric-react/lib/Panel';
65
import { Spinner, SpinnerType } from 'office-ui-fabric-react/lib/Spinner';
@@ -32,7 +31,6 @@ export const TERM_IMG = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQC
3231
* Renders the controls for PropertyFieldTermPicker component
3332
*/
3433
export class TaxonomyPicker extends React.Component<ITaxonomyPickerProps, ITaxonomyPickerState> {
35-
private async: Async;
3634
private delayedValidate: (value: IPickerTerms) => void;
3735
private termsService: SPTermStorePickerService;
3836
private previousValues: IPickerTerms = [];
@@ -58,7 +56,6 @@ export class TaxonomyPicker extends React.Component<ITaxonomyPickerProps, ITaxon
5856
this.onClosePanel = this.onClosePanel.bind(this);
5957
this.onSave = this.onSave.bind(this);
6058
this.termsChanged = this.termsChanged.bind(this);
61-
this.async = new Async(this);
6259
this.termsFromPickerChanged = this.termsFromPickerChanged.bind(this);
6360
}
6461

@@ -202,12 +199,29 @@ export class TaxonomyPicker extends React.Component<ITaxonomyPickerProps, ITaxon
202199
}
203200

204201
/**
205-
* Called when the component will unmount
202+
* TermSet selection handler
203+
* @param termSet
204+
* @param isChecked
206205
*/
207-
public componentWillUnmount() {
208-
if (typeof this.async !== 'undefined') {
209-
this.async.dispose();
210-
}
206+
private termSetSelectedChange = (termSet: ITermSet, isChecked: boolean) => {
207+
const ts: ITermSet = {...termSet};
208+
// Clean /Guid.../ from the ID
209+
ts.Id = this.termsService.cleanGuid(ts.Id);
210+
// Create a term for the termset
211+
const term: ITerm = {
212+
Name: ts.Name,
213+
Id: ts.Id,
214+
TermSet: ts,
215+
PathOfTerm: "",
216+
_ObjectType_: ts._ObjectType_,
217+
_ObjectIdentity_: ts._ObjectIdentity_,
218+
Description: ts.Description,
219+
IsDeprecated: null,
220+
IsRoot: null
221+
};
222+
223+
// Trigger the normal change event
224+
this.termsChanged(term, isChecked);
211225
}
212226

213227
/**
@@ -227,6 +241,7 @@ export class TaxonomyPicker extends React.Component<ITaxonomyPickerProps, ITaxon
227241
termPickerHostProps={this.props}
228242
disabled={this.props.disabled}
229243
value={this.state.activeNodes}
244+
isTermSetSelectable={this.props.isTermSetSelectable}
230245
onChanged={this.termsFromPickerChanged}
231246
allowMultipleSelections={this.props.allowMultipleSelections}
232247
/>
@@ -268,6 +283,8 @@ export class TaxonomyPicker extends React.Component<ITaxonomyPickerProps, ITaxon
268283
<TermParent anchorId={this.props.ancoreId}
269284
autoExpand={null}
270285
termset={this.state.termSetAndTerms}
286+
isTermSetSelectable={this.props.isTermSetSelectable}
287+
termSetSelectedChange={this.termSetSelectedChange}
271288
activeNodes={this.state.activeNodes}
272289
changedCallback={this.termsChanged}
273290
multiSelection={this.props.allowMultipleSelections} />

src/controls/taxonomyPicker/TermParent.tsx

Lines changed: 41 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import { EXPANDED_IMG, COLLAPSED_IMG, TERMSET_IMG, TERM_IMG } from './TaxonomyPi
66
import Term from './Term';
77

88
import styles from './TaxonomyPicker.module.scss';
9+
import { Checkbox } from 'office-ui-fabric-react';
10+
import * as strings from 'ControlStrings';
911

1012
/**
1113
* Term Parent component, represents termset or term if anchorId
@@ -17,6 +19,7 @@ export default class TermParent extends React.Component<ITermParentProps, ITermP
1719

1820
constructor(props: ITermParentProps) {
1921
super(props);
22+
2023
this._terms = this.props.termset.Terms;
2124
this.state = {
2225
loaded: true,
@@ -25,19 +28,7 @@ export default class TermParent extends React.Component<ITermParentProps, ITermP
2528
this._handleClick = this._handleClick.bind(this);
2629
}
2730

28-
29-
3031
/**
31-
* Handle the click event: collapse or expand
32-
*/
33-
private _handleClick() {
34-
this.setState({
35-
expanded: !this.state.expanded
36-
});
37-
}
38-
39-
40-
/**
4132
* componentWillMount
4233
*/
4334
public componentWillMount()
@@ -51,10 +42,10 @@ export default class TermParent extends React.Component<ITermParentProps, ITermP
5142
const anchorDepth = anchorTerm.PathDepth;
5243
this._anchorName = anchorTerm.Name;
5344
var anchorTerms : ITerm[] = this._terms.filter(t => t.PathOfTerm.substring(0, anchorTerm.PathOfTerm.length) === anchorTerm.PathOfTerm && t.Id !== anchorTerm.Id);
54-
45+
5546
anchorTerms = anchorTerms.map(term => {
5647
term.PathDepth = term.PathDepth - anchorTerm.PathDepth;
57-
48+
5849
return term;
5950
});
6051

@@ -64,6 +55,24 @@ export default class TermParent extends React.Component<ITermParentProps, ITermP
6455
}
6556

6657

58+
/**
59+
* Handle the click event: collapse or expand
60+
*/
61+
private _handleClick() {
62+
this.setState({
63+
expanded: !this.state.expanded
64+
});
65+
}
66+
67+
68+
/**
69+
* The term set selection changed
70+
*/
71+
private termSetSelectionChange = (ev: React.FormEvent<HTMLElement>, isChecked: boolean): void => {
72+
this.props.termSetSelectedChange(this.props.termset, isChecked);
73+
}
74+
75+
6776
public render(): JSX.Element {
6877
// Specify the inline styling to show or hide the termsets
6978
const styleProps: React.CSSProperties = {
@@ -72,7 +81,7 @@ export default class TermParent extends React.Component<ITermParentProps, ITermP
7281

7382
let termElm: JSX.Element = <div />;
7483
// Check if the terms have been loaded
75-
84+
7685
if (this.state.loaded) {
7786
if (this._terms.length > 0) {
7887
termElm = (
@@ -85,18 +94,30 @@ export default class TermParent extends React.Component<ITermParentProps, ITermP
8594
</div>
8695
);
8796
} else {
88-
termElm = <div className={`${styles.listItem} ${styles.term}`}>Term set does not contain any terms</div>;
97+
termElm = <div className={`${styles.listItem} ${styles.term}`}>{strings.TaxonomyPickerNoTerms}</div>;
8998
}
9099
} else {
91100
termElm = <Spinner type={SpinnerType.normal} />;
92101
}
93-
102+
94103

95104
return (
96105
<div>
97-
<div className={`${styles.listItem} ${styles.termset}`} onClick={this._handleClick}>
98-
<img src={this.state.expanded ? EXPANDED_IMG : COLLAPSED_IMG} alt='Expand This Term Set' title='Expand This Term Set' />
99-
<img src={this.props.anchorId ? TERM_IMG : TERMSET_IMG} title='Menu for Term Set' alt='Menu for Term Set' /> {this.props.anchorId ? this._anchorName : this.props.termset.Name}
106+
<div className={`${styles.listItem} ${styles.termset} ${(!this.props.anchorId && this.props.isTermSetSelectable) ? styles.termSetSelectable : ""}`} onClick={this._handleClick}>
107+
<img src={this.state.expanded ? EXPANDED_IMG : COLLAPSED_IMG} alt={strings.TaxonomyPickerExpandTitle} title={strings.TaxonomyPickerExpandTitle} />
108+
{
109+
// Show the termset selection box
110+
(!this.props.anchorId && this.props.isTermSetSelectable) &&
111+
<Checkbox className={styles.termSetSelector}
112+
checked={this.props.activeNodes.filter(a => a.path === "" && a.key === a.termSet).length >= 1}
113+
onChange={this.termSetSelectionChange} />
114+
}
115+
<img src={this.props.anchorId ? TERM_IMG : TERMSET_IMG} alt={strings.TaxonomyPickerMenuTermSet} title={strings.TaxonomyPickerMenuTermSet} />
116+
{
117+
this.props.anchorId ?
118+
this._anchorName :
119+
this.props.termset.Name
120+
}
100121
</div>
101122
<div style={styleProps}>
102123
{termElm}

src/controls/taxonomyPicker/TermPicker.tsx

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import SPTermStorePickerService from './../../services/SPTermStorePickerService'
55
import styles from './TaxonomyPicker.module.scss';
66
import { ITaxonomyPickerProps } from './ITaxonomyPicker';
77
import { IWebPartContext } from '@microsoft/sp-webpart-base';
8+
import * as strings from 'ControlStrings';
89

910
export class TermBasePicker extends BasePicker<IPickerTerm, IBasePickerProps<IPickerTerm>>
1011
{
@@ -20,8 +21,9 @@ export interface ITermPickerProps {
2021
context: IWebPartContext;
2122
disabled: boolean;
2223
value: IPickerTerms;
23-
onChanged: (items: IPickerTerm[]) => void;
2424
allowMultipleSelections : boolean;
25+
isTermSetSelectable?: boolean;
26+
onChanged: (items: IPickerTerm[]) => void;
2527
}
2628

2729
export default class TermPicker extends React.Component<ITermPickerProps, ITermPickerState> {
@@ -91,7 +93,7 @@ export default class TermPicker extends React.Component<ITermPickerProps, ITermP
9193
return (
9294
<div className={styles.termSuggestion} title={termTitle}>
9395
<div>{term.name}</div>
94-
<div className={styles.termSuggestionSubTitle}> in {termParent}</div>
96+
<div className={styles.termSuggestionSubTitle}> {strings.TaxonomyPickerInLabel} {termParent ? termParent : strings.TaxonomyPickerTermSetLabel}</div>
9597
</div>
9698
);
9799
}
@@ -102,7 +104,22 @@ export default class TermPicker extends React.Component<ITermPickerProps, ITermP
102104
private async onFilterChanged(filterText: string, tagList: IPickerTerm[]): Promise<IPickerTerm[]> {
103105
if (filterText !== "") {
104106
let termsService = new SPTermStorePickerService(this.props.termPickerHostProps, this.props.context);
105-
let terms = await termsService.searchTermsByName(filterText);
107+
let terms: IPickerTerm[] = await termsService.searchTermsByName(filterText);
108+
// Check if the termset can be selected
109+
if (this.props.isTermSetSelectable) {
110+
// Retrieve the current termset
111+
const termSet = await termsService.getTermSet();
112+
// Check if termset was retrieved and if it contains the filter value
113+
if (termSet && termSet.Name.toLowerCase().indexOf(filterText.toLowerCase()) === 0) {
114+
// Add the termset to the suggestion list
115+
terms.push({
116+
key: termsService.cleanGuid(termSet.Id),
117+
name: termSet.Name,
118+
path: "",
119+
termSet: termsService.cleanGuid(termSet.Id)
120+
});
121+
}
122+
}
106123
// Filter out the terms which are already set
107124
const filteredTerms = [];
108125
for (const term of terms) {

src/loc/en-us.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ define([], () => {
3838
"SendEmailTo": "Send an email to {0}",
3939
"StartChatWith": "Start a chat with {0}",
4040
"Contact": "Contact",
41-
"UpdateProfile": "Update your profile"
41+
"UpdateProfile": "Update your profile",
42+
43+
"TaxonomyPickerNoTerms": "Term set does not contain any terms",
44+
"TaxonomyPickerExpandTitle": "Expand This Term Set",
45+
"TaxonomyPickerMenuTermSet": "Menu for Term Set",
46+
"TaxonomyPickerInLabel": "in",
47+
"TaxonomyPickerTermSetLabel": "Term Set"
4248
};
4349
});

src/loc/mystrings.d.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@ declare interface IControlStrings {
88
StartChatWith: string;
99
Contact: string;
1010
UpdateProfile: string;
11+
12+
// Taxonomy picker
13+
TaxonomyPickerNoTerms: string;
14+
TaxonomyPickerExpandTitle: string;
15+
TaxonomyPickerMenuTermSet: string;
16+
TaxonomyPickerInLabel: string;
17+
TaxonomyPickerTermSetLabel: string;
1118
}
1219

1320
declare module 'ControlStrings' {

0 commit comments

Comments
 (0)