Skip to content

Instantly share code, notes, and snippets.

@chemoish
Created August 27, 2013 22:31
Show Gist options
  • Save chemoish/6359986 to your computer and use it in GitHub Desktop.
Save chemoish/6359986 to your computer and use it in GitHub Desktop.
Ext Sample
Ext.define('PICS.model.report.Report', {
extend: 'Ext.data.Model',
requires: [
'PICS.model.report.Column',
'PICS.model.report.Filter',
'PICS.model.report.Sort'
],
fields: [{
name: 'type',
type: 'string'
}, {
name: 'name',
type: 'string'
}, {
name: 'description',
type: 'string'
}, {
name: 'filter_expression',
type: 'string',
useNull: true
}, {
name: 'is_editable',
type: 'boolean',
persist: false
}, {
name: 'is_favorite',
type: 'boolean'
}, {
name: 'subscription_frequency',
type: 'string'
}],
hasMany: [{
model: 'PICS.model.report.Column',
name: 'columns',
foreignKey: 'report_id',
storeConfig : {
listeners: {
add: function (store, records, index, eOpts) {
var record = records[0];
// "Add" fires when loading the report. Abort if the report has no columns.
if (!record) {
return;
}
// If the report is still loading, then this will do nothing.
this.setReportHasUnsavedChanges(record.get('report_id'));
},
remove: function (store, record, index, eOpts) {
// A column has a "report" property only if it is part of the saved report.
if (record.report) {
record.report.setHasUnsavedChanges(true);
} else {
this.setReportHasUnsavedChanges(record.get('report_id'));
}
},
update: function (store, record, operation, modifiedFieldNames, eOpts) {
// A column has a "report" property only if it is part of the saved report.
if (record.report) {
record.report.setHasUnsavedChanges(true);
} else {
this.setReportHasUnsavedChanges(record.get('report_id'));
}
}
},
setReportHasUnsavedChanges: function (report_id) {
var report_store = Ext.StoreManager.get('report.Reports'),
report = report_store.getById(report_id);
if (report) {
report.setHasUnsavedChanges(true);
}
}
}
}, {
model: 'PICS.model.report.Filter',
name: 'filters',
foreignKey: 'report_id',
storeConfig : {
listeners: {
add: function (store, records, index, eOpts) {
var record = records[0];
// "Add" fires when loading the report. Abort if the report has no filters.
if (!record) {
return;
}
// If the report is still loading, then this will do nothing.
this.setReportHasUnsavedChanges(record.get('report_id'));
},
remove: function (store, record, index, eOpts) {
// A filter has a "report" property only if it is part of the saved report.
if (record.report) {
record.report.setHasUnsavedChanges(true);
} else {
this.setReportHasUnsavedChanges(record.get('report_id'));
}
},
update: function (store, record, operation, modifiedFieldNames, eOpts) {
// A filter has a "report" property only if it is part of the saved report.
if (record.report) {
record.report.setHasUnsavedChanges(true);
} else {
this.setReportHasUnsavedChanges(record.get('report_id'));
}
}
},
setReportHasUnsavedChanges: function (report_id) {
var report_store = Ext.StoreManager.get('report.Reports'),
report = report_store.getById(report_id);
if (report) {
report.setHasUnsavedChanges(true);
}
}
}
}, {
model: 'PICS.model.report.Sort',
name: 'sorts',
foreignKey: 'report_id',
storeConfig : {
listeners: {
// Applying or changing sort order only fires the "add" event.
add: function (store, records, index, eOpts) {
var record = records[0];
// "Add" fires when loading the report. Abort if the report has no sorts.
if (!record) {
return;
}
// If the report is still loading, then this will do nothing.
this.setReportHasUnsavedChanges(record.get('report_id'));
}
},
setReportHasUnsavedChanges: function (report_id) {
var report_store = Ext.StoreManager.get('report.Reports'),
report = report_store.getById(report_id);
if (report) {
report.setHasUnsavedChanges(true);
}
}
}
}],
getFilterExpression: function () {
var filter_expression = this.get('filter_expression');
return filter_expression.replace(/\{([\d]+)\}/g, function (match, p1) {
return parseInt(p1);
});
},
getHasUnsavedChanges: function () {
return this.has_unsaved_changes;
},
getRecordDataAsJson: function () {
var proxy = this.getProxy(),
writer = proxy.getWriter(),
record_data = writer.getRecordData(this);
return Ext.encode(record_data);
},
has_unsaved_changes: false,
isNewFilterExpression: function (filter_expression) {
var current_expression = this.get('filter_expression'),
sanitized_expression = this.sanitizeFilterExpression(filter_expression);
if (sanitized_expression == current_expression) {
return false;
} else {
return true;
}
},
// TODO: probably fix this because nichols wrote it
setFilterExpression: function (filter_expression) {
var sanitized_expression = this.sanitizeFilterExpression(filter_expression);
this.set('filter_expression', sanitized_expression);
},
// TODO write a real grammar and parser for our filter formula DSL
sanitizeFilterExpression: function (filter_expression) {
var validTokenRegex = /[0-9]+|\(|\)|and|or/gi,
tokens = [],
token = '',
paren_count = 0,
token_count = 0,
index_num = 0,
sanitized_expression = '',
max_token_value = this.filters().count(),
token_value;
if (typeof filter_expression != 'string') {
return '';
}
// Split into tokens
filter_expression = filter_expression.replace(validTokenRegex, ' $& ');
tokens = filter_expression.trim().split(/ +/);
// Check for invalid tokens and make sure parens are balanced
for (token_count = 0; token_count < tokens.length; token_count += 1) {
token = tokens[token_count];
if (token.search(validTokenRegex) === -1) {
return '';
}
if (token === '(') {
paren_count += 1;
sanitized_expression += token;
} else if (token === ')') {
paren_count -= 1;
sanitized_expression += token;
} else if (token.toUpperCase() === 'AND') {
sanitized_expression += ' AND ';
} else if (token.toUpperCase() === 'OR') {
sanitized_expression += ' OR ';
} else if (token.search(/[0-9]+/) !== -1) {
token_value = parseInt(token);
if (token_value == 0 || token_value > max_token_value) {
return '';
}
sanitized_expression += '{' + token_value + '}';
} else {
return '';
}
if (paren_count < 0) {
return '';
}
}
if (paren_count !== 0) {
return '';
}
return sanitized_expression;
},
addColumn: function (column) {
if (Ext.getClassName(column) != 'PICS.model.report.Column') {
Ext.Error.raise('Invalid column');
}
var column_store = this.columns(),
new_column = column.getData();
column_store.add(new_column);
this.resortColumns();
},
addColumns: function (columns) {
var new_columns = [];
Ext.each(columns, function (column) {
if (Ext.getClassName(column) != 'PICS.model.report.Column') {
Ext.Error.raise('Invalid column');
}
new_columns.push(column.getData());
});
var column_store = this.columns();
column_store.add(new_columns);
this.resortColumns();
},
addFilter: function (filter) {
if (Ext.getClassName(filter) != 'PICS.model.report.Filter') {
Ext.Error.raise('Invalid filter');
}
var filter_store = this.filters(),
new_filter = filter.getData();
filter_store.add(new_filter);
},
addFilters: function (filters) {
var new_filters = [];
Ext.each(filters, function (filter) {
if (Ext.getClassName(filter) != 'PICS.model.report.Filter') {
Ext.Error.raise('Invalid filter');
}
new_filters.push(filter.getData());
});
var filter_store = this.filters();
filter_store.add(new_filters);
},
addSort: function (column, direction) {
if (Ext.getClassName(column) != 'PICS.model.report.Column') {
Ext.Error.raise('Invalid column');
}
var sort_store = this.sorts(),
field_id = column.get('field_id');
sort_store.add({
field_id: field_id,
direction: direction
});
},
convertColumnsToModelFields: function () {
var column_store = this.columns(),
model_fields = [];
column_store.each(function (column) {
var model_field = column.toModelField();
model_fields.push(model_field);
});
return model_fields;
},
convertColumnsToGridColumns: function () {
var column_store = this.columns(),
grid_columns = [];
column_store.each(function (column) {
var grid_column = column.toGridColumn();
grid_columns.push(grid_column);
});
return grid_columns;
},
// reorder columns
moveColumnByIndex: function (from_index, to_index) {
var column_store = this.columns(),
columns = [];
// generate an array of columns from column store
column_store.each(function (column, index) {
columns[index] = column;
});
// splice out the column store - column your moving
var spliced_column = columns.splice(from_index, 1)[0];
// insert the column store - column to the position you moved it to
columns.splice(to_index, 0, spliced_column);
// remove all column store records
this.removeColumns();
this.addColumns(columns);
this.resortColumns();
this.setHasUnsavedChanges(true);
},
removeColumns: function () {
this.columns().removeAll();
},
removeSorts: function () {
this.sorts().removeAll();
},
resortColumns: function () {
var column_store = this.columns();
column_store.each(function (column, index) {
index += 1;
column.set('sort', index);
});
},
setHasUnsavedChanges: function (value) {
this.has_unsaved_changes = value;
}
});
Ext.define('PICS.data.ServerCommunication', {
statics: (function () {
function loadReportStore(json) {
var report_store = Ext.StoreManager.get('report.Reports');
report_store.setProxyForRead();
report_store.loadRawData(json);
return report_store;
}
function loadColumnStore(json) {
var column_store = Ext.StoreManager.get('report.Columns');
column_store.loadRawData(json);
return column_store;
}
function loadFilterStore(json) {
var filter_store = Ext.StoreManager.get('report.Filters');
filter_store.loadRawData(json);
return filter_store;
}
function loadDataTableStore(json) {
var report_store = Ext.StoreManager.get('report.Reports'),
report = report_store.first(),
data_table_store = Ext.StoreManager.get('report.DataTables'),
model_fields = report.convertColumnsToModelFields();
// update data table model
data_table_store.updateDataTableModelFields(model_fields);
// load data table with results
data_table_store.loadRawData(json);
return data_table_store;
}
function startDataTableLoading() {
var data_table_view = Ext.ComponentQuery.query('reportdatatable')[0];
data_table_view.setLoading(true);
}
function stopDataTableLoading() {
var data_table_view = Ext.ComponentQuery.query('reportdatatable')[0];
data_table_view.setLoading(false);
}
function updateDataTableView(report) {
var data_table_view = Ext.ComponentQuery.query('reportdatatable')[0],
new_grid_columns = report.convertColumnsToGridColumns();
data_table_view.updateGridColumns(new_grid_columns);
}
/* For our purposes, a "response object" is one that contains either a status or responseText property or both.
*
* Ext.Ajax.request(), on success, returns a status property (of value 2xx) and a reponseText property value: { status: 2xx, responseText: { ... } }
* If the backend caught an error, this responseText property will contain a JSON string representing exception data used by PICS.data.Exception.
* On failure, Ext.Ajax.request() returns a non-2xx status value but no responseText: { status: non-2xx }
* Both of these qualify as "response objects".
*
* A store's sync method, however, returns a different set of data. If we need a response object following a call to sync,
* then we must create the response object ourselves from the data that sync provides. This method primarily serves that purpose.
*/
function createResponse(operation, jsonData) {
var response = {};
// If the server returned a non-2xx status code, then we can get our response object's "status" value from operation.error.status.
if (operation.error && operation.error.status) {
response.status = operation.error.status;
// If the store's reader contains JSON data, then we can create our response object's "responseText" value by converting that data to a string.
// Otherwise, we first need to create the JSON data to convert.
} else {
// Since the response had no error, it was successful but it contained useless data.
if (!jsonData) {
var unknown_error = PICS.data.Exception.getUnknownError();
jsonData = {
title: unknown_error.title,
message: unknown_error.message,
success: false
};
}
response.responseText = Ext.encode(jsonData);
}
return response;
}
return {
copyReport: function () {
var report_store = Ext.StoreManager.get('report.Reports'),
report = report_store.first(),
report_copy = report_store.add(report)[0],
url = PICS.data.ServerCommunicationUrl.getCopyReportUrl();
// Remove the original report, so that sync sends only the copy.
report_store.remove(report);
// Flag the store as dirty so that sync will execute.
report_copy.setDirty();
// set load data proxy
report_store.setProxyForWrite(url);
report_store.sync({
callback: function (batch, eOpts) {
var operation = batch.operations[batch.current],
response = operation.response,
jsonData = this.getReader().jsonData;
// sync does not return response when the server sends "success: false"
if (!response) {
response = createResponse(operation, jsonData);
}
if (PICS.data.Exception.hasException(response)) {
PICS.data.Exception.handleException({
response: response
});
} else {
var report_id = jsonData.id;
window.location.href = 'Report.action?report=' + report_id;
}
}
});
},
exportReport: function () {
var url = PICS.data.ServerCommunicationUrl.getExportReportUrl();
this.sendReportViaForm(url, '_blank');
},
favoriteReport: function () {
var url = PICS.data.ServerCommunicationUrl.getFavoriteReportUrl();
Ext.Ajax.request({
url: url,
callback: function (options, success, response) {
if (PICS.data.Exception.hasException(response)) {
PICS.data.Exception.handleException({
response: response
});
}
}
});
},
loadAll: function (options) {
var url = PICS.data.ServerCommunicationUrl.getLoadAllUrl(),
success_callback = typeof options.success_callback == 'function' ? options.success_callback : function () {},
scope = options.scope ? options.scope : this;
Ext.Ajax.request({
url: url,
callback: function (options, success, response) {
if (PICS.data.Exception.hasException(response)) {
PICS.data.Exception.handleException({
response: response
});
} else {
var data = response.responseText,
json = Ext.JSON.decode(data);
loadReportStore(json);
loadColumnStore(json);
loadFilterStore(json);
loadDataTableStore(json);
// TODO: Find a better place for non-report data like this.
PICS.export_limit = json.export_limit;
success_callback.apply(scope, arguments);
}
}
});
},
loadReportAndData: function () {
var report_store = Ext.StoreManager.get('report.Reports'),
report = report_store.first(),
report_id = report.get('id'),
has_unsaved_changes = report.getHasUnsavedChanges(),
url = PICS.data.ServerCommunicationUrl.getLoadReportAndDataUrl();
// add data table loading mask
startDataTableLoading();
// flag store as dirty so it will sync data to server
report.setDirty();
// set load data proxy
report_store.setProxyForWrite(url);
// sync
report_store.sync({
callback: function (batch, eOpts) {
var operation = batch.operations[batch.current],
response = operation.response,
jsonData = this.getReader().jsonData;
if (!response) {
response = createResponse(operation, jsonData);
}
if (PICS.data.Exception.hasException(response)) {
PICS.data.Exception.handleException({
response: response
});
} else {
// load the report store
var json = this.getReader().jsonData,
report_store = loadReportStore(json),
report = report_store.first();
// Persist the unsaved changes flag.
report.setHasUnsavedChanges(has_unsaved_changes);
// load new results
loadDataTableStore(json);
// remove data table loading mask
stopDataTableLoading();
// refresh grid
updateDataTableView(report);
}
}
});
},
loadData: function (page, limit) {
var report_store = Ext.StoreManager.get('report.Reports'),
report = report_store.first(),
report_id = report.get('id'),
data_table_store = Ext.StoreManager.get('report.DataTables'),
page = page ? page : 1,
limit = limit ? limit : data_table_store.pageSize,
url = PICS.data.ServerCommunicationUrl.getLoadDataUrl(page, limit),
that = this;
// updates the stores limit tracker
data_table_store.setLimit(limit);
// updates the stores page tracker
data_table_store.setPage(page);
// add data table loading mask
startDataTableLoading();
// flag store as dirty so it will sync data to server
report.setDirty();
// set load data proxy
report_store.setProxyForWrite(url);
// sync
report_store.sync({
callback: function (batch, eOpts) {
var operation = batch.operations[batch.current],
response = operation.response,
jsonData = this.getReader().jsonData;
if (!response) {
response = createResponse(operation, jsonData);
}
if (PICS.data.Exception.hasException(response)) {
PICS.data.Exception.handleException({
response: response
});
} else {
var json = this.getReader().jsonData,
report_store = Ext.StoreManager.get('report.Reports'),
report = report_store.first();
// load new results
loadDataTableStore(json);
// remove data table loading mask
stopDataTableLoading();
// refresh grid
updateDataTableView(report);
}
}
});
},
printReport: function () {
var url = PICS.data.ServerCommunicationUrl.getPrintReportUrl();
this.sendReportViaForm(url, '_blank');
},
saveReport: function (options) {
var report_store = Ext.StoreManager.get('report.Reports'),
report = report_store.first(),
success_callback = typeof options.success_callback == 'function' ? options.success_callback : function () {},
url = PICS.data.ServerCommunicationUrl.getSaveReportUrl();
// flag store as dirty so it will sync data to server
report.setDirty();
// set load data proxy
report_store.setProxyForWrite(url);
report_store.sync({
callback: function (batch, eOpts) {
var operation = batch.operations[batch.current],
response = operation.response,
jsonData = this.getReader().jsonData;
if (!response) {
response = createResponse(operation, jsonData);
}
if (PICS.data.Exception.hasException(response)) {
PICS.data.Exception.handleException({
response: response
});
} else {
report.setHasUnsavedChanges(false);
success_callback();
}
}
});
},
sendReportViaForm: function (url, target) {
var form = document.createElement('form'),
ext_form = new Ext.Element(form),
input = document.createElement('input'),
ext_input = new Ext.Element(input),
report_store = Ext.StoreManager.get('report.Reports'),
report = report_store.first(),
json = report.getRecordDataAsJson(report);
ext_form.set({
action: url,
method: 'post',
target: target
});
ext_form.addCls('send-report-form');
ext_input.set({
name: 'reportJson',
value: json,
type: 'hidden'
});
ext_form.appendChild(input);
Ext.getBody().appendChild(ext_form);
ext_form.dom.submit();
},
shareReport: function (options) {
var id = options.id,
access_type = options.access_type,
is_editable = options.is_editable,
success_callback = typeof options.success_callback == 'function' ? options.success_callback : function () {},
failure_callback = typeof options.failure_callback == 'function' ? options.failure_callback : function () {},
url = '';
if (!(id && access_type && typeof is_editable != 'undefined')) {
Ext.Error.raise('Error');
}
if (is_editable) {
switch (access_type) {
case 'account':
url = PICS.data.ServerCommunicationUrl.getShareWithAccountEditPermissionUrl();
break;
case 'group':
url = PICS.data.ServerCommunicationUrl.getShareWithGroupEditPermissionUrl();
break;
case 'user':
default:
url = PICS.data.ServerCommunicationUrl.getShareWithUserEditPermissionUrl();
break;
}
} else {
switch (access_type) {
case 'account':
url = PICS.data.ServerCommunicationUrl.getShareWithAccountViewPermissionUrl();
break;
case 'group':
url = PICS.data.ServerCommunicationUrl.getShareWithGroupViewPermissionUrl();
break;
case 'user':
default:
url = PICS.data.ServerCommunicationUrl.getShareWithUserViewPermissionUrl();
break;
}
}
Ext.Ajax.request({
url: url,
params: {
shareId: id
},
callback: function (options, success, response) {
if (PICS.data.Exception.hasException(response)) {
PICS.data.Exception.handleException({
response: response
});
} else {
if (success) {
success_callback(response);
} else {
failure_callback(response);
}
}
}
});
},
requestSubscription: function (frequency) {
var url = PICS.data.ServerCommunicationUrl.getRequestSubscriptionUrl();
Ext.Ajax.request({
url: url,
params: {
frequency: frequency
}
});
},
unfavoriteReport: function () {
var url = PICS.data.ServerCommunicationUrl.getUnfavoriteReportUrl();
Ext.Ajax.request({
url: url,
callback: function (options, success, response) {
if (PICS.data.Exception.hasException(response)) {
PICS.data.Exception.handleException({
response: response
});
}
}
});
},
getReportInfo: function (options) {
var url = PICS.data.ServerCommunicationUrl.getGetReportInfoUrl(),
success_callback = typeof options.success_callback == 'function' ? options.success_callback : function () {};
Ext.Ajax.request({
url: url,
callback: function (options, success, response) {
var data, json;
if (PICS.data.Exception.hasException(response)) {
PICS.data.Exception.handleException({
response: response
});
} else {
json = response.responseText;
data = Ext.JSON.decode(json);
success_callback(data);
}
}
});
}
};
}())
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment