When CRUD is applied, DataViews communicates with the server when you edit an item.
Sending a server request every time you edit an item is a waste of server bandwidth and performance. The more economic way is to send a request to the server once after a series of local edits.
DataViews supports batch edit, which allows you to send a single request that consists of multiple actions.
To apply batch editing, set dataSource.batchEdit = true. Once batch edit mode is set, update and create item actions are only applied locally. To save changes, use dataView.saveBatchEdit(). After that, dataSource.batch(params) is used to allow you to send a request, such as CRUD. To cancel batch edit and remove cached edits, use dataView.cancelBatchEdit().
The params contain: [Array] actions, which is the cache of all locally applied actions of create, update, and delete.
Try using CRUD actions in the grid and then save or cancel the changes using the buttons above the grid.
This demo calls some API items from the internet, make sure your internet connection is working and runing this demo with HTTP or HTTPS protocol.
<!DOCTYPE html>
<html lang="en">
<head>
<base href="/dataviewsjs/demos/en/sample/Features/Editing/BatchEdit/vue/" />
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="keywords" content="crud" />
<meta
name="description"
content="DataViews supports batch edit, which allows you to send a single request that consists of multiple actions."
/>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Batch Edit | Features | MESCIUS DataViewsJS Vue Demos</title>
<link href="/dataviewsjs/demos/node_modules/normalize.css/normalize.css" rel="stylesheet" type="text/css" />
<link href="/dataviewsjs/demos/static/css/base.css" rel="stylesheet" type="text/css" />
<link href="/dataviewsjs/demos/static/css/bootstrap-snippet.min.css" rel="stylesheet" type="text/css" />
<link
href="/dataviewsjs/demos/node_modules/@fortawesome/fontawesome-free/css/all.min.css"
rel="stylesheet"
type="text/css"
/>
<link href="/dataviewsjs/demos/static/css/pageui.css" rel="stylesheet" type="text/css" />
<link href="/dataviewsjs/demos/static/dataviews/gc.dataviews.core.min.css" rel="stylesheet" type="text/css" />
<link href="/dataviewsjs/demos/static/dataviews/gc.dataviews.grid.min.css" rel="stylesheet" type="text/css" />
<link href="styles.css" rel="stylesheet" type="text/css" />
<script src="/dataviewsjs/demos/static/js/app-polyfills.min.js" type="text/javascript"></script>
<script type="text/javascript">
window.process = {
env: {
NODE_ENV: 'production',
USE_NPM: false,
USE_CDN: false,
SITE_ROOT: '/dataviewsjs/demos',
FRAMEWORK: 'vue',
DVJS_LICENSE_KEY:
'E348418822993781#B0EWvwY4dNNVQqJHUDpFROVWe5ZWNYFlVQFmRsJWRht4Z6lDO4Vla7YUaXhEWxd7Z5YXMuRnY7tWTQRHSlVnaYlXNhlEOpdkZ0FHWYJ5QKd6VXN5aR3ieGhUav9kZTBXWahkYBhEVutmZ72CbjdlZvV5TVdGdiplQsZXe95kUmNmZVF5cJ3mcypWNyx4UydESE3UblxGZyE7KQ94R4BjbUxUewsiaoREMxRDNllWREV6Voh4Q4dDZPRjWrIzUJl4TERXcQZWMHp4Sp9WaMZzN5o6StJmVDJXcwIVVmR6UMVGOlxUW8RmTxZDZTJWVN5GZqJHZuVDMkVGSW3WdxNzKCdDdSB7TzY7cqlnMU5GVyNzNP9WMyhDRvEEOFdkQORDM4dFVlFFWqFWSyMjNQJiOiMlIsISQyIkQ9YjQxIiOigkIsUTM7YjNxYTM0IicfJye&Qf35VfikFVVljI0IyQiwiIxYHITp4c7VWaWFGdhRkI0IiTis7W0ICZyBlIsIiNxUTN6ADI8EDMxMjMwIjI0ICdyNkIsIyc59yc5l6YzVWbuoCLwpmLzVXajNXZt9iKs2WauMXdpN6cl5mLqwSbvNmLzVXajNXZt9iKsAnau26YuMXdpN6cl5mLqwSbvNmL6VGZ9RXajVGchJ7ZuoCLuNmLt36YukHdpNWZwFmcn9iKs46bj9Se4l6YlBXYydmLqwicr9ybj9Se4l6YlBXYydmLqwCcq9ybj9Se4l6YlBXYydmLqIiOiMXbEJCLiMVVJN4UF5kI0ISYONkIsUWdyRnOiwmdFJCLiEDO7MTO9IjM8gTM4gDNzIiOiQWSisnOiQkIsISP3EkVxBVUHFDMplzLlVUdGd7cI9UeIt4SshESzV7NvY7ZxlDOuNTb5tzLr',
SJS_LICENSE_KEY:
'E518585142165236#B0wm4nx4QzdlTHRTSOFzcvVnaJdjSnNEeXdTMUtSUzk6bU94QuVXNwZVZjd4SzYjcadXRIVEMzEXTThkVyR7R85UayoHZZBTYQ5mZyh4Shd6VxFXazF4cBNGRG5WTvUGTsV4T6knQYRzKxxUdk9EarplU7d6VLF6KIR7bPJ5N6ZUMWZWaURGRKRDbLJDN5YjSN5mUoxmaxonSD56LEh7Y7RXenpmTvomevZlV9dkaysCO7hTRQFHcGRWQyc5LI9kQmB7QwR4Z7ZHOR3CSXp6SiFWYzFXeXZUSp94K8VDTkFjdwl4KptSYlRWcDxmNE5kS6kzdrkVcNJXROVGbLJkcTNGRzIER8tmd4YGNhh7dxAnMvIHRv46VtBXS4U5KvJ6dZJ6M5p4TxIjd9I5QSpXTTV6SDZXb7lzaL56ZiojITJCLikTQxUTQFV4NiojIIJCLyETO7UzM7kTO0IicfJye&Qf35VfikkR9IkI0IyQiwiIyEjL6ByUKBCZhVmcwNlI0IiTis7W0ICZyBlIsISNwkTN6ADI8EDMxMjMwIjI0ICdyNkIsIyc59yc5l6YzVWbuoCLwpmLzVXajNXZt9iKs2WauMXdpN6cl5mLqwSbvNmLzVXajNXZt9iKsAnau26YuMXdpN6cl5mLqwSbvNmL6VGZ9RXajVGchJ7ZuoCLuNmLt36YukHdpNWZwFmcn9iKs46bj9Se4l6YlBXYydmLqwicr9ybj9Se4l6YlBXYydmLqwCcq9ybj9Se4l6YlBXYydmLqIiOiMXbEJCLiMVVJN4UF5kI0ISYONkIsUWdyRnOiwmdFJCLiYzMyUjNxIDNxUDO5gTM5IiOiQWSiwSfdtlOicGbmJCLlNHbhZmOiI7ckJye0ICbuFkI1pjIEJCLi4TPRtGOhtWWEFWd4IDOLRVRvx4SyMGcDhTW6n4ep',
},
};
</script>
<script src="/dataviewsjs/demos/node_modules/jquery/dist/jquery.min.js" type="text/javascript"></script>
<script src="/dataviewsjs/demos/static/js/batchjs.js" type="text/javascript"></script>
<script src="/dataviewsjs/demos/static/js/license.js" type="text/javascript"></script>
<script src="/dataviewsjs/demos/node_modules/systemjs/dist/system.js" type="text/javascript"></script>
<script src="systemjs.config.js" type="text/javascript"></script>
</head>
<body class="theme-default">
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script type="text/javascript">
System.import('./app.vue');
</script>
</body>
</html>
<script>
import Vue from 'vue';
import { getControlByElement } from '@grapecity/dataviews.vue';
import { GridLayout } from '@grapecity/dataviews.grid';
import './pager.vue';
import { dataSource } from './data';
import locale from './locale';
const cols = [
{
id: 'id',
caption: 'Order Id',
dataField: 'Transaction_Id',
dataType: 'number',
allowEditing: false,
width: 80,
},
{
id: 'product',
caption: 'Product',
dataField: 'Product',
width: 290,
},
{
id: 'price',
caption: 'Price',
dataField: 'Price',
dataType: 'number',
width: 60,
},
{
id: 'quantity',
caption: 'Qty',
dataField: 'Quantity',
dataType: 'number',
width: 55,
},
{
id: 'name',
caption: 'Name',
dataField: 'Name',
width: 135,
},
{
id: 'country',
caption: 'Country',
dataField: 'Country',
width: 120,
},
{
id: 'detail',
caption: 'Detail',
dataField: 'Product_Detail',
width: '*',
minWidth: 445,
},
{
id: 'editCol',
width: 75,
action: [
{
name: 'edit',
presenter: '<button class="edit-btn action-btn" data-action="edit"><span class="edit-icon"></span></button>',
handler: startEditing,
},
{
name: 'save',
presenter:
'<button class="save-btn action-btn" data-action="save" style="display:none;"><span class="save-icon"></span></button>',
handler: saveEdit,
},
{
name: 'cancel',
presenter:
'<button class="cancel-btn action-btn" data-action="cancel" style="display:none;"><span class="cancel-icon"></span></button>',
handler: cancelEdit,
},
],
},
{
id: 'deleteCol',
width: 50,
action: [
{
name: 'delete',
presenter: '<button class="delete-btn action-btn" data-action="delete"><span>✖</span></button>',
handler: deleteItem,
},
],
},
];
const layout = new GridLayout({
colWidth: 80,
showRowHeader: true,
rowHeight: 36,
showColHeader: true,
pageSize: 9,
allowEditing: true,
autoAddRowPosition: 'top',
headerRow: {
visible: true,
height: 40,
separateColumn: false,
position: 'above',
renderer: `
<button id="btnAddNew" class="btn btn-sm">
<span class="add-icon"></span>
<span>${locale.addNew}</span>
</button>`,
},
});
function getDataView() {
return getControlByElement(document.body);
}
// action column handlers
function startEditing(args) {
const dataView = getDataView();
const hitInfo = args.hitInfo;
const elementId = dataView.getRowId(hitInfo);
if (!dataView.isEditing) {
const row = $(`#${elementId}`);
row.find('[data-action="save"]').css('display', 'inline-block');
row.find('[data-action="cancel"]').css('display', 'inline-block');
row.find('[data-action="edit"]').css('display', 'none');
row.find('[data-action="delete"]').css('display', 'none');
dataView.startEditing();
}
}
function saveEdit() {
getDataView().stopEditing();
}
function cancelEdit() {
getDataView().cancelEditing();
}
function deleteItem(args) {
const dataView = getDataView();
const rowId = dataView.getRowId(args.hitInfo);
const dataItem = dataView.getItem(rowId);
if (dataItem && dataItem.item) {
const sourceIndex = dataItem.item.sourceIndex;
if (sourceIndex >= 0) {
dataView.data.removeDataItems(sourceIndex);
}
}
}
function addNewRow() {
const dataView = getDataView();
if (!dataView.isEditing) {
dataView.options.allowAutoAddRow = true;
dataView.invalidate();
const autoRow = $(`#${dataView.uid}-autorow`);
autoRow.find('[data-action="save"]').css('display', 'inline-block');
autoRow.find('[data-action="cancel"]').css('display', 'inline-block');
autoRow.find('[data-action="edit"]').css('display', 'none');
autoRow.find('[data-action="delete"]').css('display', 'none');
dataView.startEditing(0);
}
}
new Vue({
el: '#root',
template: `<div class="main-container" v-on:click="handleClick">
<div class="sample-options">
<div class="btn-group">
<button id="save-changes" class="btn btn-default" v-on:click="saveChanges">
{{locale.saveChanges}}
</button>
<button id="cancel-changes" class="btn btn-default" v-on:click="cancelChanges">
{{locale.cancelChanges}}
</button>
</div>
</div>
<gc-dataview
id="grid"
class="grid"
:data="data"
:cols="cols"
:layout="layout"
v-on:editing="handleEditing"
v-on:beforeloadrange="beforeLoadRange"
/>
<pager />
</div>`,
data: { locale, data: dataSource, cols, layout },
methods: {
saveChanges() {
getDataView().saveBatchEdit();
},
cancelChanges() {
getDataView().cancelBatchEdit();
},
handleEditing(args) {
if ((args.status === 'endEditing' && args.isNewRow) || args.status === 'cancelEditing') {
const dataView = getDataView();
if (dataView.options.allowAutoAddRow) {
dataView.options.allowAutoAddRow = false;
dataView.invalidate();
}
}
},
beforeLoadRange(args) {
const dataView = getDataView();
const cachedActions = dataView.getCachedBatchActions();
if (cachedActions) {
alert(locale.navError);
args.cancel = true;
}
},
handleClick(e) {
let target = e.target;
while (target) {
if ($(target).is('#btnAddNew')) {
addNewRow();
break;
}
target = target.parentNode;
}
},
},
});
</script>
import locale from './locale';
const API_ROOT = `${process.env.SITE_ROOT}/remotedata/api`;
function buildRequests(actions) {
const result = [];
let i;
let len;
let action;
let actionType;
let dataItem;
for (i = 0, len = actions.length; i < len; i++) {
action = actions[i];
actionType = action.type;
dataItem = action.dataItem;
if (actionType === 'update') {
result.push({
type: 'PUT',
url: `${API_ROOT}/records/${dataItem.Transaction_Id}`,
data: dataItem,
});
} else if (actionType === 'delete') {
result.push({
type: 'DELETE',
url: `${API_ROOT}/records/${dataItem.Transaction_Id}`,
});
} else if (actionType === 'create') {
result.push({
type: 'POST',
url: `${API_ROOT}/records`,
data: dataItem,
});
}
}
return result;
}
function getRecords(start, count) {
return `${API_ROOT}/records`;
}
const parseBatchResponse = function (responseData) {
// response of batch edit should be an array, which contains each action's response status.
// each action's response should be an object, which contains success status and response information. { status: [Boolean], object: [Object] }
return responseData.map((response) => ({
status: response.status === 200 || response.status === 204,
object: response.data,
}));
};
export const dataSource = {
loadRange(params) {
$.ajax({
// pageSize and startPageIndex only works when paging component is referenced, if control
// do find the paging component, pageIndex and pageSize will be undefined.
url: getRecords(params.pageIndex === undefined ? undefined : params.pageSize * params.pageIndex, params.pageSize),
crossDomain: true,
success(result) {
const currentPageDataSource = result.m_Item2;
const itemsTotalCount = result.m_Item1;
params.success(currentPageDataSource, itemsTotalCount);
},
error(xhr, status) {
params.failed();
if (status !== 'abort') {
alert(locale.loadFailed);
}
},
});
},
batch(params) {
jQuery.ajaxBatch({
url: `${API_ROOT}/$batch`,
data: buildRequests(params.actions),
complete(xhr, status, data) {
params.success(parseBatchResponse(data));
},
});
},
batchEdit: true,
};
module.exports = {
saveChanges: 'Save Changes',
cancelChanges: 'Cancel Changes',
loadFailed: 'Failed to load data from remote web site.',
navError: "Cannot navigate to another page because there are some changes which don't submit to server.",
addNew: ' Add new record',
};
<template>
<div id="page-nav">
<div class="left-part">
<button id="firstBtn" :disabled="!!c1" class="button" v-bind:class="c1" v-on:click="first">
<span class="fa fa-step-backward" />
</button>
<button id="previousBtn" :disabled="!!c1" class="button" v-bind:class="c1" v-on:click="previous">
<span class="fa fa-chevron-left" />
</button>
<div class="divider" />
<div class="content">
<span> page </span>
<input
id="currentPage-input"
:value="requestedPage === undefined ? status.pageIndex + 1 : requestedPage"
v-on:keydown="handlePageEnter"
v-on:blur="handlePageBlur"
v-on:change="handleOnPageChange"
/>
<span> of </span>
<span id="totalPages">{{ status.maxPages }}</span>
</div>
<div class="divider" />
<button id="nextBtn" :disabled="!!c2" class="button" v-bind:class="c2" v-on:click="next">
<span class="fa fa-chevron-right" />
</button>
<button id="lastBtn" :disabled="!!c2" class="button" v-bind:class="c2" v-on:click="last">
<span class="fa fa-step-forward" />
</button>
</div>
<div class="right-part">
<div class="content">
Rows <span id="startIndex">{{ start }}</span> - <span id="endIndex">{{ end }}</span>
<span> of </span>
<span id="totalItems">{{ status.maxItems }}</span>
</div>
</div>
</div>
</template>
<script>
import Vue from 'vue';
import DataView from '@grapecity/dataviews.core';
const initialStatus = () => ({ pageIndex: 0, pageSize: 10, maxItems: 0, maxPages: 0 });
const pageControllerStub = {
getStatus() {
return initialStatus();
},
first() {},
previous() {},
next() {},
last() {},
goToPage() {},
statusChanged: {
addHandler() {},
removeHandler() {},
},
};
const Pager = Vue.extend({
props: {
pageController: Object,
},
data() {
return {
status: initialStatus(),
requestedPage: undefined,
};
},
computed: {
end() {
const status = this.status;
return Math.min((status.pageIndex + 1) * status.pageSize, status.maxItems);
},
start() {
const status = this.status;
const end = this.end;
return Math.min(status.pageIndex * status.pageSize + 1, end);
},
c1() {
const status = this.status;
return status.pageIndex === 0 ? ' intangible' : '';
},
c2() {
const status = this.status;
return status.pageIndex >= status.maxPages - 1 ? ' intangible' : '';
},
},
mounted() {
const retry = () => {
const ctrl = this.findCtrl();
if (ctrl !== pageControllerStub) {
this.ctrl = ctrl;
this.status = ctrl.getStatus();
this.ctrl.statusChanged.addHandler(this.handleStatusChange);
return;
}
setTimeout(retry, 10);
};
retry();
},
methods: {
findCtrl() {
if (this.pageController) {
return this.pageController;
}
const dataView = DataView.getControlByElement(document.body);
return (dataView ? dataView.data.pageController : undefined) || pageControllerStub;
},
handleStatusChange(newStatus) {
this.status = newStatus;
},
handlePageBlur(e) {
const activePage = this.status.pageIndex + 1;
const nextPage = e.target.value;
if (nextPage > 0 && nextPage <= this.status.maxPages) {
this.ctrl.goToPage(nextPage - 1);
} else {
console.info(activePage);
this.handlePageChange(activePage);
}
},
handlePageEnter(e) {
const { key, keyCode, target } = e;
const usedKey = key || keyCode;
if (usedKey === 'Enter' || usedKey === 13) {
const activePage = this.status.pageIndex + 1;
const nextPage = target.value;
if (nextPage > 0 && nextPage <= this.status.maxPages) {
this.ctrl.goToPage(nextPage - 1);
} else {
this.handlePageChange(activePage);
}
}
},
handlePageChange(page) {
this.requestedPage = page;
},
handleOnPageChange(e) {
this.handlePageChange(e.target.value);
},
first() {
this.ctrl.first();
this.handlePageChange(1);
},
previous() {
const activePage = this.status.pageIndex + 1;
this.ctrl.previous();
this.handlePageChange(activePage - 1);
},
next() {
const activePage = this.status.pageIndex + 1;
this.ctrl.next();
this.handlePageChange(activePage + 1);
},
last() {
this.ctrl.last();
this.handlePageChange(this.status.maxPages);
},
},
});
Vue.component('pager', Pager);
export default Pager;
</script>
.main-container {
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
overflow: auto;
}
.sample-options {
background: #fbfbfb;
box-sizing: border-box;
float: right;
overflow: auto;
padding: 10px;
flex-grow: 0;
flex-shrink: 0;
}
.sample-options .btn {
display: flex;
align-items: center;
justify-content: center;
height: 32px;
}
#grid {
height: calc(100% - 95px);
min-height: 200px;
width: 100%;
flex-grow: 0;
flex-shrink: 0;
}
.gc-header-row-cell {
background-color: #eaeaea;
display: flex;
align-items: center;
}
#btnAddNew {
display: flex;
align-items: center;
justify-content: center;
border-radius: 5px;
margin: 5px;
}
.add-icon {
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA7CAAAOwgEVKEqAAAAAB3RJTUUH3QsJATErA49PDwAAAgBJREFUOMut1T1IVWEYB/DfPfdKXxTRkFFD0KUhDUIotEYHl0KkoKlF+qBIoqGGloZoq6EPpaAiCGmIDDVaa4sgSYSyaIiiEEkSK4REr7flOXA63NsH9MCBw/s+z//5/r+Fjo4ONWQrdmMvmlGN8wJe4QEe4WXesJADXImTOI05PMczTMf9GrRhB5bgAi7hewpQyoCtQy/24V4oj6gt28PpOWxDDyazgKvRhz04hluYV19GcABPcDlKcRAzKWBP1Oswbvo7mcd1LOAGRnG+WC6Xm3EH93E204BUVmEX1mMqALIyhs04hKEEneHtIio1ItmCAdzG2hr3lbCdR2eCLjyNkOulVox6/6ijMxoYXQmaYjSyqa7AJjRGqgUk2IgN8TVk9KuB0VQKxS85j+3RnG9YHg6WRepVfEI33mZsppEkoVDxn6QUgI2588fYidnYiruRxX5MhM7nnM0aLJYwjtaoU1rHWbyL/4k4X8SHGkDpjrdhPMFgzFlLnSwaoiQLWFpHpyUwBhMMh9GpGI+8vI797q4TXTFsGzBcLJfLU9HpE/iIFzmDObyPu4UagEdwJohiIN3l3gi7Lxr1J3JIS3E0yGEAV0VkMIPjeIhr6A+K8hv66seV4IAefM3z4WTUaSy4rj1HsJXY5dYYpWKQyS8EW/iHJ6AaGaVPwBDe5A1/AgojgwuRXC6BAAAAAElFTkSuQmCC");
background-repeat: no-repeat;
border: 0;
color: transparent;
cursor: pointer;
height: 20px;
margin-right: 5px;
padding: 0;
width: 20px;
}
.edit-icon {
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAAlwSFlzAAALEwAACxMBAJqcGAAAAVlpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDUuNC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iPgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KTMInWQAAAVJJREFUOBGV0ksrRGEcx/FjhmJBLGyUCElRyuUNaIp4B1ayUd6AjbLxjixtZBALElGuRQmRSwkpl+/3zDmTOcYY//qcy3P5nfM85wRBEKRgdWEaDd5QcXvu7o9jL/2v+MQeamGVHTLLYCffROdFzlZFJLwpdWih8w6GnCEDl1MJy6CilabVQffYQjtmMI9n9GMZLsXwH2XABzwfw1cfwwjasI8erMMHObagnGiZ7lMeMYhNDKMet2jEDqpQEBIH0J6vNa4yWME4DK3BG05QEJIMiNeaZeAoljCJA3TgHFdwXrgnyQAbbXvHNoawgSmsYgCH8IuFXyYZQHuY7IY9wSf24QiGuKkv8GcL36JYAH3hRrnWa/iHNkVtbmQ1mrGL9G8B9OVDTrn2186iE3N4wAJKzac7Vy7H6oZLcp8ukELZFYc4YQKXcIP/Vd+fWMfMVmd/AZ8ZSPZy3VL5AAAAAElFTkSuQmCC");
}
.save-icon {
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAUUlEQVQ4T2NkYGD4z0AeWMDAwJDISIEBIGsXIBuAyzCQOAjAXAriJzAwMMwHCZJrANzAoWEAehyhhAm6F0iJUHCgjhow2MKAlCiEq6U0NzIAAGhyJqIFiXmZAAAAAElFTkSuQmCC");
}
.cancel-icon {
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAv0lEQVQ4T6WT7RHBQBRFTyqgA3RAB0rQASoQHShBOtAJKpASlKAD5mR2Z3YIJrvvV5K3e+59H6kojAo4AZuEMwV2wBKYh+8tcAEa4J5qCngGyBY4hsu/fHlmHw9EgO8PYBwSKulMZUMnNbBOHC18TgERaiJefHciyFJGoZy6D6Cy5XwLIbeQnPUBzP2DmLecRkBORBdtLkBRp9c1MTeKAC7ZGbjmOogLl9XEjzEO7YH/wiRdpKEAHRyAVekUOuEXS4Mk/lKeo50AAAAASUVORK5CYII=");
}
.action-btn {
background-color: transparent;
border: 0;
display: inline-block;
height: 100%;
outline: none;
padding-left: 6px;
padding-right: 6px;
}
.action-btn span {
display: block;
height: 16px;
width: 16px;
}
.gc-action-area {
text-align: center;
}
/*# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIkZlYXR1cmVzL0VkaXRpbmcvQmF0Y2hFZGl0L3Z1ZS9zdHlsZXMuc2NzcyIsIkZlYXR1cmVzL0VkaXRpbmcvQmF0Y2hFZGl0L3Z1ZS9zdHlsZXMuY3NzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0VBQ0UsYUFBQTtFQUNBLHNCQUFBO0VBQ0EsV0FBQTtFQUNBLFlBQUE7RUFDQSxjQUFBO0FDQ0Y7O0FERUE7RUFDRSxtQkFBQTtFQUNBLHNCQUFBO0VBQ0EsWUFBQTtFQUNBLGNBQUE7RUFDQSxhQUFBO0VBQ0EsWUFBQTtFQUNBLGNBQUE7QUNDRjtBRENFO0VBQ0UsYUFBQTtFQUNBLG1CQUFBO0VBQ0EsdUJBQUE7RUFDQSxZQUFBO0FDQ0o7O0FER0E7RUFDRSx5QkFBQTtFQUNBLGlCQUFBO0VBQ0EsV0FBQTtFQUNBLFlBQUE7RUFDQSxjQUFBO0FDQUY7O0FER0E7RUFDRSx5QkFBQTtFQUNBLGFBQUE7RUFDQSxtQkFBQTtBQ0FGOztBREdBO0VBQ0UsYUFBQTtFQUNBLG1CQUFBO0VBQ0EsdUJBQUE7RUFDQSxrQkFBQTtFQUNBLFdBQUE7QUNBRjs7QURHQTtFQUNFLDYyQkFBQTtFQUNBLDRCQUFBO0VBQ0EsU0FBQTtFQUNBLGtCQUFBO0VBQ0EsZUFBQTtFQUNBLFlBQUE7RUFDQSxpQkFBQTtFQUNBLFVBQUE7RUFDQSxXQUFBO0FDQUY7O0FER0E7RUFDRSxpa0NBQUE7QUNBRjs7QURHQTtFQUNFLGlPQUFBO0FDQUY7O0FER0E7RUFDRSxxWEFBQTtBQ0FGOztBREdBO0VBQ0UsNkJBQUE7RUFDQSxTQUFBO0VBQ0EscUJBQUE7RUFDQSxZQUFBO0VBQ0EsYUFBQTtFQUNBLGlCQUFBO0VBQ0Esa0JBQUE7QUNBRjtBREVFO0VBQ0UsY0FBQTtFQUNBLFlBQUE7RUFDQSxXQUFBO0FDQUo7O0FESUE7RUFDRSxrQkFBQTtBQ0RGIiwiZmlsZSI6IkZlYXR1cmVzL0VkaXRpbmcvQmF0Y2hFZGl0L3Z1ZS9zdHlsZXMuY3NzIiwic291cmNlc0NvbnRlbnQiOlsiLm1haW4tY29udGFpbmVyIHtcbiAgZGlzcGxheTogZmxleDtcbiAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcbiAgd2lkdGg6IDEwMCU7XG4gIGhlaWdodDogMTAwJTtcbiAgb3ZlcmZsb3c6IGF1dG87XG59XG5cbi5zYW1wbGUtb3B0aW9ucyB7XG4gIGJhY2tncm91bmQ6ICNmYmZiZmI7XG4gIGJveC1zaXppbmc6IGJvcmRlci1ib3g7XG4gIGZsb2F0OiByaWdodDtcbiAgb3ZlcmZsb3c6IGF1dG87XG4gIHBhZGRpbmc6IDEwcHg7XG4gIGZsZXgtZ3JvdzogMDtcbiAgZmxleC1zaHJpbms6IDA7XG5cbiAgLmJ0biB7XG4gICAgZGlzcGxheTogZmxleDtcbiAgICBhbGlnbi1pdGVtczogY2VudGVyO1xuICAgIGp1c3RpZnktY29udGVudDogY2VudGVyO1xuICAgIGhlaWdodDogMzJweDtcbiAgfVxufVxuXG4jZ3JpZCB7XG4gIGhlaWdodDogY2FsYygxMDAlIC0gOTVweCk7XG4gIG1pbi1oZWlnaHQ6IDIwMHB4O1xuICB3aWR0aDogMTAwJTtcbiAgZmxleC1ncm93OiAwO1xuICBmbGV4LXNocmluazogMDtcbn1cblxuLmdjLWhlYWRlci1yb3ctY2VsbCB7XG4gIGJhY2tncm91bmQtY29sb3I6ICNlYWVhZWE7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG59XG5cbiNidG5BZGROZXcge1xuICBkaXNwbGF5OiBmbGV4O1xuICBhbGlnbi1pdGVtczogY2VudGVyO1xuICBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjtcbiAgYm9yZGVyLXJhZGl1czogNXB4O1xuICBtYXJnaW46IDVweDtcbn1cblxuLmFkZC1pY29uIHtcbiAgYmFja2dyb3VuZDogdXJsKCdkYXRhOmltYWdlL3BuZztiYXNlNjQsaVZCT1J3MEtHZ29BQUFBTlNVaEVVZ0FBQUJRQUFBQVVDQVlBQUFDTmlSME5BQUFBQm1KTFIwUUEvd0QvQVArZ3ZhZVRBQUFBQ1hCSVdYTUFBQTdDQUFBT3dnRVZLRXFBQUFBQUIzUkpUVVVIM1FzSkFURXJBNDlQRHdBQUFnQkpSRUZVT011dDFUMUlWV0VZQi9EZlBmZEtYeFRSa0ZGRDBLVWhEVUlvdEVZSGwwS2tvS2xGK3FCSW9xR0dsb1pvcTZFUHBhQWlDR21JRERWYWE0c2dTWVN5YUlpaUVFa1NLNFJFcjdmbE9YQTYzTnNIOU1DQncvcyt6Ly81L3IrRmpvNE9OV1FyZG1Ndm1sR044d0plNFFFZTRXWGVzSkFEWEltVE9JMDVQTWN6VE1mOUdyUmhCNWJnQWk3aGV3cFF5b0N0UXkvMjRWNG9qNmd0MjhQcE9XeEREeWF6Z0t2Umh6MDRobHVZVjE5R2NBQlBjRGxLY1JBektXQlAxT3N3YnZvN21jZDFMT0FHUm5HK1dDNlhtM0VIOTNFMjA0QlVWbUVYMW1NcUFMSXloczA0aEtFRW5lSHRJaW8xSXRtQ0FkekcyaHIzbGJDZFIyZUNManlOa091bFZveDYvNmlqTXhvWVhRbWFZalN5cWE3QUpqUkdxZ1VrMklnTjhUVms5S3VCMFZRS3hTODVqKzNSbkc5WUhnNldSZXBWZkVJMzNtWnNwcEVrb1ZEeG42UVVnSTI1ODhmWWlkbllpcnVSeFg1TWhNN25uTTBhTEpZd2p0YW9VMXJIV2J5TC80azRYOFNIR2tEcGpyZGhQTUZnekZsTG5Td2FvaVFMV0ZwSHB5VXdCaE1NaDlHcEdJKzh2STc5N3E0VFhURnNHekJjTEpmTFU5SHBFL2lJRnptRE9ieVB1NFVhZ0Vkd0pvaGlJTjNsM2dpN0x4cjFKM0pJUzNFMHlHRUFWMFZrTUlQamVJaHI2QStLOGh2NjZzZVY0SUFlZk0zejRXVFVhU3k0cmoxSHNKWFk1ZFlZcFdLUXlTOEVXL2lISjZBYUdhVlB3QkRlNUExL0Fnb2pnd3VSWEM2QkFBQUFBRWxGVGtTdVFtQ0MnKTtcbiAgYmFja2dyb3VuZC1yZXBlYXQ6IG5vLXJlcGVhdDtcbiAgYm9yZGVyOiAwO1xuICBjb2xvcjogdHJhbnNwYXJlbnQ7XG4gIGN1cnNvcjogcG9pbnRlcjtcbiAgaGVpZ2h0OiAyMHB4O1xuICBtYXJnaW4tcmlnaHQ6IDVweDtcbiAgcGFkZGluZzogMDtcbiAgd2lkdGg6IDIwcHg7XG59XG5cbi5lZGl0LWljb24ge1xuICBiYWNrZ3JvdW5kOiB1cmwoJ2RhdGE6aW1hZ2UvcG5nO2Jhc2U2NCxpVkJPUncwS0dnb0FBQUFOU1VoRVVnQUFBQkFBQUFBUUNBWUFBQUFmOC85aEFBQUFBWE5TUjBJQXJzNGM2UUFBQUFsd1NGbHpBQUFMRXdBQUN4TUJBSnFjR0FBQUFWbHBWRmgwV0UxTU9tTnZiUzVoWkc5aVpTNTRiWEFBQUFBQUFEeDRPbmh0Y0cxbGRHRWdlRzFzYm5NNmVEMGlZV1J2WW1VNmJuTTZiV1YwWVM4aUlIZzZlRzF3ZEdzOUlsaE5VQ0JEYjNKbElEVXVOQzR3SWo0S0lDQWdQSEprWmpwU1JFWWdlRzFzYm5NNmNtUm1QU0pvZEhSd09pOHZkM2QzTG5jekxtOXlaeTh4T1RrNUx6QXlMekl5TFhKa1ppMXplVzUwWVhndGJuTWpJajRLSUNBZ0lDQWdQSEprWmpwRVpYTmpjbWx3ZEdsdmJpQnlaR1k2WVdKdmRYUTlJaUlLSUNBZ0lDQWdJQ0FnSUNBZ2VHMXNibk02ZEdsbVpqMGlhSFIwY0RvdkwyNXpMbUZrYjJKbExtTnZiUzkwYVdabUx6RXVNQzhpUGdvZ0lDQWdJQ0FnSUNBOGRHbG1aanBQY21sbGJuUmhkR2x2Ymo0eFBDOTBhV1ptT2s5eWFXVnVkR0YwYVc5dVBnb2dJQ0FnSUNBOEwzSmtaanBFWlhOamNtbHdkR2x2Ymo0S0lDQWdQQzl5WkdZNlVrUkdQZ284TDNnNmVHMXdiV1YwWVQ0S1RNSW5XUUFBQVZKSlJFRlVPQkdWMGtzclJHRWN4L0ZqaG1KQkxHeVVDRWxSeXVVTmFJcDRCMWF5VWQ2QWpiTHhqaXh0WkJBTEVsR3VSUW1SU3drcGwrLzN6RG1UT2NZWS8vcWN5M1A1bmZNODV3UkJFS1JnZFdFYURkNVFjWHZ1N285akwvMnYrTVFlYW1HVkhUTExZQ2ZmUk9kRnpsWkZKTHdwZFdpaDh3NkduQ0VEbDFNSnk2Q2lsYWJWUWZmWVFqdG1NSTluOUdNWkxzWHdIMlhBQnp3ZncxY2Z3d2phc0k4ZXJNTUhPYmFnbkdpWjdsTWVNWWhOREtNZXQyakVEcXBRRUJJSDBKNnZOYTR5V01FNERLM0JHMDVRRUpJTWlOZWFaZUFvbGpDSkEzVGdIRmR3WHJnbnlRQWJiWHZITm9hd2dTbXNZZ0NIOEl1Rlh5WVpRSHVZN0lZOXdTZjI0UWlHdUtrdjhHY0wzNkpZQUgzaFJybldhL2lITmtWdGJtUTFtckdMOUc4QjlPVkRUcm4yMTg2aUUzTjR3QUpLemFjN1Z5N0g2b1pMY3A4dWtFTFpGWWM0WVFLWGNJUC9WZCtmV01mTVZtZC9BWjhaU1BaeTNWTDVBQUFBQUVsRlRrU3VRbUNDJyk7XG59XG5cbi5zYXZlLWljb24ge1xuICBiYWNrZ3JvdW5kOiB1cmwoJ2RhdGE6aW1hZ2UvcG5nO2Jhc2U2NCxpVkJPUncwS0dnb0FBQUFOU1VoRVVnQUFBQkFBQUFBUUNBWUFBQUFmOC85aEFBQUFVVWxFUVZRNFQyTmtZR0Q0ejBBZVdNREF3SkRJU0lFQklHc1hJQnVBeXpDUU9BakFYQXJpSnpBd01Nd0hDWkpyQU56QW9XRUFlaHloaEFtNkYwaUpVSENnamhvdzJNS0FsQ2lFcTZVME56SUFBR2h5SnFJRmlYbVpBQUFBQUVsRlRrU3VRbUNDJyk7XG59XG5cbi5jYW5jZWwtaWNvbiB7XG4gIGJhY2tncm91bmQ6IHVybCgnZGF0YTppbWFnZS9wbmc7YmFzZTY0LGlWQk9SdzBLR2dvQUFBQU5TVWhFVWdBQUFCQUFBQUFRQ0FZQUFBQWY4LzloQUFBQXYwbEVRVlE0VDZXVDdSSEJRQlJGVHlxZ0EzUkFCMHJRQVNvUUhTaEJPdEFKS3BBU2xLQUQ1bVIyWjNZSUpydnZWNUszZSs1OUg2a29qQW80QVp1RU13VjJ3QktZaCs4dGNBRWE0SjVxQ25nR3lCWTRoc3UvZkhsbUh3OUVnTzhQWUJ3U0t1bE1aVU1uTmJCT0hDMThUZ0VSYWlKZWZIY2l5RkpHb1p5NkQ2Q3k1WHdMSWJlUW5QVUJ6UDJEbUxlY1JrQk9SQmR0TGtCUnA5YzFNVGVLQUM3Wkdiam1Pb2dMbDlYRWp6RU83WUgvd2lSZHBLRUFIUnlBVmVrVU91RVhTNE1rL2xLZW81MEFBQUFBU1VWT1JLNUNZSUk9Jyk7XG59XG5cbi5hY3Rpb24tYnRuIHtcbiAgYmFja2dyb3VuZC1jb2xvcjogdHJhbnNwYXJlbnQ7XG4gIGJvcmRlcjogMDtcbiAgZGlzcGxheTogaW5saW5lLWJsb2NrO1xuICBoZWlnaHQ6IDEwMCU7XG4gIG91dGxpbmU6IG5vbmU7XG4gIHBhZGRpbmctbGVmdDogNnB4O1xuICBwYWRkaW5nLXJpZ2h0OiA2cHg7XG5cbiAgc3BhbiB7XG4gICAgZGlzcGxheTogYmxvY2s7XG4gICAgaGVpZ2h0OiAxNnB4O1xuICAgIHdpZHRoOiAxNnB4O1xuICB9XG59XG5cbi5nYy1hY3Rpb24tYXJlYSB7XG4gIHRleHQtYWxpZ246IGNlbnRlcjtcbn1cbiIsIi5tYWluLWNvbnRhaW5lciB7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47XG4gIHdpZHRoOiAxMDAlO1xuICBoZWlnaHQ6IDEwMCU7XG4gIG92ZXJmbG93OiBhdXRvO1xufVxuXG4uc2FtcGxlLW9wdGlvbnMge1xuICBiYWNrZ3JvdW5kOiAjZmJmYmZiO1xuICBib3gtc2l6aW5nOiBib3JkZXItYm94O1xuICBmbG9hdDogcmlnaHQ7XG4gIG92ZXJmbG93OiBhdXRvO1xuICBwYWRkaW5nOiAxMHB4O1xuICBmbGV4LWdyb3c6IDA7XG4gIGZsZXgtc2hyaW5rOiAwO1xufVxuLnNhbXBsZS1vcHRpb25zIC5idG4ge1xuICBkaXNwbGF5OiBmbGV4O1xuICBhbGlnbi1pdGVtczogY2VudGVyO1xuICBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjtcbiAgaGVpZ2h0OiAzMnB4O1xufVxuXG4jZ3JpZCB7XG4gIGhlaWdodDogY2FsYygxMDAlIC0gOTVweCk7XG4gIG1pbi1oZWlnaHQ6IDIwMHB4O1xuICB3aWR0aDogMTAwJTtcbiAgZmxleC1ncm93OiAwO1xuICBmbGV4LXNocmluazogMDtcbn1cblxuLmdjLWhlYWRlci1yb3ctY2VsbCB7XG4gIGJhY2tncm91bmQtY29sb3I6ICNlYWVhZWE7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG59XG5cbiNidG5BZGROZXcge1xuICBkaXNwbGF5OiBmbGV4O1xuICBhbGlnbi1pdGVtczogY2VudGVyO1xuICBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjtcbiAgYm9yZGVyLXJhZGl1czogNXB4O1xuICBtYXJnaW46IDVweDtcbn1cblxuLmFkZC1pY29uIHtcbiAgYmFja2dyb3VuZDogdXJsKFwiZGF0YTppbWFnZS9wbmc7YmFzZTY0LGlWQk9SdzBLR2dvQUFBQU5TVWhFVWdBQUFCUUFBQUFVQ0FZQUFBQ05pUjBOQUFBQUJtSkxSMFFBL3dEL0FQK2d2YWVUQUFBQUNYQklXWE1BQUE3Q0FBQU93Z0VWS0VxQUFBQUFCM1JKVFVVSDNRc0pBVEVyQTQ5UER3QUFBZ0JKUkVGVU9NdXQxVDFJVldFWUIvRGZQZmRLWHhUUmtGRkQwS1VoRFVJb3RFWUhsMEtrb0tsRitxQklvcUdHbG9ab3E2RVBwYUFpQ0dtSUREVmFhNHNnU1lTeWFJaWlFRWtTSzRSRXI3ZmxPWEE2M05zSDlNQ0J3L3Mrei8vNS9yK0ZqbzRPTldRcmRtTXZtbEdOOHdKZTRRRWU0V1hlc0pBRFhJbVRPSTA1UE1jelRNZjlHclJoQjViZ0FpN2hld3BReW9DdFF5LzI0VjRvajZndDI4UHBPV3hERHlhemdLdlJoejA0aGx1WVYxOUdjQUJQY0RsS2NSQXpLV0JQMU9zd2J2bzdtY2QxTE9BR1JuRytXQzZYbTNFSDkzRTIwNEJVVm1FWDFtTXFBTEl5aHMwNGhLRUVuZUh0SWlvMUl0bUNBZHpHMmhyM2xiQ2RSMmVDTGp5TmtPdWxWb3g2LzZpak14b1lYUW1hWWpTeXFhN0FKalJHcWdVazJJZ044VFZrOUt1QjBWUUt4Uzg1aiszUm5HOVlIZzZXUmVwVmZFSTMzbVpzcHBFa29WRHhuNlFVZ0kyNTg4ZllpZG5ZaXJ1UnhYNU1oTTdubk0wYUxKWXdqdGFvVTFySFdieUwvNGs0WDhTSEdrRHBqcmRoUE1GZ3pGbExuU3dhb2lRTFdGcEhweVV3QmhNTWg5R3BHSSs4dkk3OTdxNFRYVEZzR3pCY0xKZkxVOUhwRS9pSUZ6bURPYnlQdTRVYWdFZHdKb2hpSU4zbDNnaTdMeHIxSjNKSVMzRTB5R0VBVjBWa01JUGplSWhyNkErSzhodjY2c2VWNElBZWZNM3o0V1RVYVN5NHJqMUhzSlhZNWRZWXBXS1F5UzhFVy9pSEo2QWFHYVZQd0JEZTVBMS9BZ29qZ3d1UlhDNkJBQUFBQUVsRlRrU3VRbUNDXCIpO1xuICBiYWNrZ3JvdW5kLXJlcGVhdDogbm8tcmVwZWF0O1xuICBib3JkZXI6IDA7XG4gIGNvbG9yOiB0cmFuc3BhcmVudDtcbiAgY3Vyc29yOiBwb2ludGVyO1xuICBoZWlnaHQ6IDIwcHg7XG4gIG1hcmdpbi1yaWdodDogNXB4O1xuICBwYWRkaW5nOiAwO1xuICB3aWR0aDogMjBweDtcbn1cblxuLmVkaXQtaWNvbiB7XG4gIGJhY2tncm91bmQ6IHVybChcImRhdGE6aW1hZ2UvcG5nO2Jhc2U2NCxpVkJPUncwS0dnb0FBQUFOU1VoRVVnQUFBQkFBQUFBUUNBWUFBQUFmOC85aEFBQUFBWE5TUjBJQXJzNGM2UUFBQUFsd1NGbHpBQUFMRXdBQUN4TUJBSnFjR0FBQUFWbHBWRmgwV0UxTU9tTnZiUzVoWkc5aVpTNTRiWEFBQUFBQUFEeDRPbmh0Y0cxbGRHRWdlRzFzYm5NNmVEMGlZV1J2WW1VNmJuTTZiV1YwWVM4aUlIZzZlRzF3ZEdzOUlsaE5VQ0JEYjNKbElEVXVOQzR3SWo0S0lDQWdQSEprWmpwU1JFWWdlRzFzYm5NNmNtUm1QU0pvZEhSd09pOHZkM2QzTG5jekxtOXlaeTh4T1RrNUx6QXlMekl5TFhKa1ppMXplVzUwWVhndGJuTWpJajRLSUNBZ0lDQWdQSEprWmpwRVpYTmpjbWx3ZEdsdmJpQnlaR1k2WVdKdmRYUTlJaUlLSUNBZ0lDQWdJQ0FnSUNBZ2VHMXNibk02ZEdsbVpqMGlhSFIwY0RvdkwyNXpMbUZrYjJKbExtTnZiUzkwYVdabUx6RXVNQzhpUGdvZ0lDQWdJQ0FnSUNBOGRHbG1aanBQY21sbGJuUmhkR2x2Ymo0eFBDOTBhV1ptT2s5eWFXVnVkR0YwYVc5dVBnb2dJQ0FnSUNBOEwzSmtaanBFWlhOamNtbHdkR2x2Ymo0S0lDQWdQQzl5WkdZNlVrUkdQZ284TDNnNmVHMXdiV1YwWVQ0S1RNSW5XUUFBQVZKSlJFRlVPQkdWMGtzclJHRWN4L0ZqaG1KQkxHeVVDRWxSeXVVTmFJcDRCMWF5VWQ2QWpiTHhqaXh0WkJBTEVsR3VSUW1SU3drcGwrLzN6RG1UT2NZWS8vcWN5M1A1bmZNODV3UkJFS1JnZFdFYURkNVFjWHZ1N285akwvMnYrTVFlYW1HVkhUTExZQ2ZmUk9kRnpsWkZKTHdwZFdpaDh3NkduQ0VEbDFNSnk2Q2lsYWJWUWZmWVFqdG1NSTluOUdNWkxzWHdIMlhBQnp3ZncxY2Z3d2phc0k4ZXJNTUhPYmFnbkdpWjdsTWVNWWhOREtNZXQyakVEcXBRRUJJSDBKNnZOYTR5V01FNERLM0JHMDVRRUpJTWlOZWFaZUFvbGpDSkEzVGdIRmR3WHJnbnlRQWJiWHZITm9hd2dTbXNZZ0NIOEl1Rlh5WVpRSHVZN0lZOXdTZjI0UWlHdUtrdjhHY0wzNkpZQUgzaFJybldhL2lITmtWdGJtUTFtckdMOUc4QjlPVkRUcm4yMTg2aUUzTjR3QUpLemFjN1Z5N0g2b1pMY3A4dWtFTFpGWWM0WVFLWGNJUC9WZCtmV01mTVZtZC9BWjhaU1BaeTNWTDVBQUFBQUVsRlRrU3VRbUNDXCIpO1xufVxuXG4uc2F2ZS1pY29uIHtcbiAgYmFja2dyb3VuZDogdXJsKFwiZGF0YTppbWFnZS9wbmc7YmFzZTY0LGlWQk9SdzBLR2dvQUFBQU5TVWhFVWdBQUFCQUFBQUFRQ0FZQUFBQWY4LzloQUFBQVVVbEVRVlE0VDJOa1lHRDR6MEFlV01EQXdKRElTSUVCSUdzWElCdUF5ekNRT0FqQVhBcmlKekF3TU13SENaSnJBTnpBb1dFQWVoeWhoQW02RjBpSlVIQ2dqaG93Mk1LQWxDaUVxNlUwTnpJQUFHaHlKcUlGaVhtWkFBQUFBRWxGVGtTdVFtQ0NcIik7XG59XG5cbi5jYW5jZWwtaWNvbiB7XG4gIGJhY2tncm91bmQ6IHVybChcImRhdGE6aW1hZ2UvcG5nO2Jhc2U2NCxpVkJPUncwS0dnb0FBQUFOU1VoRVVnQUFBQkFBQUFBUUNBWUFBQUFmOC85aEFBQUF2MGxFUVZRNFQ2V1Q3UkhCUUJSRlR5cWdBM1JBQjByUUFTb1FIU2hCT3RBSktwQVNsS0FENW1SMlozWUlKcnZ2VjVLM2UrNTlINmtvakFvNEFadUVNd1Yyd0JLWWgrOHRjQUVhNEo1cUNuZ0d5Qlk0aHN1L2ZIbG1IdzlFZ084UFlCd1NLdWxNWlVNbk5iQk9IQzE4VGdFUmFpSmVmSGNpeUZKR29aeTZENkN5NVh3TEliZVFuUFVCelAyRG1MZWNSa0JPUkJkdExrQlJwOWMxTVRlS0FDN1pHYmptT29nTGw5WEVqekVPN1lIL3dpUmRwS0VBSFJ5QVZla1VPdUVYUzRNay9sS2VvNTBBQUFBQVNVVk9SSzVDWUlJPVwiKTtcbn1cblxuLmFjdGlvbi1idG4ge1xuICBiYWNrZ3JvdW5kLWNvbG9yOiB0cmFuc3BhcmVudDtcbiAgYm9yZGVyOiAwO1xuICBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7XG4gIGhlaWdodDogMTAwJTtcbiAgb3V0bGluZTogbm9uZTtcbiAgcGFkZGluZy1sZWZ0OiA2cHg7XG4gIHBhZGRpbmctcmlnaHQ6IDZweDtcbn1cbi5hY3Rpb24tYnRuIHNwYW4ge1xuICBkaXNwbGF5OiBibG9jaztcbiAgaGVpZ2h0OiAxNnB4O1xuICB3aWR0aDogMTZweDtcbn1cblxuLmdjLWFjdGlvbi1hcmVhIHtcbiAgdGV4dC1hbGlnbjogY2VudGVyO1xufSJdfQ== */
(function () {
const IS_PROD = window.process.env.NODE_ENV === 'production';
const USE_NPM = window.process.env.USE_NPM;
const USE_CDN = window.process.env.USE_CDN;
const SITE_ROOT = window.process.env.SITE_ROOT;
const FRAMEWORK = window.process.env.FRAMEWORK;
const ext = IS_PROD ? '.min.js' : '.js';
function js(name) {
return name + ext;
}
function npm(t) {
if (!t.file) {
t.file = IS_PROD ? t.prod : t.dev;
}
const version = USE_CDN && t.version ? '@' + t.version : '';
const path = t.pkg + version + '/' + t.file;
if (USE_CDN) {
return 'https://unpkg.com/' + path;
}
return 'npm:' + path;
}
function dv(t) {
if (USE_CDN || USE_NPM) {
t.file = 'dist/' + t.file + '.min.js';
return npm(t);
}
return SITE_ROOT + '/static/dataviews/' + js(t.file);
}
const isTypeScript = FRAMEWORK === 'angular';
const babelConfig = {
es2015: true,
react: true,
};
const meta = {
js: {
babelOptions: babelConfig,
},
ts: {
typescriptOptions: {
tsconfig: true
},
},
};
const map = {
// gc.dataviews packages
'@grapecity/dataviews.common': dv({pkg:'@grapecity/dataviews.common',file:'gc.dataviews.common',version:'1.8.17'}),
'@grapecity/dataviews.core': dv({pkg:'@grapecity/dataviews.core',file:'gc.dataviews.core',version:'1.8.17'}),
'@grapecity/dataviews.grid': dv({pkg:'@grapecity/dataviews.grid',file:'gc.dataviews.grid',version:'1.8.17'}),
'@grapecity/dataviews.cardlayout': dv({pkg:'@grapecity/dataviews.cardlayout',file:'gc.dataviews.cardlayout',version:'1.8.17'}),
'@grapecity/dataviews.masonry': dv({pkg:'@grapecity/dataviews.masonry',file:'gc.dataviews.masonry',version:'1.8.17'}),
'@grapecity/dataviews.calendar': dv({pkg:'@grapecity/dataviews.calendar',file:'gc.dataviews.calendar',version:'1.8.17'}),
'@grapecity/dataviews.timeline': dv({pkg:'@grapecity/dataviews.timeline',file:'gc.dataviews.timeline',version:'1.8.17'}),
'@grapecity/dataviews.trellis': dv({pkg:'@grapecity/dataviews.trellis',file:'gc.dataviews.trellis',version:'1.8.17'}),
'@grapecity/dataviews.gantt': dv({pkg:'@grapecity/dataviews.gantt',file:'gc.dataviews.gantt',version:'1.8.17'}),
'@grapecity/dataviews.searchbox': dv({pkg:'@grapecity/dataviews.searchbox',file:'gc.dataviews.searchbox',version:'1.8.17'}),
'@grapecity/dataviews.react': dv({pkg:'@grapecity/dataviews.react',file:'gc.dataviews.react',version:'1.8.17'}),
'@grapecity/dataviews.vue': dv({pkg:'@grapecity/dataviews.vue',file:'gc.dataviews.vue',version:'1.8.17'}),
'@grapecity/dataviews.angular': dv({pkg:'@grapecity/dataviews.angular',file:'gc.dataviews.angular',version:'1.8.17'}),
'@grapecity/dataviews.csvexport': dv({pkg:'@grapecity/dataviews.angular',file:'gc.dataviews.csvexport',version:'1.8.17'}),
// third-party libs
react: npm({pkg:'react',prod:'umd/react.production.min.js',dev:'umd/react.development.js',version:'16.13.1'}),
'react-dom': npm({pkg:'react-dom',prod:'umd/react-dom.production.min.js',dev:'umd/react-dom.development.js',version:'16.13.1'}),
'react-router-dom': npm({pkg:'react-router-dom',prod:'umd/react-router-dom.min.js',dev:'umd/react-router-dom.js',version:'5.2.0'}),
'vue': npm({pkg:'vue',file:'dist/vue.js',version:'2.6.12'}),
'vue-router': npm({pkg:'vue-router',file:'dist/vue-router.js',version:'3.4.3'}),
'lodash': npm({pkg: 'lodash', file: js('lodash')}),
'zone.js': npm({pkg: 'zone.js', file: js('dist/zone')}),
'rxjs': npm({pkg: 'rxjs', file: js('bundles/rxjs.umd')}),
'rxjs/operators': npm({pkg:'rxjs-operators-bundle',prod:'dist/bundle.min.js',dev:'dist/bundle.js',version:'1.0.2'}),
'@angular/core': npm({pkg: '@angular/core', file: js('bundles/core.umd')}),
'@angular/common': npm({pkg: '@angular/common', file: js('bundles/common.umd')}),
'@angular/compiler': npm({pkg: '@angular/compiler', file: js('bundles/compiler.umd')}),
'@angular/platform-browser': npm({pkg: '@angular/platform-browser', file: js('bundles/platform-browser.umd')}),
'@angular/platform-browser-dynamic': npm({pkg: '@angular/platform-browser-dynamic', file: js('bundles/platform-browser-dynamic.umd')}),
'@angular/http': npm({pkg: '@angular/http', file: js('bundles/http.umd')}),
'@angular/common/http': npm({pkg: '@angular/common', file: js('bundles/common-http.umd')}),
'@angular/router': npm({pkg: '@angular/router', file: js('bundles/router.umd')}),
'@angular/forms': npm({pkg: '@angular/forms', file: js('bundles/forms.umd')}),
// systemjs plugins
'systemjs-plugin-json': npm({pkg:'systemjs-plugin-json',file:'json.js',version:'0.3.0'}),
'systemjs-plugin-css': npm({pkg:'systemjs-plugin-css',file:'css.js',version:'0.1.37'}),
'systemjs-plugin-babel': npm({pkg:'systemjs-plugin-babel',file:'plugin-babel.js',version:'0.0.25'}),
'systemjs-babel-build': npm({pkg:'systemjs-plugin-babel',file:'systemjs-babel-browser.js',version:'0.0.25'}),
'plugin-typescript': npm({pkg:'plugin-typescript',file:'lib/plugin.js',version:'8.0.0'}),
'typescript': npm({pkg:'typescript',file:'lib/typescript.js',version:'4.0.2'}),
'systemjs-vue-browser': npm({pkg:'systemjs-vue-browser',file:'index.js',version:'1.0.11'}),
};
const config = {
defaultJSExtensions: true,
transpiler: isTypeScript ? 'plugin-typescript' : 'systemjs-plugin-babel',
typescriptOptions: {
tsconfig: true
},
meta: {
'*.json': {loader: 'systemjs-plugin-json'},
'*.css': {loader: 'systemjs-plugin-css'},
'*.vue': {loader: 'systemjs-vue-browser'},
'*.js': meta.js,
'*.ts': meta.ts,
'app.js': {
format: 'esm',
babelOptions: babelConfig,
},
'typescript': {
exports: 'ts',
},
'@grapecity/dataviews.common': {
format: 'amd',
},
'@grapecity/dataviews.core': {
format: 'amd',
deps: [
'@grapecity/dataviews.common',
],
},
'@grapecity/dataviews.grid': {
format: 'amd',
deps: [
'@grapecity/dataviews.common',
'@grapecity/dataviews.core',
],
},
'@grapecity/dataviews.cardlayout': {
format: 'amd',
deps: [
'@grapecity/dataviews.common',
],
},
'@grapecity/dataviews.masonry': {
format: 'amd',
deps: [
'@grapecity/dataviews.common',
],
},
'@grapecity/dataviews.calendar': {
format: 'amd',
deps: [
'@grapecity/dataviews.common',
'@grapecity/dataviews.core',
],
},
'@grapecity/dataviews.timeline': {
format: 'amd',
deps: [
'@grapecity/dataviews.common',
],
},
'@grapecity/dataviews.trellis': {
format: 'amd',
deps: [
'@grapecity/dataviews.common',
],
},
'@grapecity/dataviews.gantt': {
format: 'amd',
deps: [
'@grapecity/dataviews.common',
],
},
'@grapecity/dataviews.searchbox': {
format: 'amd',
deps: [
'@grapecity/dataviews.common',
],
},
'@grapecity/dataviews.react': {
format: 'amd',
deps: [
'react',
'@grapecity/dataviews.common',
'@grapecity/dataviews.core'
],
},
'@grapecity/dataviews.vue': {
format: 'amd',
deps: [
'vue',
'@grapecity/dataviews.common',
'@grapecity/dataviews.core'
],
},
'@grapecity/dataviews.angular': {
format: 'amd',
deps: [
'@angular/core',
'@grapecity/dataviews.common',
'@grapecity/dataviews.core'
],
},
'@grapecity/dataviews.csvexport': {
format: 'amd',
deps: [
'@grapecity/dataviews.common'
],
},
},
paths: {
// paths serve as alias
'npm:': SITE_ROOT + '/node_modules/',
},
// map tells the System loader where to look for things
map: map,
// packages tells the System loader how to load when no filename and/or no extension
packages: {
'.': { defaultExtension: isTypeScript ? 'ts' : 'js' },
node_modules: { defaultExtension: 'js' },
}
};
// fast format detection to avoid detection by source code using regexp
Object.keys(map).filter(function (key) {
return !config.meta[key];
}).forEach(function (key) {
const path = map[key];
if (path.indexOf('/umd') >= 0 || path.indexOf('.umd') >= 0) {
config.meta[key] = { format: 'amd' };
}
if (path.indexOf('/cjs') >= 0) {
config.meta[key] = { format: 'cjs' };
}
});
System.config(config);
})(this);