Updated the WebPart with the latest spfx packages.

Multiple bottle-neck bugs have been fixed in SPFX which allows to update
the WebPart with the latest SPFX packages. Overall performance should
now be better and other minor bugs have been fixed.
This commit is contained in:
Simon-Pierre Plante 2017-07-23 21:52:07 -04:00
parent ac8fa43ab6
commit 3c77c0b8e0
22 changed files with 15482 additions and 8440 deletions

75
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,75 @@
// Place your settings in this file to overwrite default and user settings.
{
// Configure glob patterns for excluding files and folders in the file explorer.
"files.exclude": {
"**/.git": true,
"**/.DS_Store": true,
"**/bower_components": true,
"**/coverage": true,
"**/lib-amd": true,
"src/**/*.scss.ts": true
},
"typescript.tsdk": ".\\node_modules\\typescript\\lib",
"json.schemas": [
{
"fileMatch": [
"/config/config.json"
],
"url": "./node_modules/@microsoft/sp-build-web/lib/schemas/config.schema.json"
},
{
"fileMatch": [
"/config/copy-assets.json"
],
"url": "./node_modules/@microsoft/sp-build-core-tasks/lib/copyAssets/copy-assets.schema.json"
},
{
"fileMatch": [
"/config/deploy-azure-storage.json"
],
"url": "./node_modules/@microsoft/sp-build-core-tasks/lib/deployAzureStorage/deploy-azure-storage.schema.json"
},
{
"fileMatch": [
"/config/package-solution.json"
],
"url": "./node_modules/@microsoft/sp-build-core-tasks/lib/packageSolution/package-solution.schema.json"
},
{
"fileMatch": [
"/config/serve.json"
],
"url": "./node_modules/@microsoft/gulp-core-build-serve/lib/serve.schema.json"
},
{
"fileMatch": [
"/config/tslint.json"
],
"url": "./node_modules/@microsoft/gulp-core-build-typescript/lib/schemas/tslint.schema.json"
},
{
"fileMatch": [
"/config/write-manifests.json"
],
"url": "./node_modules/@microsoft/sp-build-core-tasks/lib/writeManifests/write-manifests.schema.json"
},
{
"fileMatch": [
"/config/configure-webpack.json"
],
"url": "./node_modules/@microsoft/sp-build-core-tasks/lib/configureWebpack/configure-webpack.schema.json"
},
{
"fileMatch": [
"/config/configure-external-bundling-webpack.json"
],
"url": "./node_modules/@microsoft/sp-build-core-tasks/lib/configureWebpack/configure-webpack-external-bundling.schema.json"
},
{
"fileMatch": [
"/copy-static-assets.json"
],
"url": "./node_modules/@microsoft/sp-build-core-tasks/lib/copyStaticAssets/copy-static-assets.schema.json"
}
]
}

View File

@ -1,8 +1,8 @@
{
"@microsoft/generator-sharepoint": {
"libraryName": "content-query-webpart",
"framework": "react",
"version": "1.0.0",
"libraryId": "00406271-0276-406f-9666-512623eb6709"
"version": "1.1.1",
"libraryName": "react-content-query",
"libraryId": "489c9f8f-8e66-4efb-8365-85279ba91433",
"environment": "spo"
}
}

View File

@ -6,4 +6,4 @@
"port": 5432,
"entryPath": "node_modules/@microsoft/sp-webpart-workbench/lib/api/"
}
}
}

View File

@ -18,7 +18,7 @@
"label-position": false,
"member-access": true,
"no-arg": false,
"no-console": true,
"no-console": false,
"no-construct": false,
"no-duplicate-case": true,
"no-duplicate-variable": true,
@ -39,8 +39,7 @@
"use-named-parameter": true,
"valid-typeof": true,
"variable-name": false,
"whitespace": false,
"prefer-const": false
"whitespace": false
}
}
}

View File

