coveo-search-ui
Version:
Coveo JavaScript Search Framework
171 lines (148 loc) • 6.29 kB
text/typescript
import { Component } from '../Base/Component';
import { ComponentOptions } from '../Base/ComponentOptions';
import { IFieldOption } from '../Base/IComponentOptions';
import { IComponentBindings } from '../Base/ComponentBindings';
import { SettingsEvents } from '../../events/SettingsEvents';
import { ISettingsPopulateMenuArgs } from '../Settings/Settings';
import { IAnalyticsNoMeta, analyticsActionCauseList } from '../Analytics/AnalyticsActionListMeta';
import { Initialization } from '../Base/Initialization';
import { l } from '../../strings/Strings';
import * as _ from 'underscore';
import { exportGlobally } from '../../GlobalExports';
import 'styling/_ExportToExcel';
import { SVGIcons } from '../../utils/SVGIcons';
import { SearchInterface } from '../SearchInterface/SearchInterface';
import { get } from '../Base/RegisteredNamedMethods';
import * as moment from 'moment';
import { IQuery } from '../../rest/Query';
let createAnchor = () => document.createElement('a');
export function setCreateAnchor(fn: () => HTMLAnchorElement) {
createAnchor = fn;
}
export interface IExportToExcelOptions {
numberOfResults?: number;
fieldsToInclude?: IFieldOption[];
}
/**
* The ExportToExcel component renders an item in the {@link Settings} menu to allow the end user to export the current
* search results to the Microsoft Excel format (.xlsx).
*
* @availablesince [November 2015 Release (v1.0.139)](https://docs.coveo.com/en/289/#november-2015-release-v10139)
*/
export class ExportToExcel extends Component {
static ID = 'ExportToExcel';
static doExport = () => {
exportGlobally({
ExportToExcel: ExportToExcel
});
};
/**
* The options for the ExportToExcel
* @componentOptions
*/
static options: IExportToExcelOptions = {
/**
* Specifies the number of results to include in the resulting Excel file.
*
* Generating and downloading the Excel file should take a reasonably short amount of time when using the default
* value. However, this amount of time will increase exponentially as you set the value higher.
*
* Consequently, you should avoid setting this value above the default index limit of 1000 search results.
*
* Note that for HIPAA organizations, the export size limit is 5 MB, and for non-HIPAA organizations, the limit is 25 MB.
*
* Default value is `100`. Minimum value is `1`.
*
* @availablesince [February 2016 Release (v1.0.318)](https://docs.coveo.com/en/309/#february-2016-release-v10318)
*/
numberOfResults: ComponentOptions.buildNumberOption({ defaultValue: 100, min: 1 }),
/**
* Specifies the fields to include in the CSV output.
*
* Note that this does not affect top level properties such as the title, clickUri, printableUri and sysUri, for example.
*
* Default value is `undefined`, meaning all fields will be exported.
*/
fieldsToInclude: ComponentOptions.buildFieldsOption()
};
/**
* Creates a new ExportToExcel component.
* @param element The HTMLElement on which to instantiate the component.
* @param options The options for the ExportToExcel component.
* @param bindings The bindings that the component requires to function normally. If not set, these will be
* automatically resolved (with a slower execution time).
* @param _window The global Window object (used to download the Excel link).
*/
constructor(
public element: HTMLElement,
public options: IExportToExcelOptions,
public bindings?: IComponentBindings,
public _window?: Window
) {
super(element, ExportToExcel.ID, bindings);
this._window = this._window || window;
this.options = ComponentOptions.initComponentOptions(element, ExportToExcel, options);
this.bind.onRootElement(SettingsEvents.settingsPopulateMenu, (args: ISettingsPopulateMenuArgs) => {
args.menuData.push({
text: l('ExportToExcel'),
className: 'coveo-export-to-excel',
tooltip: l('ExportToExcelDescription'),
onOpen: () => this.download(),
svgIcon: SVGIcons.icons.dropdownExport,
svgIconClassName: 'coveo-export-to-excel-svg'
});
});
}
/**
* Downloads the Excel representation of the current query.
*
* Also logs an `exportToExcel` event in the usage analytics.
*/
public download() {
const query = this.buildExcelQuery();
this.logger.debug("Performing query following 'Export to Excel' click");
const endpoint = this.queryController.getEndpoint();
this.usageAnalytics.logCustomEvent<IAnalyticsNoMeta>(analyticsActionCauseList.exportToExcel, {}, this.element);
endpoint.fetchBinary(query).then(content => this.downloadExcelFile(content));
}
private buildExcelQuery(): IQuery {
let query = this.queryController.getLastQuery();
query = _.omit(query, ['numberOfResults', 'fieldsToInclude']);
if (this.options.fieldsToInclude) {
query.fieldsToInclude = <string[]>this.options.fieldsToInclude;
}
return {
...query,
format: 'xlsx',
numberOfResults: this.options.numberOfResults
};
}
private downloadExcelFile(content: ArrayBuffer) {
const blob = new Blob([content], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const fileName = this.buildExcelFileName();
if (window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(blob, fileName);
return;
}
const url = URL.createObjectURL(blob);
const a = createAnchor();
a.href = url;
a.download = fileName;
a.click();
URL.revokeObjectURL(url);
}
private buildExcelFileName() {
const utc = moment().utc();
const year = utc.format('YYYY');
const month = utc.format('MM');
const day = utc.format('DD');
const hour = utc.format('HH');
const minute = utc.format('mm');
const second = utc.format('ss');
return `query--${year}-${month}-${day}--${hour}-${minute}-${second}.xlsx`;
}
static create(element: HTMLElement, options?: IExportToExcelOptions, root?: HTMLElement): ExportToExcel {
return new ExportToExcel(element, options, (<SearchInterface>get(root, SearchInterface)).getBindings());
}
}
Initialization.registerAutoCreateComponent(ExportToExcel);