Merge remote-tracking branch 'refs/remotes/origin/dev'

This commit is contained in:
Simon-Pierre Plante 2017-07-23 21:58:28 -04:00
commit 08f8a5af71
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;