@ -1,3 +1,3 @@
{
"cdnBasePath": "https://publiccdn.sharepointonline.com/spptechnologies.sharepoint.com/110700492eeea162ee5bad0f35b1f0061ded8bf436ce0199efe2a4d24109e1c0df1ec594/react-content-query-1.0.1"
"cdnBasePath": "https://publiccdn.sharepointonline.com/spptechnologies.sharepoint.com/110700492eeea162ee5bad0f35b1f0061ded8bf436ce0199efe2a4d24109e1c0df1ec594/react-content-query-1.0.2"
}

View File

@ -11,11 +11,12 @@ const build = require('@microsoft/sp-build-web');
********************************************************************************************/
build.configureWebpack.mergeConfig({
additionalConfiguration: (generatedConfiguration) => {
generatedConfiguration.resolve.alias = { handlebars: 'handlebars/dist/handlebars.min.js' };
generatedConfiguration.module.loaders.push({
test: /\.js$/, loader: 'unlazy'
});
generatedConfiguration.module.rules.push(
{ test: /\.js$/, loader: 'unlazy-loader' }
);
generatedConfiguration.node = {
fs: 'empty'

8248
npm-shrinkwrap.json generated

File diff suppressed because it is too large Load Diff

15295
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,38 +1,34 @@
{
"name": "react-content-query",
"version": "1.0.1",
"version": "1.0.2",
"private": true,
"engines": {
"node": ">=0.10.0"
},
"dependencies": {
"@microsoft/sp-client-base": "~1.0.0",
"@microsoft/sp-core-library": "~1.0.0",
"@microsoft/sp-webpart-base": "~1.0.0",
"@types/handlebars": "^4.0.32",
"@microsoft/sp-core-library": "~1.1.0",
"@microsoft/sp-webpart-base": "~1.1.1",
"@types/handlebars": "4.0.32",
"@types/react": "0.14.46",
"@types/react-addons-shallow-compare": "0.14.17",
"@types/react-addons-test-utils": "0.14.15",
"@types/react-addons-update": "0.14.14",
"@types/react-dom": "0.14.18",
"@types/webpack-env": ">=1.12.1 <1.14.0",
"brace": "^0.10.0",
"handlebars": "^4.0.6",
"handlebars-helpers": "^0.8.2",
"moment": "^2.18.1",
"office-ui-fabric-react": "1.14.3",
"react": "15.4.2",
"react-ace": "^4.2.1",
"react-ace": "^5.1.0",
"react-dom": "15.4.2"
},
"devDependencies": {
"@microsoft/sp-build-web": "https://registry.npmjs.org/@microsoft/sp-build-web/-/sp-build-web-1.0.0.tgz",
"@microsoft/sp-module-interfaces": "~1.0.0",
"@microsoft/sp-webpart-workbench": "~1.0.0",
"@microsoft/sp-build-web": "~1.1.0",
"@microsoft/sp-module-interfaces": "~1.1.0",
"@microsoft/sp-webpart-workbench": "~1.1.0",
"@types/chai": ">=3.4.34 <3.6.0",
"@types/microsoft-ajax": "0.0.31",
"@types/mocha": ">=2.2.33 <2.6.0",
"@types/sharepoint": "^2013.1.4",
"awesome-typescript-loader": "^3.2.1",
"gulp": "~3.9.1",
"unlazy-loader": "^0.1.2"
},

View File

@ -19,7 +19,8 @@ export class CamlQueryHelper {
// Generates the <Where /> part
if(querySettings.filters && !isEmpty(querySettings.filters)) {
query += Text.format('<Where>{0}</Where>', this.generateFilters(querySettings.filters));
let sortedFilters = querySettings.filters.sort((a, b) => { if(a.index > b.index) { return 1; } else { return 0; } });
query += Text.format('<Where>{0}</Where>', this.generateFilters(sortedFilters));
}
// Generates the <OrderBy /> part
@ -127,6 +128,7 @@ export class CamlQueryHelper {
let termValue:ITag[] = [ term ];
let taxFilter:IQueryFilter = {
index: null,
field: filter.field,
value: termValue,
join: QueryFilterJoin.And,
@ -170,6 +172,7 @@ export class CamlQueryHelper {
let userValue:IPersonaProps[] = [ user ];
let userFilter:IQueryFilter = {
index: null,
field: filter.field,
value: userValue,
join: QueryFilterJoin.And,

View File

@ -14,7 +14,7 @@ export interface IContentQueryService {
getFilterFields: (webUrl: string, listTitle: string) => Promise<IQueryFilterField[]>;
getViewFieldsChecklistItems: (webUrl: string, listTitle: string) => Promise<IChecklistItem[]>;
getPeoplePickerSuggestions: (webUrl: string, filterText: string, currentPersonas: IPersonaProps[], limitResults?: number) => Promise<IPersonaProps[]>;
getTaxonomyPickerSuggestions: (webUrl: string, listTitle: string, field: IQueryFilterField, filterText: string, currentTerms: ITag[]) => Promise<IPersonaProps[]>;
getTaxonomyPickerSuggestions: (webUrl: string, listTitle: string, field: IQueryFilterField, filterText: string, currentTerms: ITag[]) => Promise<ITag[]>;
ensureFileResolves: (filePath: string) => Promise<{}>;
isValidTemplateFile: (filePath: string) => boolean;
generateDefaultTemplate: (viewFields: string[]) => string;

View File

@ -35,29 +35,18 @@ export class ListService {
};
let options: ISPHttpClientOptions = { headers: { 'odata-version': '3.0' }, body: JSON.stringify(data) };
// Tests the web URL against 404 errors before executing the query, to avoid a bug that occurs with SPHttpClient.post when trying to post
// https://github.com/SharePoint/sp-dev-docs/issues/553
this.spHttpClient.get(webUrl, SPHttpClient.configurations.v1, { method: 'HEAD' })
.then((headResponse: SPHttpClientResponse) => {
if(headResponse.status != 404) {
// If there is no 404, proceeds with the CAML query
this.spHttpClient.post(endpoint, SPHttpClient.configurations.v1, options)
.then((postResponse: SPHttpClientResponse) => {
if(postResponse.ok) {
resolve(postResponse.json());
}
else {
reject(postResponse);
}
})
.catch((error) => { reject(error); });
this.spHttpClient.post(endpoint, SPHttpClient.configurations.v1, options)
.then((postResponse: SPHttpClientResponse) => {
if(postResponse.ok) {
resolve(postResponse.json());
}
else {
reject(headResponse);
reject(postResponse);
}
})
.catch((error) => { reject(error); });
.catch((error) => {
reject(error);
});
});
}

View File

@ -4,6 +4,7 @@ import { QueryFilterJoin } from './QueryFilterJoin';
import { IPersonaProps, ITag } from 'office-ui-fabric-react';
export interface IQueryFilter {
index: number;
field: IQueryFilterField;
operator: QueryFilterOperator;
value: string | IPersonaProps[] | ITag[] | Date;

View File

@ -9,8 +9,7 @@ export interface IQueryFilterProps {
fields: IQueryFilterField[];
onLoadTaxonomyPickerSuggestions: (field: IQueryFilterField, filterText: string, currentTerms: ITag[]) => Promise<ITag[]>;
onLoadPeoplePickerSuggestions: (filterText: string, currentPersonas: IPersonaProps[], limitResults?: number) => Promise<IPersonaProps[]>;
onChanged?: (filter: IQueryFilter, index: number) => void;
onChanged?: (filter: IQueryFilter) => void;
disabled?: boolean;
strings: IQueryFilterStrings;
index?: number;
}

View File

@ -33,7 +33,7 @@ export class QueryFilter extends React.Component<IQueryFilterProps, IQueryFilter
moment.locale(this.props.strings.datePickerLocale);
this.state = {
filter: (this.props.filter ? cloneDeep(this.props.filter) : { field: null, operator: QueryFilterOperator.Eq, value: '', join: QueryFilterJoin.Or }),
filter: (this.props.filter ? cloneDeep(this.props.filter) : { index: 0, field: null, operator: QueryFilterOperator.Eq, value: '', join: QueryFilterJoin.Or }),
pickersKey: Math.random()
};
@ -71,8 +71,10 @@ export class QueryFilter extends React.Component<IQueryFilterProps, IQueryFilter
* When the TextField value changes
*************************************************************************************/
private onValueTextFieldChange(newValue: string): string {
this.state.filter.value = newValue;
this.onAnyChange();
if(this.state.filter.value != newValue) {
this.state.filter.value = newValue;
this.onAnyChange();
}
return '';
}
@ -169,7 +171,7 @@ export class QueryFilter extends React.Component<IQueryFilterProps, IQueryFilter
*************************************************************************************/
private onAnyChange() {
if(this.props.onChanged) {
this.props.onChanged(this.state.filter, this.props.index);
this.props.onChanged(this.state.filter);
}
}

View File

@ -15,14 +15,6 @@ import styles from './QueryFilterPanel.module.
export class QueryFilterPanel extends React.Component<IQueryFilterPanelProps, IQueryFilterPanelState> {
/*************************************************************************************
* Adds a default filter that always appears
*************************************************************************************/
private defaultFilters:IQueryFilter[] = [
{ field: null, operator: QueryFilterOperator.Eq, join: QueryFilterJoin.Or, value: '' }
];
/*************************************************************************************
* Component's constructor
* @param props
@ -48,11 +40,11 @@ export class QueryFilterPanel extends React.Component<IQueryFilterPanelProps, IQ
*************************************************************************************/
private getDefaultFilters():IQueryFilter[] {
if(this.props.filters != null && this.props.filters.length > 0) {
return this.props.filters;
return this.sortFiltersByIndex(this.props.filters);
}
let defaultFilters:IQueryFilter[] = [
{ field: null, operator: QueryFilterOperator.Eq, join: QueryFilterJoin.Or, value: '' }
{ index: 0, field: null, operator: QueryFilterOperator.Eq, join: QueryFilterJoin.Or, value: '' }
];
return defaultFilters;
}
@ -83,9 +75,7 @@ export class QueryFilterPanel extends React.Component<IQueryFilterPanelProps, IQ
this.setState((prevState: IQueryFilterPanelState, props: IQueryFilterPanelProps): IQueryFilterPanelState => {
prevState.loading = true;
prevState.fields = new Array<IQueryFilterField>();
prevState.error = null;
prevState.filters = this.getDefaultFilters();
return prevState;
});
@ -93,6 +83,7 @@ export class QueryFilterPanel extends React.Component<IQueryFilterPanelProps, IQ
this.setState((prevState: IQueryFilterPanelState, props: IQueryFilterPanelProps): IQueryFilterPanelState => {
prevState.loading = false;
prevState.fields = fields;
prevState.filters = this.getDefaultFilters();
return prevState;
});
})
@ -109,17 +100,18 @@ export class QueryFilterPanel extends React.Component<IQueryFilterPanelProps, IQ
/*************************************************************************************
* When one of the filter changes
*************************************************************************************/
private onFilterChanged(filter:IQueryFilter, index:number): void {
private onFilterChanged(filter:IQueryFilter): void {
// Makes sure the parent is not notified for no reason if the modified filter was (and still is) considered empty
let isWorthNotifyingParent = true;
let oldFilter = this.state.filters[index];
let oldFilter = this.state.filters.filter((i) => { return i.index == filter.index; })[0];
let oldFilterIndex = this.state.filters.indexOf(oldFilter);
if(this.props.trimEmptyFiltersOnChange && this.isFilterEmpty(oldFilter) && this.isFilterEmpty(filter)) {
isWorthNotifyingParent = false;
}
// Updates the modified filter in the state
this.state.filters[index] = cloneDeep(filter);
this.state.filters[oldFilterIndex] = cloneDeep(filter);
this.setState((prevState: IQueryFilterPanelState, props: IQueryFilterPanelProps): IQueryFilterPanelState => {
prevState.filters = this.state.filters;
return prevState;
@ -170,7 +162,8 @@ export class QueryFilterPanel extends React.Component<IQueryFilterPanelProps, IQ
*************************************************************************************/
private onAddFilterClick(): void {
// Updates the state with an all fresh new filter
let newFilter:IQueryFilter = { field: null, operator: QueryFilterOperator.Eq, join: QueryFilterJoin.Or, value: '' };
let nextAvailableFilterIndex = this.state.filters[this.state.filters.length-1].index + 1;
let newFilter:IQueryFilter = { index: nextAvailableFilterIndex, field: null, operator: QueryFilterOperator.Eq, join: QueryFilterJoin.Or, value: '' };
this.state.filters.push(newFilter);
this.setState((prevState: IQueryFilterPanelState, props: IQueryFilterPanelProps): IQueryFilterPanelState => {
@ -180,6 +173,13 @@ export class QueryFilterPanel extends React.Component<IQueryFilterPanelProps, IQ
}
private sortFiltersByIndex(filters:IQueryFilter[]): IQueryFilter[] {
return filters.sort((a, b) => {
if(a.index > b.index) { return 1; } else { return 0; }
});
}
/*************************************************************************************
* Renders the the QueryFilter component
*************************************************************************************/
@ -196,7 +196,7 @@ export class QueryFilterPanel extends React.Component<IQueryFilterPanelProps, IQ
onLoadPeoplePickerSuggestions={this.props.onLoadPeoplePickerSuggestions}
onChanged={this.onFilterChanged.bind(this)}
strings={this.props.strings.queryFilterStrings}
index={index} />
key={index} />
</div>
);

View File

@ -17,7 +17,6 @@ import { PropertyPaneAsyncDropdown }
import { PropertyPaneQueryFilterPanel } from '../../controls/PropertyPaneQueryFilterPanel/PropertyPaneQueryFilterPanel';
import { PropertyPaneAsyncChecklist } from '../../controls/PropertyPaneAsyncChecklist/PropertyPaneAsyncChecklist';
import { PropertyPaneTextDialog } from '../../controls/PropertyPaneTextDialog/PropertyPaneTextDialog';
import { IQueryFilter } from '../../controls/PropertyPaneQueryFilterPanel/components/QueryFilter/IQueryFilter';
import { IQueryFilterField } from '../../controls/PropertyPaneQueryFilterPanel/components/QueryFilter/IQueryFilterField';
import { IChecklistItem } from '../../controls/PropertyPaneAsyncChecklist/components/AsyncChecklist/IChecklistItem';
import { ContentQueryService } from '../../common/services/ContentQueryService';
@ -55,7 +54,7 @@ export default class ContentQueryWebPart extends BaseClientSideWebPart<IContentQ
* Returns the WebPart's version
***************************************************************************/
protected get dataVersion(): Version {
return Version.parse('1.0.1');
return Version.parse('1.0.2');
}
@ -114,7 +113,7 @@ export default class ContentQueryWebPart extends BaseClientSideWebPart<IContentQ
loadingLabel: strings.WebUrlFieldLoadingLabel,
errorLabelFormat: strings.WebUrlFieldLoadingError,
loadOptions: this.loadWebUrlOptions.bind(this),
onPropertyChange: this.onWebUrlChange.bind(this),
onPropertyChange: this.onCustomPropertyPaneChange.bind(this),
selectedKey: this.properties.webUrl || ""
});
@ -124,7 +123,7 @@ export default class ContentQueryWebPart extends BaseClientSideWebPart<IContentQ
loadingLabel: strings.ListTitleFieldLoadingLabel,
errorLabelFormat: strings.ListTitleFieldLoadingError,
loadOptions: this.loadListTitleOptions.bind(this),
onPropertyChange: this.onListTitleChange.bind(this),
onPropertyChange: this.onCustomPropertyPaneChange.bind(this),
selectedKey: this.properties.listTitle || "",
disabled: firstCascadingLevelDisabled
});
@ -135,7 +134,7 @@ export default class ContentQueryWebPart extends BaseClientSideWebPart<IContentQ
loadingLabel: strings.OrderByFieldLoadingLabel,
errorLabelFormat: strings.OrderByFieldLoadingError,
loadOptions: this.loadOrderByOptions.bind(this),
onPropertyChange: this.onOrderByChange.bind(this),
onPropertyChange: this.onCustomPropertyPaneChange.bind(this),
selectedKey: this.properties.orderBy || "",
disabled: secondCascadingLevelDisabled
});
@ -146,7 +145,7 @@ export default class ContentQueryWebPart extends BaseClientSideWebPart<IContentQ
loadFields: this.loadFilterFields.bind(this),
onLoadTaxonomyPickerSuggestions: this.loadTaxonomyPickerSuggestions.bind(this),
onLoadPeoplePickerSuggestions: this.loadPeoplePickerSuggestions.bind(this),
onPropertyChange: this.onFiltersChange.bind(this),
onPropertyChange: this.onCustomPropertyPaneChange.bind(this),
trimEmptyFiltersOnChange: true,
disabled: secondCascadingLevelDisabled,
strings: strings.queryFilterPanelStrings
@ -156,7 +155,7 @@ export default class ContentQueryWebPart extends BaseClientSideWebPart<IContentQ
this.viewFieldsChecklist = new PropertyPaneAsyncChecklist(ContentQueryConstants.propertyViewFields, {
loadItems: this.loadViewFieldsChecklistItems.bind(this),
checkedItems: this.properties.viewFields,
onPropertyChange: this.onViewFieldsChange.bind(this),
onPropertyChange: this.onCustomPropertyPaneChange.bind(this),
disable: secondCascadingLevelDisabled,
strings: strings.viewFieldsChecklistStrings
});
@ -164,7 +163,7 @@ export default class ContentQueryWebPart extends BaseClientSideWebPart<IContentQ
// Creates a custom PropertyPaneTextDialog for the templateText property
this.templateTextDialog = new PropertyPaneTextDialog(ContentQueryConstants.propertyTemplateText, {
dialogTextFieldValue: this.properties.templateText,
onPropertyChange: this.onTemplateTextChange.bind(this),
onPropertyChange: this.onCustomPropertyPaneChange.bind(this),
disabled: false,
strings: strings.templateTextStrings
});
@ -238,17 +237,7 @@ export default class ContentQueryWebPart extends BaseClientSideWebPart<IContentQ
groupName: strings.DisplayGroupName,
groupFields: [
this.viewFieldsChecklist,
this.templateTextDialog
]
}
]
},
{
header: { description: strings.ExternalPageDescription },
groups: [
{
groupName: strings.ExternalGroupName,
groupFields: [
this.templateTextDialog,
this.templateUrlTextField
]
}
@ -339,116 +328,59 @@ export default class ContentQueryWebPart extends BaseClientSideWebPart<IContentQ
/***************************************************************************
* Handles the change of the webUrl property
* When a custom property pane updates
***************************************************************************/
private onWebUrlChange(propertyPath: string, newValue: any): void {
Log.verbose(this.logSource, "WebPart property 'webUrl' has changed, refreshing WebPart...", this.context.serviceScope);
private onCustomPropertyPaneChange(propertyPath: string, newValue: any): void {
Log.verbose(this.logSource, "WebPart property '" + propertyPath + "' has changed, refreshing WebPart...", this.context.serviceScope);
let rerenderTemplateTextDialog = false;
const oldValue = get(this.properties, propertyPath);
// Stores the new value in web part properties
update(this.properties, propertyPath, (): any => { return newValue; });
// Resets the web-dependent property panes
this.resetListTitlePropertyPane();
this.resetOrderByPropertyPane();
this.resetFiltersPropertyPane();
this.resetViewFieldsPropertyPane();
// Refreshes the web part
this.onPropertyPaneFieldChanged(propertyPath, oldValue, newValue);
}
// Resets dependent property panes if needed
this.resetDependentPropertyPanes(propertyPath);
/***************************************************************************
* Handles the change of the listTitle property
***************************************************************************/
private onListTitleChange(propertyPath: string, newValue: any): void {
Log.verbose(this.logSource, "WebPart property 'listTitle' has changed, refreshing WebPart...", this.context.serviceScope);
const oldValue = get(this.properties, propertyPath);
// Stores the new value in web part properties
update(this.properties, propertyPath, (): any => { return newValue; });
// Resets the list-dependent property panes
this.resetOrderByPropertyPane();
this.resetFiltersPropertyPane();
this.resetViewFieldsPropertyPane();
// refresh web part
this.onPropertyPaneFieldChanged(propertyPath, oldValue, newValue);
}
/***************************************************************************
* Handles the change of the orderBy property
***************************************************************************/
private onOrderByChange(propertyPath: string, newValue: string): void {
Log.verbose(this.logSource, "WebPart property 'orderBy' has changed, refreshing WebPart...", this.context.serviceScope);
const oldValue = get(this.properties, propertyPath);
// Stores the new value in web part properties
update(this.properties, propertyPath, (): any => { return newValue; });
// refresh web part
this.onPropertyPaneFieldChanged(propertyPath, oldValue, newValue);
}
/***************************************************************************
* Handles the change of the filters property
***************************************************************************/
private onFiltersChange(propertyPath: string, newFilters:IQueryFilter[]) {
Log.verbose(this.logSource, "WebPart property 'filters' has changed, refreshing WebPart...", this.context.serviceScope);
const oldValue = get(this.properties, propertyPath);
// Stores the new value in web part properties
update(this.properties, propertyPath, (): any => { return newFilters; });
// refresh web part
this.onPropertyPaneFieldChanged(propertyPath, oldValue, newFilters);
}
/***************************************************************************
* Handles the change of the viewFields property
***************************************************************************/
private onViewFieldsChange(propertyPath: string, checkedKeys: string[]) {
Log.verbose(this.logSource, "WebPart property 'viewFields' has changed, refreshing WebPart...", this.context.serviceScope);
const oldValue = get(this.properties, propertyPath);
// Stores the new value in web part properties
update(this.properties, propertyPath, (): any => { return checkedKeys; });
// Updates the default template text if it hasn't been altered by the user
if(!this.properties.hasDefaultTemplateBeenUpdated) {
let generatedTemplate = this.ContentQueryService.generateDefaultTemplate(checkedKeys);
// If the viewfields have changed, update the default template text if it hasn't been altered by the user
if(propertyPath == ContentQueryConstants.propertyViewFields && !this.properties.hasDefaultTemplateBeenUpdated) {
let generatedTemplate = this.ContentQueryService.generateDefaultTemplate(newValue);
update(this.properties, ContentQueryConstants.propertyTemplateText, (): any => { return generatedTemplate; });
this.templateTextDialog.properties.dialogTextFieldValue = generatedTemplate;
this.templateTextDialog.render();
rerenderTemplateTextDialog = true;
}
// refresh web part
this.onPropertyPaneFieldChanged(propertyPath, oldValue, checkedKeys);
}
/***************************************************************************
* Handles the change of the viewFields property
***************************************************************************/
private onTemplateTextChange(propertyPath: string, text: string) {
Log.verbose(this.logSource, "WebPart property 'templateText' has changed, refreshing WebPart...", this.context.serviceScope);
const oldValue = get(this.properties, propertyPath);
// Stores the new value in web part properties
update(this.properties, propertyPath, (): any => { return text; });
// Updates the "hasDefaultTemplateBeenUpdated" to true so the WebPart doesn't override the user template after updating view fields
if(!this.properties.hasDefaultTemplateBeenUpdated) {
// If the templateText have changed, update the "hasDefaultTemplateBeenUpdated" to true so the WebPart doesn't override the user template after updating view fields
if(propertyPath == ContentQueryConstants.propertyTemplateText && !this.properties.hasDefaultTemplateBeenUpdated) {
update(this.properties, ContentQueryConstants.propertyhasDefaultTemplateBeenUpdated, (): any => { return true; });
}
// refresh web part
this.onPropertyPaneFieldChanged(propertyPath, oldValue, text);
// Refreshes the web part manually because custom fields don't update since sp-webpart-base@1.1.1
// https://github.com/SharePoint/sp-dev-docs/issues/594
if (!this.disableReactivePropertyChanges)
this.render();
if(rerenderTemplateTextDialog) {
this.templateTextDialog.render();
}
}
/***************************************************************************
* Resets dependent property panes if needed
***************************************************************************/
private resetDependentPropertyPanes(propertyPath: string): void {
if(propertyPath == ContentQueryConstants.propertyWebUrl) {
this.resetListTitlePropertyPane();
this.resetOrderByPropertyPane();
this.resetFiltersPropertyPane();
this.resetViewFieldsPropertyPane();
}
else if (propertyPath == ContentQueryConstants.propertyListTitle) {
this.resetOrderByPropertyPane();
this.resetFiltersPropertyPane();
this.resetViewFieldsPropertyPane();
}
}

View File

@ -3,11 +3,9 @@ define([], function() {
SourcePageDescription: "Specify where the WebPart should get the results from.",
QueryPageDescription: "If needed, choose the sorting behavior, limit the results, or add filters in order to narrow the query down.",
DisplayPageDescription: "Specify which fields should be available for rendering within the HandleBars template, and edit your handlebars template.",
ExternalPageDescription: "Optionally, externalize the properties below by specifying valid sharepoint urls.",
SourceGroupName: "Source",
QueryGroupName: "Query",
DisplayGroupName: "Display",
ExternalGroupName: "External Resources",
WebUrlFieldLabel: "Web Url",
WebUrlFieldPlaceholder: "Select the source web...",
WebUrlFieldLoadingLabel: "Loading webs from current site...",

View File

@ -2,11 +2,9 @@ declare interface IContentQueryStrings {
SourcePageDescription: string;
QueryPageDescription: string;
DisplayPageDescription: string;
ExternalPageDescription: string;
SourceGroupName: string;
QueryGroupName: string;
DisplayGroupName: string;
ExternalGroupName: string;
WebUrlFieldLabel: string;
WebUrlFieldPlaceholder: string;
WebUrlFieldLoadingLabel: string;

View File

@ -6,12 +6,11 @@
"jsx": "react",
"declaration": true,
"sourceMap": true,
"experimentalDecorators": true,
"types": [
"es6-promise",
"es6-collections",
"webpack-env",
"microsoft-ajax",
"sharepoint"
"webpack-env"
]
}
}

View File

@ -5,4 +5,7 @@
Code that is wrapped inside an if(UNIT_TEST) {...}
block will not be included in the final bundle when the
--ship flag is specified */
declare const UNIT_TEST: boolean;
declare const UNIT_TEST: boolean;
/* Global defintion for SPO builds */
declare const DATACENTER: boolean;