Update MegaMenu Application Customizer: Version bump to 1.1.0, localization support added, and unnecessary files removed
- Deleted obsolete localization file for English (en-us). - Updated version number from 1.0.4 to 1.1.0 in manifests.js and manifests.json. - Added localization support for German (de-de) in a new localization file. - Removed unnecessary dependencies from manifests. - Added .gitignore to exclude build artifacts and temporary files.
This commit is contained in:
@@ -12,6 +12,18 @@ import { ApplicationCustomizerContext } from '@microsoft/sp-application-base';
|
||||
import { debugError } from './MegaMenuDebug';
|
||||
|
||||
const EmptyGuid: string = '00000000-0000-0000-0000-000000000000';
|
||||
const TermCachePrefix: string = 'MegaMenu:TermSet:';
|
||||
const PickerCachePrefix: string = 'MegaMenu:PickerTerms:';
|
||||
|
||||
interface ITermCacheEntry {
|
||||
expiresAt: number;
|
||||
value: ITermSet;
|
||||
}
|
||||
|
||||
interface IPickerTermCacheEntry {
|
||||
expiresAt: number;
|
||||
value: IPickerTerm[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Service implementation to manage term stores in SharePoint
|
||||
@@ -31,7 +43,7 @@ export default class SPTermStorePickerService {
|
||||
public async getTermLabels(termId: string): Promise<string[]> {
|
||||
let result: string[] = null;
|
||||
try {
|
||||
const data = `<Request AddExpandoFieldTypeSuffix="true" SchemaVersion="15.0.0.0" LibraryVersion="16.0.0.0" ApplicationName=".NET Library" xmlns="http://schemas.microsoft.com/sharepoint/clientquery/2009"><Actions><ObjectPath Id="8" ObjectPathId="7" /><ObjectIdentityQuery Id="9" ObjectPathId="7" /><ObjectPath Id="11" ObjectPathId="10" /><ObjectIdentityQuery Id="12" ObjectPathId="10" /><ObjectPath Id="14" ObjectPathId="13" /><ObjectIdentityQuery Id="15" ObjectPathId="13" /><Query Id="16" ObjectPathId="13"><Query SelectAllProperties="false"><Properties><Property Name="Labels" SelectAll="true"><Query SelectAllProperties="false"><Properties /></Query></Property></Properties></Query></Query></Actions><ObjectPaths><StaticMethod Id="7" Name="GetTaxonomySession" TypeId="{981cbc68-9edc-4f8d-872f-71146fcbb84f}" /><Method Id="10" ParentId="7" Name="GetDefaultKeywordsTermStore" /><Method Id="13" ParentId="10" Name="GetTerm"><Parameters><Parameter Type="Guid">${termId}</Parameter></Parameters></Method></ObjectPaths></Request>`;
|
||||
const data = `<Request AddExpandoFieldTypeSuffix="true" SchemaVersion="15.0.0.0" LibraryVersion="16.0.0.0" ApplicationName=".NET Library" xmlns="http://schemas.microsoft.com/sharepoint/clientquery/2009"><Actions><ObjectPath Id="8" ObjectPathId="7" /><ObjectIdentityQuery Id="9" ObjectPathId="7" /><ObjectPath Id="11" ObjectPathId="10" /><ObjectIdentityQuery Id="12" ObjectPathId="10" /><ObjectPath Id="14" ObjectPathId="13" /><ObjectIdentityQuery Id="15" ObjectPathId="13" /><Query Id="16" ObjectPathId="13"><Query SelectAllProperties="false"><Properties><Property Name="Labels" SelectAll="true"><Query SelectAllProperties="false"><Properties /></Query></Property></Properties></Query></Query></Actions><ObjectPaths><StaticMethod Id="7" Name="GetTaxonomySession" TypeId="{981cbc68-9edc-4f8d-872f-71146fcbb84f}" /><Method Id="10" ParentId="7" Name="GetDefaultSiteCollectionTermStore" /><Method Id="13" ParentId="10" Name="GetTerm"><Parameters><Parameter Type="Guid">${termId}</Parameter></Parameters></Method></ObjectPaths></Request>`;
|
||||
|
||||
const reqHeaders = new Headers();
|
||||
reqHeaders.append('accept', 'application/json');
|
||||
@@ -43,6 +55,7 @@ export default class SPTermStorePickerService {
|
||||
};
|
||||
|
||||
const callResult = await this.context.spHttpClient.post(this.clientServiceUrl, SPHttpClient.configurations.v1, httpPostOptions);
|
||||
this.ensureSuccessfulResponse(callResult, 'Term labels');
|
||||
const jsonResult = await callResult.json();
|
||||
|
||||
const node = jsonResult.find(x => x._ObjectType_ === 'SP.Taxonomy.Term');
|
||||
@@ -73,6 +86,7 @@ export default class SPTermStorePickerService {
|
||||
};
|
||||
|
||||
return this.context.spHttpClient.post(this.clientServiceUrl, SPHttpClient.configurations.v1, httpPostOptions).then((serviceResponse: SPHttpClientResponse) => {
|
||||
this.ensureSuccessfulResponse(serviceResponse, 'Term stores');
|
||||
return serviceResponse.json().then((serviceJSONResponse: any) => {
|
||||
// Construct results
|
||||
const termStoreResult: ITermStore[] = serviceJSONResponse.filter((r: { [x: string]: string; }) => r['_ObjectType_'] === 'SP.Taxonomy.TermStore');
|
||||
@@ -124,7 +138,13 @@ export default class SPTermStorePickerService {
|
||||
* Retrieve all terms for the given term set
|
||||
* @param termset
|
||||
*/
|
||||
public async getAllTerms(termset: string, hideDeprecatedTags?: boolean, hideTagsNotAvailableForTagging?: boolean, useSessionStorage: boolean = true): Promise<ITermSet> {
|
||||
public async getAllTerms(
|
||||
termset: string,
|
||||
hideDeprecatedTags?: boolean,
|
||||
hideTagsNotAvailableForTagging?: boolean,
|
||||
useSessionStorage: boolean = true,
|
||||
cacheMinutes: number = 15
|
||||
): Promise<ITermSet> {
|
||||
let termsetId: string = termset;
|
||||
// Check if the provided term set property is a GUID or string
|
||||
if (!this.isGuid(termset)) {
|
||||
@@ -139,14 +159,14 @@ export default class SPTermStorePickerService {
|
||||
}
|
||||
}
|
||||
|
||||
const childTerms = this.getTermsById(termsetId, useSessionStorage);
|
||||
const childTerms = this.getCachedTermSet(termsetId, useSessionStorage);
|
||||
|
||||
if (childTerms) {
|
||||
return childTerms;
|
||||
}
|
||||
|
||||
// Request body to retrieve all terms for the given term set
|
||||
const data = `<Request xmlns="http://schemas.microsoft.com/sharepoint/clientquery/2009" SchemaVersion="15.0.0.0" LibraryVersion="16.0.0.0" ApplicationName="Javascript Library"><Actions><ObjectPath Id="1" ObjectPathId="0" /><ObjectIdentityQuery Id="2" ObjectPathId="0" /><ObjectPath Id="4" ObjectPathId="3" /><ObjectIdentityQuery Id="5" ObjectPathId="3" /><ObjectPath Id="7" ObjectPathId="6" /><ObjectIdentityQuery Id="8" ObjectPathId="6" /><ObjectPath Id="10" ObjectPathId="9" /><Query Id="11" ObjectPathId="6"><Query SelectAllProperties="true"><Properties /></Query></Query><Query Id="12" ObjectPathId="9"><Query SelectAllProperties="false"><Properties /></Query><ChildItemQuery SelectAllProperties="false"><Properties><Property Name="IsRoot" SelectAll="true" /><Property Name="Labels" SelectAll="true" /><Property Name="TermsCount" SelectAll="true" /><Property Name="CustomSortOrder" SelectAll="true" /><Property Name="Id" SelectAll="true" /><Property Name="Name" SelectAll="true" /><Property Name="PathOfTerm" SelectAll="true" /><Property Name="Parent" SelectAll="true" /><Property Name="LocalCustomProperties" SelectAll="true" /><Property Name="IsDeprecated" ScalarProperty="true" /><Property Name="IsAvailableForTagging" ScalarProperty="true" /></Properties></ChildItemQuery></Query></Actions><ObjectPaths><StaticMethod Id="0" Name="GetTaxonomySession" TypeId="{981cbc68-9edc-4f8d-872f-71146fcbb84f}" /><Method Id="3" ParentId="0" Name="GetDefaultKeywordsTermStore" /><Method Id="6" ParentId="3" Name="GetTermSet"><Parameters><Parameter Type="Guid">${termsetId}</Parameter></Parameters></Method><Method Id="9" ParentId="6" Name="GetAllTerms" /></ObjectPaths></Request>`;
|
||||
const data = `<Request xmlns="http://schemas.microsoft.com/sharepoint/clientquery/2009" SchemaVersion="15.0.0.0" LibraryVersion="16.0.0.0" ApplicationName="Javascript Library"><Actions><ObjectPath Id="1" ObjectPathId="0" /><ObjectIdentityQuery Id="2" ObjectPathId="0" /><ObjectPath Id="4" ObjectPathId="3" /><ObjectIdentityQuery Id="5" ObjectPathId="3" /><ObjectPath Id="7" ObjectPathId="6" /><ObjectIdentityQuery Id="8" ObjectPathId="6" /><ObjectPath Id="10" ObjectPathId="9" /><Query Id="11" ObjectPathId="6"><Query SelectAllProperties="true"><Properties /></Query></Query><Query Id="12" ObjectPathId="9"><Query SelectAllProperties="false"><Properties /></Query><ChildItemQuery SelectAllProperties="false"><Properties><Property Name="IsRoot" SelectAll="true" /><Property Name="Labels" SelectAll="true" /><Property Name="TermsCount" SelectAll="true" /><Property Name="CustomSortOrder" SelectAll="true" /><Property Name="Id" SelectAll="true" /><Property Name="Name" SelectAll="true" /><Property Name="PathOfTerm" SelectAll="true" /><Property Name="Parent" SelectAll="true" /><Property Name="LocalCustomProperties" SelectAll="true" /><Property Name="IsDeprecated" ScalarProperty="true" /><Property Name="IsAvailableForTagging" ScalarProperty="true" /></Properties></ChildItemQuery></Query></Actions><ObjectPaths><StaticMethod Id="0" Name="GetTaxonomySession" TypeId="{981cbc68-9edc-4f8d-872f-71146fcbb84f}" /><Method Id="3" ParentId="0" Name="GetDefaultSiteCollectionTermStore" /><Method Id="6" ParentId="3" Name="GetTermSet"><Parameters><Parameter Type="Guid">${termsetId}</Parameter></Parameters></Method><Method Id="9" ParentId="6" Name="GetAllTerms" /></ObjectPaths></Request>`;
|
||||
|
||||
const reqHeaders = new Headers();
|
||||
reqHeaders.append('accept', 'application/json');
|
||||
@@ -158,7 +178,11 @@ export default class SPTermStorePickerService {
|
||||
};
|
||||
|
||||
return this.context.spHttpClient.post(this.clientServiceUrl, SPHttpClient.configurations.v1, httpPostOptions).then((serviceResponse: SPHttpClientResponse) => {
|
||||
this.ensureSuccessfulResponse(serviceResponse, 'Terms');
|
||||
return serviceResponse.json().then((serviceJSONResponse: any) => {
|
||||
if (!Array.isArray(serviceJSONResponse)) {
|
||||
throw new Error('The taxonomy service returned an unexpected response.');
|
||||
}
|
||||
const termStoreResultTermSets: ITermSet[] = serviceJSONResponse.filter((r: { [x: string]: string; }) => r['_ObjectType_'] === 'SP.Taxonomy.TermSet');
|
||||
|
||||
if (termStoreResultTermSets.length > 0) {
|
||||
@@ -203,7 +227,12 @@ export default class SPTermStorePickerService {
|
||||
|
||||
try {
|
||||
if (useSessionStorage && window.sessionStorage) {
|
||||
window.sessionStorage.setItem(termsetId, JSON.stringify(termStoreResultTermSet));
|
||||
const ttlMinutes: number = this.normalizeCacheMinutes(cacheMinutes);
|
||||
const cacheEntry: ITermCacheEntry = {
|
||||
expiresAt: Date.now() + ttlMinutes * 60 * 1000,
|
||||
value: termStoreResultTermSet
|
||||
};
|
||||
window.sessionStorage.setItem(TermCachePrefix + termsetId, JSON.stringify(cacheEntry));
|
||||
}
|
||||
} catch (error) {
|
||||
// Do nothing, sometimes "storage quota exceeded" error if too many items
|
||||
@@ -225,7 +254,7 @@ export default class SPTermStorePickerService {
|
||||
|
||||
public async searchTermsByTermId(searchText: string, termId: string): Promise<IPickerTerm[]> {
|
||||
const { useSessionStorage } = this.props;
|
||||
const childTerms = this.getTermsById(termId, useSessionStorage);
|
||||
const childTerms = this.getCachedPickerTerms(termId, useSessionStorage);
|
||||
if (childTerms) {
|
||||
return this.searchTermsBySearchText(childTerms, searchText);
|
||||
} else {
|
||||
@@ -257,12 +286,18 @@ export default class SPTermStorePickerService {
|
||||
|
||||
const returnTerms: IPickerTerm[] = [];
|
||||
|
||||
const childTerms = this.getTermsById(anchorId, useSessionStorage);
|
||||
const childTerms = this.getCachedPickerTerms(anchorId, useSessionStorage);
|
||||
if (childTerms) {
|
||||
return childTerms;
|
||||
}
|
||||
|
||||
const termSet = await this.getAllTerms(termsetNameOrID, hideDeprecatedTags, hideTagsNotAvailableForTagging);
|
||||
const termSet = await this.getAllTerms(
|
||||
termsetNameOrID,
|
||||
hideDeprecatedTags,
|
||||
hideTagsNotAvailableForTagging,
|
||||
useSessionStorage,
|
||||
this.props.cacheMinutes
|
||||
);
|
||||
const terms = termSet.Terms;
|
||||
if (anchorId) {
|
||||
const anchorTerm = terms.filter(t => t.Id.toLowerCase() === anchorId.toLowerCase()).shift();
|
||||
@@ -277,7 +312,11 @@ export default class SPTermStorePickerService {
|
||||
|
||||
try {
|
||||
if (useSessionStorage && window.sessionStorage) {
|
||||
window.sessionStorage.setItem(anchorId, JSON.stringify(returnTerms));
|
||||
const cacheEntry: IPickerTermCacheEntry = {
|
||||
expiresAt: Date.now() + this.normalizeCacheMinutes(this.props.cacheMinutes) * 60 * 1000,
|
||||
value: returnTerms
|
||||
};
|
||||
window.sessionStorage.setItem(PickerCachePrefix + anchorId, JSON.stringify(cacheEntry));
|
||||
}
|
||||
} catch (error) {
|
||||
// Do nothing
|
||||
@@ -332,15 +371,21 @@ export default class SPTermStorePickerService {
|
||||
return null;
|
||||
}
|
||||
|
||||
private getTermsById(termId, useSessionStorage: boolean = true) {
|
||||
private getCachedTermSet(termId: string, useSessionStorage: boolean = true): ITermSet {
|
||||
try {
|
||||
if (useSessionStorage && window.sessionStorage) {
|
||||
const terms = window.sessionStorage.getItem(termId);
|
||||
if (terms) {
|
||||
return JSON.parse(terms);
|
||||
} else {
|
||||
const key: string = TermCachePrefix + termId;
|
||||
const terms: string = window.sessionStorage.getItem(key);
|
||||
if (!terms) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const cacheEntry: ITermCacheEntry = JSON.parse(terms) as ITermCacheEntry;
|
||||
if (!cacheEntry || !cacheEntry.value || !cacheEntry.expiresAt || cacheEntry.expiresAt <= Date.now()) {
|
||||
window.sessionStorage.removeItem(key);
|
||||
return null;
|
||||
}
|
||||
return cacheEntry.value;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
@@ -349,6 +394,42 @@ export default class SPTermStorePickerService {
|
||||
}
|
||||
}
|
||||
|
||||
private getCachedPickerTerms(termId: string, useSessionStorage: boolean = true): IPickerTerm[] {
|
||||
try {
|
||||
if (!useSessionStorage || !window.sessionStorage) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const key: string = PickerCachePrefix + termId;
|
||||
const serialized: string = window.sessionStorage.getItem(key);
|
||||
if (!serialized) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const cacheEntry: IPickerTermCacheEntry = JSON.parse(serialized) as IPickerTermCacheEntry;
|
||||
if (!cacheEntry || !cacheEntry.value || !cacheEntry.expiresAt || cacheEntry.expiresAt <= Date.now()) {
|
||||
window.sessionStorage.removeItem(key);
|
||||
return null;
|
||||
}
|
||||
return cacheEntry.value;
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private normalizeCacheMinutes(value: number): number {
|
||||
if (typeof value !== 'number' || !isFinite(value)) {
|
||||
return 15;
|
||||
}
|
||||
return Math.min(Math.max(Math.floor(value), 1), 1440);
|
||||
}
|
||||
|
||||
private ensureSuccessfulResponse(response: SPHttpClientResponse, operation: string): void {
|
||||
if (!response.ok) {
|
||||
throw new Error(operation + ' request failed (' + response.status + ' ' + response.statusText + ').');
|
||||
}
|
||||
}
|
||||
|
||||
private searchTermsBySearchText(terms, searchText) {
|
||||
if (terms) {
|
||||
return terms.filter((t) => { return t.name.toLowerCase().indexOf(searchText.toLowerCase()) > -1; });
|
||||
|
||||
Reference in New Issue
Block a user