Search wp updates with various new functionalities (#27)
This commit is contained in:
parent
67795ba337
commit
b3812d76c4
|
@ -22,6 +22,7 @@ react-search-wp|Elio Struyf (MVP, Ventigrate, [@eliostruyf](https://twitter.com/
|
|||
Version|Date|Comments
|
||||
-------|----|--------
|
||||
0.0.4|September 08, 2016|Initial release
|
||||
0.0.5|September 27, 2016|Updates for drop 4. Added the abilty to use various search tokens. Plus a logging field to watch search calls.
|
||||
|
||||
## Disclaimer
|
||||
**THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.**
|
||||
|
@ -44,6 +45,8 @@ The search web part is a sample client-side web part built on the SharePoint Fra
|
|||
|
||||
The web part has built in templating support for internal (created within the project) and external (loaded from a URL) templates.
|
||||
|
||||
When adding your query you are able to make use of the following tokens: {Today}, {Today+Number}, {Today-Number}, {CurrentDisplayLanguage}, {User}, {User.Name}, {User.Email}, {Site}, {SiteCollection}.
|
||||
|
||||
**Internal templates**
|
||||
|
||||
Internal templates can be found in the [templates]('./src/webparts/templates') folder. You can start building your own templates by using one of the provided samples.
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
{
|
||||
"name": "search-wp-spfx",
|
||||
"version": "0.0.4",
|
||||
"version": "0.0.5",
|
||||
"private": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@microsoft/sp-client-base": "~0.2.0",
|
||||
"@microsoft/sp-client-preview": "~0.2.0",
|
||||
"@microsoft/sp-client-base": "~0.3.0",
|
||||
"@microsoft/sp-client-preview": "~0.4.0",
|
||||
"flux": "^2.1.1",
|
||||
"moment": "^2.14.1",
|
||||
"office-ui-fabric-react": "0.36.0",
|
||||
|
@ -15,9 +15,9 @@
|
|||
"react-dom": "0.14.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@microsoft/sp-build-web": "~0.5.0",
|
||||
"@microsoft/sp-module-interfaces": "~0.2.0",
|
||||
"@microsoft/sp-webpart-workbench": "~0.2.0",
|
||||
"@microsoft/sp-build-web": "~0.6.0",
|
||||
"@microsoft/sp-module-interfaces": "~0.3.0",
|
||||
"@microsoft/sp-webpart-workbench": "~0.4.0",
|
||||
"expose-loader": "^0.7.1",
|
||||
"gulp": "~3.9.1"
|
||||
},
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
export interface IPropertyPaneLoggingFieldProps {
|
||||
label?: string;
|
||||
description?: string;
|
||||
value: any;
|
||||
retrieve?: Function;
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
import * as React from 'react';
|
||||
import * as ReactDom from 'react-dom';
|
||||
|
||||
import {
|
||||
IPropertyPaneField,
|
||||
IPropertyPaneFieldType
|
||||
} from '@microsoft/sp-client-preview';
|
||||
|
||||
import { IPropertyPaneLoggingFieldProps } from './IPropertyPaneLoggingFieldProps';
|
||||
import PropertyPaneLoggingFieldHost, { IPropertyPaneLoggingFieldHostProps } from './PropertyPaneLoggingFieldHost';
|
||||
|
||||
export interface IPropertyPaneLoggingFieldPropsInternal extends IPropertyPaneLoggingFieldProps {
|
||||
onRender(elem: HTMLElement): void;
|
||||
onDispose(elem: HTMLElement): void;
|
||||
}
|
||||
|
||||
class PropertyPaneLoggingFieldBuilder implements IPropertyPaneField<IPropertyPaneLoggingFieldPropsInternal> {
|
||||
// Properties defined by IPropertyPaneField
|
||||
public type: IPropertyPaneFieldType = IPropertyPaneFieldType.Custom;
|
||||
public targetProperty: string = undefined;
|
||||
public properties: IPropertyPaneLoggingFieldPropsInternal;
|
||||
|
||||
// Logging properties
|
||||
private label: string;
|
||||
private description: string;
|
||||
private value: any;
|
||||
private retrieve: Function;
|
||||
|
||||
public constructor(props: IPropertyPaneLoggingFieldPropsInternal) {
|
||||
this.properties = props;
|
||||
this.properties.onDispose = this.dispose;
|
||||
this.properties.onRender = this.render;
|
||||
|
||||
this.label = props.label;
|
||||
this.value = props.value;
|
||||
this.description = props.description;
|
||||
this.retrieve = props.retrieve;
|
||||
}
|
||||
|
||||
/**
|
||||
* @function
|
||||
* Render the logging element
|
||||
*/
|
||||
private render(elm: HTMLElement): void {
|
||||
// Construct the JSX properties
|
||||
const element: React.ReactElement<IPropertyPaneLoggingFieldHostProps> = React.createElement(PropertyPaneLoggingFieldHost, {
|
||||
label: this.label,
|
||||
value: this.value,
|
||||
description: this.description,
|
||||
retrieve: this.retrieve,
|
||||
onDispose: this.dispose,
|
||||
onRender: this.render
|
||||
});
|
||||
|
||||
// Calls the REACT content generator
|
||||
ReactDom.render(element, elm);
|
||||
}
|
||||
|
||||
/**
|
||||
* @function
|
||||
* Disposes the current object
|
||||
*/
|
||||
private dispose(elem: HTMLElement): void {}
|
||||
}
|
||||
|
||||
|
||||
export function PropertyPaneLoggingField(properties: IPropertyPaneLoggingFieldProps): IPropertyPaneField<IPropertyPaneLoggingFieldPropsInternal> {
|
||||
// Create an internal properties object from the given properties
|
||||
var newProperties: IPropertyPaneLoggingFieldPropsInternal = {
|
||||
label: properties.label,
|
||||
description: properties.description,
|
||||
value: properties.value,
|
||||
retrieve: properties.retrieve,
|
||||
onDispose: null,
|
||||
onRender: null
|
||||
};
|
||||
|
||||
// Calles the PropertyPaneLoggingField builder object
|
||||
// This object will simulate a PropertyFieldCustom to manage his rendering process
|
||||
return new PropertyPaneLoggingFieldBuilder(newProperties);
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
import * as React from 'react';
|
||||
import { IPropertyPaneLoggingFieldPropsInternal } from './PropertyPaneLoggingField';
|
||||
import { Label } from 'office-ui-fabric-react/lib/Label';
|
||||
|
||||
require('./PropertyPaneLoggingFieldStyling.css');
|
||||
|
||||
/**
|
||||
* @interface
|
||||
* PropertyPaneLoggingFieldHost properties interface
|
||||
*
|
||||
*/
|
||||
export interface IPropertyPaneLoggingFieldHostProps extends IPropertyPaneLoggingFieldPropsInternal {}
|
||||
|
||||
/**
|
||||
* @interface
|
||||
* PropertyPaneLoggingFieldHost state interface
|
||||
*
|
||||
*/
|
||||
export interface IPropertyPaneLoggingFieldState {
|
||||
logging?: any[];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @class
|
||||
* Renders the controls for PropertyPaneLoggingField component
|
||||
*/
|
||||
export default class PropertyPaneLoggingFieldHost extends React.Component<IPropertyPaneLoggingFieldHostProps, IPropertyPaneLoggingFieldState> {
|
||||
|
||||
/**
|
||||
* @function
|
||||
* Contructor
|
||||
*/
|
||||
constructor(props: IPropertyPaneLoggingFieldHostProps) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
logging: []
|
||||
};
|
||||
this.getLogging = this.getLogging.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @function
|
||||
* componentDidMount
|
||||
*/
|
||||
public componentDidMount(): void {
|
||||
this.setState({
|
||||
logging: this.props.value
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @function
|
||||
* Retrieve new logging value
|
||||
*/
|
||||
private getLogging() {
|
||||
this.setState({
|
||||
logging: this.props.retrieve()
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @function
|
||||
* Renders the key values
|
||||
*/
|
||||
private renderValue(val: any, subClass?: string) {
|
||||
const output = [];
|
||||
for (const k in val) {
|
||||
if (typeof val[k] === "object") {
|
||||
output.push(<div key={k} className={subClass}><span className="keyValue">{k}</span>: object {this.renderValue(val[k], "subElm")}</div>);
|
||||
} else {
|
||||
output.push(<div key={k} className={subClass}><span className="keyValue">{k}</span>: {val[k]}</div>);
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @function
|
||||
* Renders the logging field control
|
||||
*/
|
||||
public render(): JSX.Element {
|
||||
const valToRender = this.renderValue(this.state.logging);
|
||||
//Renders content
|
||||
return (
|
||||
<div className="loggingField">
|
||||
<Label>{this.props.label}</Label>
|
||||
{
|
||||
(() => {
|
||||
if (typeof this.props.retrieve !== 'undefined') {
|
||||
return <div className="updateLogging"><a className="ms-Link" onClick={this.getLogging}>Update logging</a></div>;
|
||||
}
|
||||
})()
|
||||
}
|
||||
<pre className="logging">{valToRender}</pre>
|
||||
{
|
||||
(() => {
|
||||
if (typeof this.props.description !== 'undefined') {
|
||||
return <span className="ms-TextField-description">{this.props.description}</span>;
|
||||
}
|
||||
})()
|
||||
}
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
.loggingField {
|
||||
margin: 0 0 85px 0;
|
||||
|
||||
pre.logging {
|
||||
border: 1px solid #c8c8c8;
|
||||
margin: 0;
|
||||
max-height: 250px;
|
||||
overflow: auto;
|
||||
padding: 6px;
|
||||
white-space: initial;
|
||||
word-break: break-all;
|
||||
|
||||
div {
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.subElm {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.keyValue {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.updateLogging {
|
||||
margin-bottom: 2px;
|
||||
margin-top: -22px;
|
||||
text-align: right;
|
||||
|
||||
a.ms-Link {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,6 +10,8 @@ import {
|
|||
PropertyPaneToggle
|
||||
} from '@microsoft/sp-client-preview';
|
||||
|
||||
import { PropertyPaneLoggingField } from './PropertyPaneControls/PropertyPaneLoggingField';
|
||||
|
||||
import ModuleLoader from '@microsoft/sp-module-loader';
|
||||
|
||||
import * as strings from 'mystrings';
|
||||
|
@ -19,15 +21,24 @@ import { IExternalTemplate, IScripts, IStyles } from './utils/ITemplates';
|
|||
import { defer, IDeferred } from './utils/defer';
|
||||
import { allTemplates } from './templates/TemplateLoader';
|
||||
|
||||
// Import the search store, needed for logging the search requests
|
||||
import searchStore from './flux/stores/searchStore';
|
||||
|
||||
// Expose React to window -> required for external template loading
|
||||
require("expose?React!react");
|
||||
|
||||
export default class SearchSpfxWebPart extends BaseClientSideWebPart<ISearchSpfxWebPartProps> {
|
||||
private crntExternalTemplateUrl: string = "";
|
||||
private crntExternalTemplate: IExternalTemplate = null;
|
||||
private onChangeBinded: boolean = false;
|
||||
private removeChangeBinding: NodeJS.Timer = null;
|
||||
|
||||
public constructor(context: IWebPartContext) {
|
||||
super(context);
|
||||
|
||||
// Bind this to the setLogging method
|
||||
this.setLogging = this.setLogging.bind(this);
|
||||
this.removeLogging = this.removeLogging.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -159,6 +170,41 @@ export default class SearchSpfxWebPart extends BaseClientSideWebPart<ISearchSpfx
|
|||
}
|
||||
}
|
||||
|
||||
protected onPropertyPaneRendered(): void {
|
||||
// Clear remove binding timeout. This is necessary if user applied a new configuration.
|
||||
if (this.removeChangeBinding !== null) {
|
||||
clearTimeout(this.removeChangeBinding);
|
||||
this.removeChangeBinding = null;
|
||||
}
|
||||
// Check if there is a change binding in place
|
||||
if (!this.onChangeBinded) {
|
||||
this.onChangeBinded = true;
|
||||
searchStore.addChangeListener(this.setLogging);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Will probably be renamed to onPropertyConfigurationComplete in the next drop
|
||||
protected onPropertyPaneConfigurationComplete() {
|
||||
// Remove the change binding
|
||||
this.removeChangeBinding = setTimeout(this.removeLogging, 500);
|
||||
}
|
||||
|
||||
// protected onPropertyPaneConfigurationStart() {
|
||||
// // Will probably be deleted in the next drop
|
||||
// console.log('onPropertyPaneConfigurationStart');
|
||||
// }
|
||||
|
||||
// protected onAfterPropertyPaneChangesApplied() {
|
||||
// // Will probably be deleted in the next drop
|
||||
// console.log('onAfterPropertyPaneChangesApplied');
|
||||
// }
|
||||
|
||||
// Will probably be added in the next drop
|
||||
// protected onPropertyPaneSave() {
|
||||
// console.log('onPropertyPaneSave');
|
||||
// }
|
||||
|
||||
/**
|
||||
* Property pane settings
|
||||
*/
|
||||
|
@ -200,17 +246,57 @@ export default class SearchSpfxWebPart extends BaseClientSideWebPart<ISearchSpfx
|
|||
}),
|
||||
PropertyPaneTextField('sorting', {
|
||||
label: strings.FieldsSorting
|
||||
}),
|
||||
})
|
||||
]
|
||||
}, {
|
||||
groupName: strings.TemplateGroupName,
|
||||
groupFields: [
|
||||
PropertyPaneToggle('external', {
|
||||
label: strings.FieldsExternalLabel
|
||||
}),
|
||||
templateProperty
|
||||
]
|
||||
}]
|
||||
}, {
|
||||
groupName: strings.LoggingGroupName,
|
||||
groupFields: [
|
||||
PropertyPaneLoggingField({
|
||||
label: strings.LoggingFieldLabel,
|
||||
description: strings.LoggingFieldDescription,
|
||||
value: searchStore.getLoggingInfo(),
|
||||
retrieve: this.getLogging
|
||||
})
|
||||
]
|
||||
}],
|
||||
displayGroupsAsAccordion: true
|
||||
}]
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to retrieve the logging value from the store
|
||||
*/
|
||||
private getLogging(): any {
|
||||
return searchStore.getLoggingInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to refresh the property pane when a change is retrieved from the store
|
||||
*/
|
||||
private setLogging(): void {
|
||||
// Refresh the property pane when search rest call is completed
|
||||
this.configureStart(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to remove the change binding when property pane is closed
|
||||
*/
|
||||
private removeLogging(): void {
|
||||
if (this.onChangeBinded) {
|
||||
this.onChangeBinded = false;
|
||||
searchStore.removeChangeListener(this.setLogging);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent from changing the query on typing
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
import { IWebPartContext } from '@microsoft/sp-client-preview';
|
||||
import { IPageContext } from '../../utils/IPageContext';
|
||||
|
||||
import * as moment from 'moment';
|
||||
|
||||
declare const _spPageContextInfo: IPageContext;
|
||||
|
||||
export default class SearchTokenHelper {
|
||||
private regexVal: RegExp = /\{[^\{]*?\}/gi;
|
||||
|
||||
constructor() {}
|
||||
|
||||
public replaceTokens(restUrl: string, context: IWebPartContext): string {
|
||||
const tokens = restUrl.match(this.regexVal);
|
||||
|
||||
if (tokens !== null && tokens.length > 0) {
|
||||
tokens.forEach((token) => {
|
||||
// Check which token has been retrieved
|
||||
if (token.toLowerCase().indexOf('today') !== -1) {
|
||||
const dateValue = this.getDateValue(token);
|
||||
restUrl = restUrl.replace(token, dateValue);
|
||||
}
|
||||
else if (token.toLowerCase().indexOf('user') !== -1) {
|
||||
const userValue = this.getUserValue(token, context);
|
||||
restUrl = restUrl.replace(token, userValue);
|
||||
}
|
||||
else {
|
||||
switch (token.toLowerCase()) {
|
||||
case "{site}":
|
||||
restUrl = restUrl.replace(/{site}/ig, context.pageContext.web.absoluteUrl);
|
||||
break;
|
||||
case "{sitecollection}":
|
||||
restUrl = restUrl.replace(/{sitecollection}/ig, _spPageContextInfo.siteAbsoluteUrl);
|
||||
break;
|
||||
case "{currentdisplaylanguage}":
|
||||
restUrl = restUrl.replace(/{currentdisplaylanguage}/ig, context.pageContext.cultureInfo.currentCultureName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return restUrl;
|
||||
}
|
||||
|
||||
private getDateValue(token: string): string {
|
||||
let dateValue = moment();
|
||||
// Check if we need to add days
|
||||
if (token.toLowerCase().indexOf("{today+") !== -1) {
|
||||
const daysVal = this.getDaysVal(token);
|
||||
dateValue = dateValue.add(daysVal, 'day');
|
||||
}
|
||||
// Check if we need to subtract days
|
||||
if (token.toLowerCase().indexOf("{today-") !== -1) {
|
||||
const daysVal = this.getDaysVal(token);
|
||||
dateValue = dateValue.subtract(daysVal, 'day');
|
||||
}
|
||||
return dateValue.format('YYYY-MM-DD');
|
||||
}
|
||||
|
||||
private getDaysVal(token: string): number {
|
||||
const tmpDays: string = token.substring(7, token.length - 1);
|
||||
return parseInt(tmpDays) || 0;
|
||||
}
|
||||
|
||||
private getUserValue(token: string, context: IWebPartContext): string {
|
||||
let userValue = '"' + context.pageContext.user.displayName + '"';
|
||||
|
||||
if (token.toLowerCase().indexOf("{user.") !== -1) {
|
||||
const propVal = token.toLowerCase().substring(6, token.length - 1);
|
||||
switch (propVal) {
|
||||
case "name":
|
||||
userValue = '"' + context.pageContext.user.displayName + '"';
|
||||
break;
|
||||
case "email":
|
||||
userValue = context.pageContext.user.email;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return userValue;
|
||||
}
|
||||
}
|
|
@ -1,17 +1,17 @@
|
|||
import appDispatcher from '../dispatcher/appDispatcher';
|
||||
import searchActionIDs from '../actions/searchActionIDs';
|
||||
import SearchTokenHelper from '../helpers/SearchTokenHelper';
|
||||
import { EventEmitter } from 'events';
|
||||
|
||||
import { IWebPartContext } from '@microsoft/sp-client-preview';
|
||||
import { ISearchResults, ICells, ICellValue } from '../../utils/ISearchResults';
|
||||
import { IPageContext } from '../../utils/IPageContext';
|
||||
|
||||
declare const _spPageContextInfo: IPageContext;
|
||||
|
||||
const CHANGE_EVENT: string = 'change';
|
||||
|
||||
export class SearchStoreStatic extends EventEmitter {
|
||||
private _results: any[] = [];
|
||||
private _url: string;
|
||||
private _response: any;
|
||||
|
||||
/**
|
||||
* @param {function} callback
|
||||
|
@ -36,8 +36,8 @@ export class SearchStoreStatic extends EventEmitter {
|
|||
}
|
||||
|
||||
public setSearchResults(crntResults: ICells[], fields: string): void {
|
||||
const flds: string[] = fields.toLowerCase().split(',');
|
||||
if (crntResults.length > 0) {
|
||||
const flds: string[] = fields.toLowerCase().split(',');
|
||||
const temp: any[] = [];
|
||||
crntResults.forEach((result) => {
|
||||
// Create a temp value
|
||||
|
@ -73,19 +73,6 @@ export class SearchStoreStatic extends EventEmitter {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} query
|
||||
*/
|
||||
public ReplaceTokens (query: string, context: IWebPartContext): string {
|
||||
if (query.toLowerCase().indexOf("{site}") !== -1) {
|
||||
query = query.replace(/{site}/ig, context.pageContext.web.absoluteUrl);
|
||||
}
|
||||
if (query.toLowerCase().indexOf("{sitecollection}") !== -1) {
|
||||
query = query.replace(/{sitecollection}/ig, _spPageContextInfo.siteAbsoluteUrl);
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
*/
|
||||
|
@ -99,6 +86,18 @@ export class SearchStoreStatic extends EventEmitter {
|
|||
public isNull (value: any): boolean {
|
||||
return value === null || typeof value === "undefined";
|
||||
}
|
||||
|
||||
public setLoggingInfo(url: string, response: any) {
|
||||
this._url = url;
|
||||
this._response = response;
|
||||
}
|
||||
|
||||
public getLoggingInfo(): any {
|
||||
return {
|
||||
URL: this._url,
|
||||
Response: this._response
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const searchStore: SearchStoreStatic = new SearchStoreStatic();
|
||||
|
@ -106,9 +105,10 @@ const searchStore: SearchStoreStatic = new SearchStoreStatic();
|
|||
appDispatcher.register((action) => {
|
||||
switch (action.actionType) {
|
||||
case searchActionIDs.SEARCH_GET:
|
||||
const tokenHelper = new SearchTokenHelper();
|
||||
let url: string = action.context.pageContext.web.absoluteUrl + "/_api/search/query?querytext=";
|
||||
// Check if a query is provided
|
||||
url += !searchStore.isEmptyString(action.query) ? `'${searchStore.ReplaceTokens(action.query, action.context)}'` : "'*'";
|
||||
url += !searchStore.isEmptyString(action.query) ? `'${tokenHelper.replaceTokens(action.query, action.context)}'` : "'*'";
|
||||
// Check if there are fields provided
|
||||
url += '&selectproperties=';
|
||||
url += !searchStore.isEmptyString(action.fields) ? `'${action.fields}'` : "'path,title'";
|
||||
|
@ -121,20 +121,28 @@ appDispatcher.register((action) => {
|
|||
url += "&clienttype='ContentSearchRegular'";
|
||||
|
||||
searchStore.GetSearchData(action.context, url).then((res: ISearchResults) => {
|
||||
searchStore.setLoggingInfo(url, res);
|
||||
let resultsRetrieved = false;
|
||||
if (res !== null) {
|
||||
if (typeof res.PrimaryQueryResult !== 'undefined') {
|
||||
if (typeof res.PrimaryQueryResult.RelevantResults !== 'undefined') {
|
||||
if (typeof res.PrimaryQueryResult.RelevantResults !== 'undefined') {
|
||||
if (typeof res.PrimaryQueryResult.RelevantResults.Table !== 'undefined') {
|
||||
if (typeof res.PrimaryQueryResult.RelevantResults.Table.Rows !== 'undefined') {
|
||||
resultsRetrieved = true;
|
||||
searchStore.setSearchResults(res.PrimaryQueryResult.RelevantResults.Table.Rows, action.fields);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reset the store its search result set on error
|
||||
if (!resultsRetrieved) {
|
||||
searchStore.setSearchResults([], null);
|
||||
}
|
||||
searchStore.emitChange();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
break;
|
||||
|
|
|
@ -8,8 +8,12 @@ define([], function() {
|
|||
"FieldsTemplateLabel": "Choose the template you want to use for rendering the results",
|
||||
"FieldsMaxResults": "Number of results to render",
|
||||
"FieldsSorting": "Sorting (MP:ascending or descending) - example: lastmodifiedtime:ascending,author:descending",
|
||||
"QueryInfoDescription": "You can make use of following tokens: {Site} - {SiteCollection}",
|
||||
"QueryInfoDescription": "You can make use of following tokens: {Site} - {SiteCollection} - {Today} or {Today+NR} or {Today-NR} - {CurrentDisplayLanguage} - {User}, {User.Name}, {User.Email}",
|
||||
"FieldsExternalLabel": "Do you want to use an external template?",
|
||||
"FieldsExternalTempLabel": "Specify the URL of the external template"
|
||||
"FieldsExternalTempLabel": "Specify the URL of the external template",
|
||||
"TemplateGroupName": "Template settings",
|
||||
"LoggingGroupName": "Logging pane",
|
||||
"LoggingFieldLabel": "Logging search API calls",
|
||||
"LoggingFieldDescription": "This field logs all search API calls"
|
||||
}
|
||||
});
|
|
@ -10,6 +10,10 @@ declare interface IStrings {
|
|||
QueryInfoDescription: string;
|
||||
FieldsExternalLabel: string;
|
||||
FieldsExternalTempLabel: string;
|
||||
TemplateGroupName: string;
|
||||
LoggingGroupName: string;
|
||||
LoggingFieldLabel: string;
|
||||
LoggingFieldDescription: string;
|
||||
}
|
||||
|
||||
declare module 'mystrings' {
|
||||
|
|
Loading…
Reference in New Issue