Skip to content

Instantly share code, notes, and snippets.

@f1code
Last active May 8, 2017 21:25
Show Gist options
  • Select an option

  • Save f1code/7e291acfc8e4416f26cd to your computer and use it in GitHub Desktop.

Select an option

Save f1code/7e291acfc8e4416f26cd to your computer and use it in GitHub Desktop.
Javascript Snippets for Infor CRM

Useful JS code snippets for Infor CRM

  • buildQueryDialog: creates a dialog with any number of buttons. The default "raiseQueryDialog" only allows for 2 buttons.
/**
* Creates a dialog with any number of buttons.
* make sure msg is wide enough to accomodate the buttons otherwise they will wrap
* @param {string} msg
* @param {string} title
* @param {string[]} buttons - The button labels
* @param {function} callback
*/
function buildQueryDialog(msg, title, buttons, callback){
var queryDialog = dijit.byId('queryDialog');
if(queryDialog){
queryDialog.destroy();
}
queryDialog = new dijit.Dialog({ id: 'queryDialog', title: title, closable: false });
var buttonsDiv = dojo.create('div', { style: 'text-align: right; padding: 10px' });
for(var i=0; i < buttons.length; i++){
var btn = new dijit.form.Button({
label: buttons[i],
onClick: function() {
callback(this.label);
}
});
dojo.place(btn.domNode, buttonsDiv);
}
var contentNode = dojo.create('div');
dojo.place('<div>' + msg + '</div>', contentNode);
dojo.place(buttonsDiv, contentNode);
dojo.place(contentNode, queryDialog.containerNode, 'only');
queryDialog.show();
return queryDialog;
}
// for comparison, this is how to use the raiseQueryDialog function:
// Note the callback will be invoked with a "true" or "false" parameter - not the button labels
Sage.UI.Dialogs.raiseQueryDialog(title, query, callback, 'Yes', 'No')
define(['Sage/UI/Dashboard/DashboardPage', 'dojo/aspect', 'dojo/query', 'dojo/dom-construct', './MultiSelectDropdown', './PicklistDataStore'],
function (DashboardPage, aspect, query, domConstruct, MultiSelect, PicklistDataStore) {
var _portalAccess = undefined;
aspect.after(DashboardPage.prototype, '_editOptionsMenu', function () {
var trButtons = query('.dijitDialog .edit-options-table > table > tbody > tr');
if (trButtons.length == 0) {
console.warn('Unable to find options dialog');
return;
}
trButtons = trButtons[trButtons.length - 1];
var trNew = domConstruct.place('<tr><td>Portal Access:</td><td><div></div></td></tr>', trButtons, 'before');
var placeholder = query('div', trNew)[0];
_portalAccess = this.portalAccess || retrievePageOption(this, '@portalAccess');
var store = new PicklistDataStore({ pickListName: 'Web Access Level' });
var ddl = new MultiSelect({
dataStore: store,
textField: 'text',
valueField: 'text',
value: _portalAccess
}, placeholder);
ddl.on('change', function (val) {
_portalAccess = val;
});
var dlg = query('.dijitDialog .edit-options-table')[0].parentNode;
dlg.style.cssText = "overflow-y: visible !important;";
});
aspect.after(DashboardPage.prototype, '_prepForSave', function (pg) {
if (_portalAccess !== undefined) {
pg.Dashboard['@portalAccess'] = _portalAccess;
_portalAccess = undefined;
}
return pg;
});
function retrievePageOption(dashboardPage, optionName) {
var dash = dijit.byId('Dashboard');
for (var i in dash.pages) { // dash.pages is NOT an array
if (dash.pages.hasOwnProperty(i)) {
var title = Sage.Utility.htmlDecode(dash.pages[i]['@title']);
if (dashboardPage.name == title) {
return dash.pages[i][optionName];
}
}
}
return null;
}
});
// hack to "stuff" a custom condition into a lookup
ScriptManager.RegisterStartupScript(this, GetType(), "CustomLookupFilter",
@"require(['Sage/UI/SDataLookup', 'dojo/aspect'], function(SDataLookup, aspect) {
aspect.after(SDataLookup.prototype, 'initConditionManager', function() {
if(/lueNotifUser/.test(this.id)){
this.conditionMgr.conditionWidgets['customcondition'] = { getCondition: function() {
return { fieldname: 'User.Type', operator: ' in (\'Remote\', \'Concurrent\', \'Network\')',
val: { toString: function() { return '' } } } } }
}
});
});", true);
aspect.around(SDataLookup.prototype, 'showLookup',
function (originalShowLookup) {
return function () {
var self = this;
if (/lkupEndUser/.test(this.id)) {
SlxDialogs.raiseQueryDialog('Warning', 'Are you sure', function (yesNo) {
if (yesNo) {
originalShowLookup.apply(self, arguments);
// now we need to register the handler for when the lookup is hidden
aspect.after(self.lookupDialog, 'onHide', function () {
self.destroy();
// autopostback
__doPostBack(self.id.replace(/_Lookup$/, ''), '');
});
} else {
self.destroy();
}
}, 'OK', 'Cancel');
} else {
originalShowLookup.apply(self, arguments);
}
}
});
define(['Sage/Data/SDataServiceRegistry', 'Sage/Data/BaseSDataStore', 'dojo/_base/declare', 'dojo/_base/lang'], function (SDataServiceRegistry, BaseSDataStore, declare, lang) {
// Wrapper for Base Sdata Store, with 2 purposes:
// - set default options for retrieving picklist data
// - unwraps the results of the sdata call to return only the picklist items
return declare([BaseSDataStore], {
constructor: function (options) {
if (!options.pickListName)
throw Error('pickListName is required');
this.pickListName = options.pickListName;
this.resourceKind = 'picklists';
this.service = SDataServiceRegistry.getSDataService('system', false, true, false);
this.directQuery = { name: options.pickListName };
this.select = [
'items/text',
'items/code',
'items/number'
];
this.include = ['items'];
},
fetch: function (context) {
var newContext = lang.mixin({
onComplete: function (feed) {
if (!feed[0]) {
console.warn('Unable to locate picklist name ' + this.pickListName);
} else {
context.onComplete(feed[0].items.$resources);
}
}
});
return this.inherited(arguments, [newContext]);
}
});
});
require(['dojo/aspect', 'Sage/Utility/File/DragDropWatcher'],
function(aspect, DragDropWatcher) {
var preventDefaultFileHandler = function(targetNode) {
aspect.around(DragDropWatcher, 'handleFileDrop', function (originalFun) {
return function (e) {
if(e.target !== targetNode) {
originalFun.apply(this, arguments);
}
};
});
}
preventDefaultFileHandler(dojo.byId('someNode'));
})
// Show an indeterminate progress bar.
// For a progress bar that can be updated, see ProgressBarDialog.js instead.
Sage.UI.Dialogs.showProgressBar({ message: 'message', showmessage: true, title: 'title', indeterminate: true, canclose: false })
// to hide:
Sage.UI.Dialogs.closeProgressBar();
// Progress Bar Dialog
// Usage:
// - pb = new ProgressBarDialog({title: 'Foo', maximum: 123})
// pb.updateProgress(123);
// pb.updateMax(4445);
// pb.destroy()
define(['dojo/_base/declare', 'dijit/ProgressBar', 'dijit/Dialog'],
function(declare, ProgressBar, Dialog) {
return declare([Dialog], {
// set progress bar title
title: '',
// total value for the progress bar
maximum: 0,
_progressBar: null,
// default to NOT closable
closable: false,
postCreate: function() {
this.inherited(arguments);
this._progressBar = new ProgressBar({ style: 'width: 300px', maximum: this.maximum });
this.setContent(this._progressBar.domNode);
this.show();
},
updateProgress: function(current) {
this._progressBar.set('value', current);
},
updateMax: function(max) {
this._progressBar.set('maximum', current);
}
});
});
// Example usage to require() a custom module that is included in the <customer>/js folder.
String appPath = Request.ApplicationPath;
ScriptManager.RegisterStartupScript(this, GetType(), "RFI_CustomerPortalScript",
@"require({ packages: [{ name: 'MyCustomer', location: '" + appPath +
@"/MyCustomer/js'}] }, ['MyCustomer/MyModule'], function(MyModule) { });
", true);
define([], function () {
// Convenience function for performing an SData operation.
// Returns a deferred object that will be resolved when the operation completes.
//
// options is an object with the following properties:
// contract: sdata contract to use (default = dynamic)
// resourceId: if provided, will use the specified id as a resource locator
// resourceKind: required - sdata resource type
// operation: name of operation to invoke on the request (i.e. update, create, read). defaults to read
// operationName: name of operation for business rule (optional but necessary for "execute" operations)
// requestType: type of resource request, defaults to Sage.SData.Client.SDataSIngleResourceRequest
// where: used as "where" query arg (optional)
// select: used as "select" query arg (optional)
// queryArgs: additional query args (optional)
//
// For operations that require a data parameter, the "data" argument should be provided, otherwise it must be left out
function doSDataRequest(options, data) {
var def = new dojo.Deferred();
var sdata = Sage.Utility.getSDataService(options.contract || "dynamic");
var requestType = options.requestType;
if (!requestType) {
if (options.operation === "execute") {
requestType = Sage.SData.Client.SDataServiceOperationRequest;
} else if (options.resourceId || options.operation === "create") {
requestType = Sage.SData.Client.SDataSingleResourceRequest;
} else {
requestType = Sage.SData.Client.SDataResourceCollectionRequest;
}
}
var req = new requestType(sdata);
req.setResourceKind(options.resourceKind);
if (options.resourceId && req.setResourceSelector)
req.setResourceSelector("'" + options.resourceId + "'");
if (options.queryArgs)
req.setQueryArgs(options.queryArgs, false);
if (options.where)
req.setQueryArg("where", options.where);
if (options.select)
req.setQueryArg("select", options.select);
if (options.operationName)
req.setOperationName(options.operationName);
if (options.operation === "execute" && options.resourceId && !data) {
data = {
$name: options.operationName,
request: {
entity: { "$key": options.resourceId }
}
};
}
var parms = [];
if (data)
parms.push(data);
parms.push({
success: function (data) {
def.resolve(data);
},
failure: function (response) {
if (typeof console !== "undefined")
console.warn("SData request failed", response);
def.reject((response && response.responseText) ? response.responseText : "Unknown error");
}
});
req[options.operation || "read"].apply(req, parms);
return def;
}
return {
// generic sdata request
doSDataRequest: doSDataRequest
};
});
// Helper class for creating a tasklet that will take an action on each record selected within a page.
// To use:
// * Create a subclass of _SDataProcessingTasklet
// * Override the custom processing methods
// * Invoke the "onProcessClick" method when the "Process" button is clicked in the UI
// * Invoke the "onCancelClick" method when the "Cancel" button is clicked in the UI
define([
'Sage/TaskPane/_BaseTaskPaneTasklet',
'dojo/_base/xhr',
'dojo/_base/lang',
'dojo/_base/declare',
'dojo/string',
'dojo/dom-class',
'dojo/dom-construct',
'dojo/on',
'Sage/Utility/Jobs',
'dijit/ProgressBar',
'dijit/Dialog',
'Sage/UI/Dialogs'
],
function (
_BaseTaskPaneTasklet,
xhr,
lang,
declare,
dString,
domClass,
domConstruct,
on,
jobs,
ProgressBar,
Dialog,
Dialogs
) {
return declare([_BaseTaskPaneTasklet], {
tableName: "C_INVOICE", // table naem / group family - TODO - this should be dyanmic
sdataResourceName: "cinvoices", // corresponding sdata name - TODO - this should be dyanmic
_cancelled: false, // cancellation flag
constructor: function (options) {
lang.mixin(this, options);
},
/////// Custom processing
validateForm: function () {
throw "validateForm must be implemented";
},
// field to be selected (in addition to the record id)
// comma separated values
getFieldsToSelect: function () {
throw "getFieldsToSelect must be implemented";
},
// if appropriate, return an additional condition (sdata string) to be appended to the sdata query
// when retrieving the record data
getAdditionalCondition: function () {
throw "getAdditionalCondition must be implemented";
},
// process a single record. Return a deferred object.
processOneRecord: function (recordData) {
throw "processOneRecord must be implemented";
},
processCompleted: function () {
throw "processCompleted must be implemented.";
},
/// *** No overridable code after this line ***
/////// Helper sdata methods - they can be called by the subclass
// page's sdata resource kind
getResourceKind: function () {
return this.sdataResourceName;
},
// update a single record and return a deferred object
updateRecord: function (recordData) {
var def = new dojo.Deferred();
var svc = Sage.Data.SDataServiceRegistry.getSDataService('dynamic');
var req = new Sage.SData.Client.SDataSingleResourceRequest(svc)
.setResourceKind(this.getResourceKind())
.setResourceSelector("'" + recordData.$key + "'");
var def = new dojo.Deferred();
req.update(recordData, {
success: function () {
def.resolve();
},
failure: function (error) {
def.reject(error);
}
});
return def;
},
updateRecordBusinessRule: function (recordData, operationName, businessRuleParams) {
var def = new dojo.Deferred();
var svc = Sage.Data.SDataServiceRegistry.getSDataService('dynamic');
var req = new Sage.SData.Client.SDataServiceOperationRequest(svc)
.setResourceKind(this.getResourceKind())
.setOperationName(operationName);
var payload =
{
name: operationName,
request:
{
entity: { '$key': recordData.$key }
}
};
for (var propertyName in businessRuleParams) {
payload.request[propertyName] = businessRuleParams[propertyName];
}
var def = new dojo.Deferred();
req.execute(payload, {
success: function () {
def.resolve();
},
failure: function (error) {
def.reject(error);
},
scope: this
});
return def;
},
/////// Event handlers
onProcessClick: function () {
if (this.validateForm()) {
this._cancelled = false;
this.prepareSelectedRecords(lang.hitch(this, "_onPrepareSelected"));
}
},
onCancelClick: function () {
this._hideProgress();
this._cancelled = true;
},
/////// Progress bar
_showProgress: function (title) {
if (!this._progressDialog) {
var pb = new ProgressBar({ style: 'width: 300px' });
var d = new Dialog({ title: title });
d.setContent(pb.domNode);
d.show();
this._progressDialog = d;
this._progressBar = pb;
} else {
this._progressDialog.set('title', title);
}
},
_hideProgress: function () {
if (this._progressDialog) {
this._progressDialog.destroy();
this._progressDialog = null;
}
},
_updateProgress: function (value) {
this._progressBar.set('value', value);
},
_updateProgressMax: function (max) {
this._progressBar.set('maximum', max);
},
//////// Reading records
_onPrepareSelected: function () {
try {
var selInfo = this.getSelectionInfo();
if (selInfo.recordCount == 0)
return;
if (selInfo.selectionCount == 0) {
// need to read the group data
this._showProgress('Reading Group Data');
var gid = this.getCurrentGroupId();
if (gid == "LOOKUPRESULTS")
sdataUrl = "slxdata.ashx/slx/system/-/groups(name%20eq%20'Lookup%20Results'%20and%20upper(family)%20eq%20'" + this.tableName + "')/%24queries/execute";
else
sdataUrl = "slxdata.ashx/slx/system/-/groups('" + gid + "')/%24queries/execute";
var selectedIds = [];
var process = lang.hitch(this, function (index) {
try {
var keyFieldName = this.tableName + "ID";
dojo.xhrGet({
url: sdataUrl + "?_includeContent=false&select=" + keyFieldName + "&format=json&startIndex=" + index,
handleAs: "json",
load: lang.hitch(this, function (response) {
if (this._cancelled)
return;
this._updateProgressMax(response.$totalResults);
this._updateProgress(response.$startIndex + response.$itemsPerPage - 1);
console.log("Reading record ids", response.$resources);
var theseIds = response.$resources.map(function (v) { return v[keyFieldName] });
console.log("theseIds", theseIds);
selectedIds = selectedIds.concat(theseIds);
if (response.$startIndex + response.$itemsPerPage > response.$totalResults) {
// done!
this._getSelectedRecordsData(selectedIds);
} else {
process(response.$startIndex + response.$itemsPerPage);
}
}),
error: function (response) {
this._hideProgress();
alert("Failed to retrieve group data");
}
});
} catch (e) {
alert("Error reading group data: " + e.toString());
this._processComplete();
}
});
process(1);
} else {
this._getSelectedRecordsData(selInfo.selectedIds);
}
} catch (e) {
if (typeof console != "undefined")
console.warn("_onPrepareSelected: uncaught exception", e);
alert("There was an error preparing the record selection: " + e.toString());
}
},
// process all selected records by batches
_getSelectedRecordsData: function (selectedIds) {
this._showProgress('Reading Record Data');
// process the records in batch
var svc = Sage.Data.SDataServiceRegistry.getSDataService('dynamic');
var req = new Sage.SData.Client.SDataResourceCollectionRequest(svc)
.setResourceKind(this.getResourceKind())
.setQueryArg("select", "Id" + (this.getFieldsToSelect() ? "," + this.getFieldsToSelect() : ""));
var recordData = [];
var condition = this.getAdditionalCondition();
if (condition)
condition = " and " + condition;
this._updateProgress(0);
this._updateProgressMax(selectedIds.length);
var processBatch = lang.hitch(this, function (start) {
try {
if (this._cancelled)
return;
if (start < selectedIds.length) {
var idBatch = selectedIds.slice(start, start + 30);
this._updateProgress(start);
req.setQueryArg("where", "Id in ('" + idBatch.join("','") + "')" + condition);
req.read({
success: function (data) {
for (var i = 0; i < data.$resources.length; i++) {
recordData.push(data.$resources[i]);
}
processBatch(start + 30);
},
failure: function () {
alert("There was an error reading Saleslogix data");
}
});
} else {
if (recordData.length == 0) {
this._processComplete();
Dialogs.alert('No record matched the specified criteria');
} else {
this._processSelectedRecords(recordData);
}
}
} catch (e) {
if (typeof console != "undefined")
console.warn(e);
alert("There was an error processing a record batch in _getSelectedRecordsData: " + e.toString());
this._processComplete();
}
});
processBatch(0);
},
////////// Processing the update
_processSelectedRecords: function (recordData) {
this._showProgress('Updating record data');
this._updateProgress(0);
this._updateProgressMax(recordData.length);
var process = lang.hitch(this, function (index) {
if (this._cancelled)
return;
this._updateProgress(index);
if (index == recordData.length) {
this._processComplete();
} else {
try {
this.processOneRecord(recordData[index]).then(lang.hitch(this, process, index + 1));
} catch (e) {
if (typeof console != "undefined")
console.warn("Uncaught exception in processOneRecord", e);
alert("There was an error processing a record: " + e.toString());
this._processComplete();
}
}
});
process(0);
},
_processComplete: function () {
this._hideProgress();
Sage.Groups.GroupManager.refreshListView();
this.processCompleted();
}
}); // end declare
}); // end define
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment