Implement multiline options support and legacy field handling in Dynamic Poll
This commit is contained in:
@@ -1,5 +1,19 @@
|
||||
import { IPoll, IPollAnswer, IPollResult } from './PollTypes';
|
||||
|
||||
export function parsePollOptionLines(values: string[]): string[] {
|
||||
const options: string[] = [];
|
||||
const seen: { [key: string]: boolean } = {};
|
||||
for (let valueIndex: number = 0; valueIndex < values.length; valueIndex++) {
|
||||
const lines: string[] = String(values[valueIndex] || '').split(/\r\n|\n|\r/);
|
||||
for (let lineIndex: number = 0; lineIndex < lines.length; lineIndex++) {
|
||||
const option: string = lines[lineIndex].trim();
|
||||
const key: string = option.toLocaleLowerCase();
|
||||
if (option && !seen[key]) { seen[key] = true; options.push(option); }
|
||||
}
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
export function selectActivePoll(polls: IPoll[], now: Date): IPoll | undefined {
|
||||
const timestamp: number = now.getTime();
|
||||
const active: IPoll[] = polls.filter((poll: IPoll): boolean =>
|
||||
@@ -34,4 +48,3 @@ export function findUserAnswer(answers: IPollAnswer[], userKey: string): string
|
||||
}
|
||||
|
||||
function dateValue(value?: Date): number { return value ? value.getTime() : 0; }
|
||||
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { SPHttpClient, SPHttpClientResponse } from '@microsoft/sp-http';
|
||||
import { WebPartContext } from '@microsoft/sp-webpart-base';
|
||||
import { calculatePollResults, findUserAnswer, selectActivePoll } from './PollCore';
|
||||
import { calculatePollResults, findUserAnswer, parsePollOptionLines, selectActivePoll } from './PollCore';
|
||||
import { IListOption, IPoll, IPollAnswer, IPollSnapshot } from './PollTypes';
|
||||
|
||||
export class PollDataService {
|
||||
private optionsFieldNames: { [listId: string]: string } = {};
|
||||
|
||||
public constructor(private context: WebPartContext) { }
|
||||
|
||||
public getLists(): Promise<IListOption[]> {
|
||||
@@ -56,19 +58,37 @@ export class PollDataService {
|
||||
}
|
||||
|
||||
private getActivePoll(listId: string): Promise<IPoll | undefined> {
|
||||
const url: string = this.webUrl + "/_api/web/lists(guid'" + this.validateGuid(listId) + "')/items" +
|
||||
'?$select=Id,Title,Question,Options,StartDate,EndDate,IsActive&$filter=IsActive eq 1&$orderby=StartDate desc&$top=100';
|
||||
return this.getJson(url).then((payload: any): IPoll | undefined => { // tslint:disable-line:no-any
|
||||
const polls: IPoll[] = this.results(payload).map((item: any): IPoll => ({ // tslint:disable-line:no-any
|
||||
id: Number(item.Id),
|
||||
title: String(item.Title || ''),
|
||||
question: String(item.Question || item.Title || ''),
|
||||
options: this.toStringArray(item.Options),
|
||||
startDate: this.toDate(item.StartDate),
|
||||
endDate: this.toDate(item.EndDate),
|
||||
isActive: item.IsActive === true || item.IsActive === 1
|
||||
}));
|
||||
return selectActivePoll(polls, new Date());
|
||||
return this.getOptionsFieldName(listId).then((optionsField: string): Promise<IPoll | undefined> => {
|
||||
const url: string = this.webUrl + "/_api/web/lists(guid'" + this.validateGuid(listId) + "')/items" +
|
||||
'?$select=Id,Title,Question,' + optionsField +
|
||||
',StartDate,EndDate,IsActive&$filter=IsActive eq 1&$orderby=StartDate desc&$top=100';
|
||||
return this.getJson(url).then((payload: any): IPoll | undefined => { // tslint:disable-line:no-any
|
||||
const polls: IPoll[] = this.results(payload).map((item: any): IPoll => ({ // tslint:disable-line:no-any
|
||||
id: Number(item.Id),
|
||||
title: String(item.Title || ''),
|
||||
question: String(item.Question || item.Title || ''),
|
||||
options: this.toStringArray(item[optionsField]),
|
||||
startDate: this.toDate(item.StartDate),
|
||||
endDate: this.toDate(item.EndDate),
|
||||
isActive: item.IsActive === true || item.IsActive === 1
|
||||
}));
|
||||
return selectActivePoll(polls, new Date());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private getOptionsFieldName(listId: string): Promise<string> {
|
||||
const cleanListId: string = this.validateGuid(listId);
|
||||
if (this.optionsFieldNames[cleanListId]) { return Promise.resolve(this.optionsFieldNames[cleanListId]); }
|
||||
const url: string = this.webUrl + "/_api/web/lists(guid'" + cleanListId + "')/fields" +
|
||||
'?$select=InternalName';
|
||||
return this.getJson(url).then((payload: any): string => { // tslint:disable-line:no-any
|
||||
const names: string[] = this.results(payload).map((field: any): string => String(field.InternalName || '')); // tslint:disable-line:no-any
|
||||
const fieldName: string = names.indexOf('OptionsText') >= 0 ? 'OptionsText' :
|
||||
(names.indexOf('Options') >= 0 ? 'Options' : '');
|
||||
if (!fieldName) { throw new Error('The poll options field is missing.'); }
|
||||
this.optionsFieldNames[cleanListId] = fieldName;
|
||||
return fieldName;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -107,9 +127,9 @@ export class PollDataService {
|
||||
return source && Array.isArray(source.results) ? source.results : [];
|
||||
}
|
||||
private toStringArray(value: any): string[] { // tslint:disable-line:no-any
|
||||
if (typeof value === 'string' && value.trim()) { return [value.trim()]; }
|
||||
const source: any[] = value && Array.isArray(value.results) ? value.results : (Array.isArray(value) ? value : []); // tslint:disable-line:no-any
|
||||
return source.map((entry: any): string => String(entry || '').trim()).filter((entry: string): boolean => !!entry); // tslint:disable-line:no-any
|
||||
const source: any[] = value && Array.isArray(value.results) ? value.results : // tslint:disable-line:no-any
|
||||
(Array.isArray(value) ? value : [value]);
|
||||
return parsePollOptionLines(source.map((entry: any): string => String(entry || ''))); // tslint:disable-line:no-any
|
||||
}
|
||||
private toDate(value: any): Date | undefined { // tslint:disable-line:no-any
|
||||
if (!value) { return undefined; }
|
||||
|
||||
Reference in New Issue
Block a user