Name

global.UIPolicyBuilder

Description

Helper class used to build the UI Policy object that is used to manage client-side UI Policy actions usage var builder = new UIPolicyBuilder(); var gr = new GlideRecord( sys_ui_policy ); gr.addQuery(......); gr.query(); builder.process(gr); builder.preEvaluate(current, fieldsOnForm); builder.updateValues(); var uiPolicy = builder.toString(); var scripts = builder.getScripts(); for (var scriptName in scripts) { var scriptText = scripts scriptName ; }

Script

var UIPolicyBuilder = Class.create();
UIPolicyBuilder.prototype = {
  initialize: function() {
  	this.uiPolicy = {};
  	this.uiPolicy.fieldPolicies = [];
  	this.uiPolicy.scripts = {};
  	this.debug = false;
  	this.uiScriptType = 0; // UI type compatibility - only use browser scripts and both by default
  	this.uiPolicyScoper = new SNC.UIPolicyScoper();
  },

  setUIScriptType: function(type) {
  	this.uiScriptType = type;
  },

  process: function(/*GlideRecord(sys_ui_policy)*/gr, /*isDataPolicy*/ isDataPolicy) {
  	while (gr.next())
  		this._process(gr, isDataPolicy);
  },

  toString: function(ignoreScripts) {
  	var xmlUtil = GlideXMLUtil;
  	var xml = xmlUtil.newDocument("ui_policy");
  	var root = xml.getDocumentElement();
  	root.setAttribute("debug", this.debug.toString());
  	for (var i = 0; i < this.uiPolicy.fieldPolicies.length; i++) {
  		var fpNode = xmlUtil.newElement(root, "fp");
  		var fp = this.uiPolicy.fieldPolicies[i];
  		this._fieldPolicyToXML(fpNode, fp);

  		for (var cndx = 0; cndx < fp.condition_fields.length; cndx++)
  			this._conditionFieldToXML(fpNode, fp.condition_fields[cndx]);

  		for (var cndx = 0; cndx < fp.conditions.length; cndx++)
  			this._conditionToXML(fpNode, fp.conditions[cndx]);

  		for (var cndx = 0; cndx < fp.actions.length; cndx++)
  			this._actionToXML(fpNode, fp.actions[cndx]);

  		for (var cndx = 0; cndx < fp.list_actions.length; cndx++)
  			this._listActionToXML(fpNode, fp.list_actions[cndx]);
  	}

  	if (!ignoreScripts) {
  		for (var n in this.uiPolicy.scripts)
  			this._scriptToXML(root, n);
  	}

  	return xmlUtil.toString(xml);
  },

  _fieldPolicyToXML: function(/*xmlnode*/ node, /*fieldPolicy{}*/ fp) {
  	node.setAttribute("table", fp.table);
  	node.setAttribute("short_description", fp.short_description);
  	node.setAttribute("reverse", fp.reverse);
  	node.setAttribute("onload", fp.onload);
  	node.setAttribute("script_false", fp.script_false);
  	node.setAttribute("script_true", fp.script_true);
  	node.setAttribute("sys_id", fp.sys_id);
  	node.setAttribute("source_table", fp.source_table);
  },

  _conditionFieldToXML: function(/*xmlnode*/ node, /*conditionField*/ name) {
  	var xmlUtil = GlideXMLUtil;
  	var cfield = xmlUtil.newElement(node, "cfield");
  	cfield.setAttribute("name", name);
  },

  _conditionToXML: function(/*xmlnode*/ node, /*condition{}*/ cond) {
  	var xmlUtil = GlideXMLUtil;
  	var condNode = xmlUtil.newElement(node, "condition");
  	condNode.setAttribute("field", cond.field);
  	condNode.setAttribute("oper", cond.oper);
  	condNode.setAttribute("value", cond.value);
  	condNode.setAttribute("or", cond.or);
  	condNode.setAttribute("type", cond.type);
  	condNode.setAttribute("newquery", cond.newquery);
  	condNode.setAttribute("term", cond.term);
  },

  _actionToXML: function(/*xmlnode*/ node, /*action{}*/ action) {
  	var xmlUtil = GlideXMLUtil;
  	var aNode = xmlUtil.newElement(node, "action");
  	aNode.setAttribute("name", action.name);
  	aNode.setAttribute("mandatory", action.mandatory);
  	aNode.setAttribute("disabled", action.disabled);
  	aNode.setAttribute("visible", action.visible);
  	aNode.setAttribute("cleared", action.cleared);
  },

  _listActionToXML: function(/*xmlnode*/ node, /*action{}*/ action) {
  	var xmlUtil = GlideXMLUtil;
  	var aNode = xmlUtil.newElement(node, "list_action");
  	aNode.setAttribute("name", action.name);
  	aNode.setAttribute("visible", action.visible);
  	aNode.setAttribute("sys_id", action.sys_id);
  },

  _scriptToXML: function(/*xmlnode*/ node, scriptName) {
  	var xmlUtil = GlideXMLUtil;
  	var script = this.uiPolicy.scripts[scriptName];
  	var sNode = xmlUtil.newElement(node, "script");
  	sNode.setAttribute("name", scriptName);
  	xmlUtil.setText(sNode, script);
  },

  toStringWithoutScripts: function() {
  	var json = new JSON();
  	return json.encode(this.uiPolicy.fieldPolicies);
  },

  getScripts: function() {
  	return this.uiPolicy.scripts;
  },

  getFieldPolicies: function() {
  	return this.uiPolicy.fieldPolicies;
  },

  setUIPolicy: function(xmlString) {
  	var xmlUtil = GlideXMLUtil;
  	this.initialize();
  	var xml = xmlUtil.parse(xmlString);
  	var root = xml.getDocumentElement();
  	if (xmlUtil.getAttribute(root, "debug", "false") == "true")
  		this.debug = true;

  	var list = xmlUtil.getChildrenByTagName(root, "fp");
  	if (list) {
  		for (var fpNdx = 0; fpNdx < list.size(); fpNdx++) {
  			var fpNode = list.get(fpNdx);
  			var fp = this._fieldPolicyFromXML(fpNode);
  			this.uiPolicy.fieldPolicies.push(fp);

  			var conditions = [];
  			fp.conditions = conditions;
  			var children = xmlUtil.getChildrenByTagName(fpNode, "condition");
  			if (children) {
  				for (var i = 0; i < children.size(); i++) {
  					var cond = this._conditionFromXML(children.get(i));
  					conditions.push(cond);
  				}
  			}

  			// get the policy actions
  			var actions = [];
  			var list_actions = [];
  			fp.actions = actions;
  			fp.list_actions = list_actions;
  			var children = xmlUtil.getChildrenByTagName(fpNode, "action");
  			if (children) {
  				for (var i = 0; i < children.size(); i++) {
  					var action = this._actionFromXML(children.get(i));
  					actions.push(action);
  				}
  			}

  			var children = xmlUtil.getChildrenByTagName(fpNode, "list_action");
  			if (children) {
  				for (var i = 0; i < children.size(); i++) {
  					var action = this._listActionFromXML(children.get(i));
  					list_actions.push(action);
  				}
  			}

  			// set of fields that have conditions attached
  			var fields = [];
  			fp.condition_fields = fields;
  			var children = xmlUtil.getChildrenByTagName(fpNode, "cfield");
  			if (children) {
  				for (var i = 0; i < children.size(); i++) {
  					var e = children.get(i);
  					fields.push(this._getAttribute(e, "name"));
  				}
  			}
  		}
  	}
  	var scripts = xmlUtil.getChildrenByTagName(root, "script");
  	if (scripts) {
  		for (var i = 0; i < scripts.size(); i++) {
  			this._scriptFromXML(scripts.get(i));
  		}
  	}
  },

  _fieldPolicyFromXML: function(/*xmlnode*/ node) {
  	var fieldPolicy = {};
  	fieldPolicy.table = this._getAttribute(node, "table");
  	fieldPolicy.short_description = this._getAttribute(node, "short_description");
  	fieldPolicy.reverse = this._getAttribute(node, "reverse") == "true";
  	fieldPolicy.onload = this._getAttribute(node, "onload") == "true";
  	fieldPolicy.script_true = this._getAttribute(node, "script_true");
  	fieldPolicy.script_false = this._getAttribute(node, "script_false");
  	fieldPolicy.sys_id = this._getAttribute(node, "sys_id");
  	fieldPolicy.source_table = this._getAttribute(node, "source_table");
  	fieldPolicy.debug = this.debug;
  	return fieldPolicy;
  },

  _conditionFromXML: function(/*xmlnode*/ node) {
  	var condition = {};
  	condition.newquery = this._getAttribute(node, "newquery") == "true";
  	condition.field = this._getAttribute(node, "field");
  	condition.oper = this._getAttribute(node, "oper");
  	condition.value = this._getAttribute(node, "value");
  	condition.type = this._getAttribute(node, "type");
  	condition.or = this._getAttribute(node, "or") == "true";
  	condition.term = this._getAttribute(node, "term");
  	return condition;
  },

  _actionFromXML: function(/*xmlnode*/ node) {
  	var action = {};
  	action.name = this._getAttribute(node, "name");
  	action.mandatory = this._getAttribute(node, "mandatory");
  	action.visible = this._getAttribute(node, "visible");
  	action.disabled = this._getAttribute(node, "disabled");
  	action.cleared = this._getAttribute(node, "cleared");
  	return action;
  },

  _listActionFromXML: function(/*xmlnode*/ node) {
  	var action = {};
  	action.name = this._getAttribute(node, "name");
  	action.visible = this._getAttribute(node, "visible");
  	action.sys_id = this._getAttribute(node, "sys_id");
  	return action;
  },

  _scriptFromXML: function(/*xmlnode*/ node) {
  	var xmlUtil = GlideXMLUtil;
  	var n = this._getAttribute(node, "name");
  	if (!n)
  		return;

  	this.uiPolicy.scripts[n] = this._escapeScript(xmlUtil.getText(node) + '');
  },

  setDebug: function(flag) {
  	this.debug = flag;
  },

  _process: function(gr, isDataPolicy) {
  	gs.addUpgradeDebuggerArtifact("sys_ui_policy", gr.getUniqueValue());
  	this._processScripts(gr);
  	this._processPolicy(gr, isDataPolicy);
  },

  /**
  * Determine if there is are true and/or false scripts for the current policy
  * and if so, save the scripts in the scripts hashmap so the script names can
  * be properly referenced when building the policy information.
  *
  * Each script is checked to ensure that there is actually some code to write out. Since we
  * default the scripts to:
  *
  * function onCondition() {
  * }
  *
  * to help the user build the scripts, we first get rid of all whitespace and see if
  * there is any user added code in the script. If so, we change the name of the
  * script to onCondition_<sys_id>_[true|false] so that there are no name conflicts.
  */
  _processScripts: function(gr) {
  	// only include this script if run_scripts is true and it is the right UI type
  	// possible values include 0 - browser, 1 - smartphone, and 10 - both, as well as null which resolves to 0
  	var uiType = gr.isValidField('ui_type') ? gr.ui_type : 0;
  	if (gr.run_scripts && (uiType == this.uiScriptType || uiType == 10)) {
  		this._processScript(gr.script_true.toString(), gr, "true");
  		this._processScript(gr.script_false.toString(), gr, "false");
  	}
  },

  _processScript: function(script, gr, type) {
  	if (!script)
  		return;

  	// See if there is code in the script first
  	var blankFunc = "functiononCondition() {}";
  	var s = script.replace(/\s/g, "");
  	if (blankFunc == s)
  		return;

  	// Mangle the function name
  	var name = this._getScriptName(gr.getValue("sys_id"), type);
  	script = script.replace(/\r/g, "");
  	script = script.replace(/onCondition/g, name);

  	if (this.uiScriptType != 1)
  		script = this.uiPolicyScoper.getScopedScript(gr, name, script);

  	this.uiPolicy.scripts[name] = script;
  },

  _getScriptName: function(sysId, type) {
  	return "onCondition_" + sysId + "_" + type;
  },

  _processPolicy: function(gr, isDataPolicy) {
  	var set = new Packages.java.util.HashSet();
  	var tableTD;
  	if (!isDataPolicy)
  		tableTD = GlideTableDescriptor.get(gr.table);
  	else
  		tableTD = GlideTableDescriptor.get(gr.model_table);

  	var scriptTrue = "";
  	var scriptFalse = "";

  	var scriptName = this._getScriptName(gr.sys_id, "true");
  	if (this.uiPolicy.scripts[scriptName])
  		scriptTrue = scriptName;

  	scriptName = this._getScriptName(gr.sys_id, "false");
  	if (this.uiPolicy.scripts[scriptName])
  		scriptFalse = scriptName;

  	var fieldPolicy = {};

  	fieldPolicy.table = gr.getTableName();
  	if (!fieldPolicy.table)
  		fieldPolicy.table = gr.model_table.toString();

  	fieldPolicy.short_description = gr.short_description.toString();
  	fieldPolicy.reverse = (gr.reverse_if_false.toString() == "true");
  	if (!isDataPolicy)
  		fieldPolicy.onload = (gr.on_load.toString() == "true");
  	else
  		fieldPolicy.onload = true;

  	fieldPolicy.script_true = scriptTrue;
  	fieldPolicy.script_false = scriptFalse;

  	fieldPolicy.sys_id = gr.sys_id.toString();
  	if (isDataPolicy)
  		fieldPolicy.source_table = 'sys_data_policy2';
  	else
  		fieldPolicy.source_table = 'sys_ui_policy';

  	fieldPolicy.debug = this.debug;
  	this.uiPolicy.fieldPolicies.push(fieldPolicy);

  	// Handle the conditions
  	var conditions = [];
  	fieldPolicy.conditions = conditions;

  	var eq = new GlideQueryString();
  	var table = gr.table;
  	if (!table)
  		table = gr.model_table;

  	eq.init(table, gr.conditions);
  	eq.deserialize();
  	var terms = eq.getTerms();
  	for (var i = 0; i != terms.size(); i++) {
  		var term = terms.get(i);

  		if (term.isEndQuery())
  			continue;

  		// determine field type
  		var ce = new GlideCompositeElement(term.getTermField(), tableTD);

  		if (!ce)
  			continue;

  		var ed = ce.getTargetED();

  		if (!ed)
  			continue;

  		var fieldType = ed.getInternalType();
  		var condition = {};
  		condition.isParenthesesTerm = false;
  		condition.newquery = term.isNewQuery();
  		condition.field = term.getTermField() + '';
  		condition.oper = this._convertOper(term.getOperator() + '');
  		condition.value = term.getValue() + '';
  		condition.type = fieldType;
  		condition.or = term.isOR();
  		condition.term = term.getTerm();
  		conditions.push(condition);

  		set.add(term.getTermField());
  	}

  	// get the policy actions
  	var actions = [];
  	var list_actions = [];
  	fieldPolicy.actions = actions;
  	fieldPolicy.list_actions = list_actions;

  	var tableName = 'sys_ui_policy_action';
  	var listTableName = 'sys_ui_policy_rl_action';
  	var joinField = 'ui_policy';
  	if (isDataPolicy){
  		tableName = 'sys_data_policy_rule';
  		joinField = 'sys_data_policy';
  	}

  	var actionGR = new GlideRecord(tableName);
  	actionGR.addQuery(joinField, gr.sys_id);
  	actionGR.query();
  	while (actionGR.next()) {
  		var action = {};
  		action.name = actionGR.field.toString();
  		action.mandatory = actionGR.mandatory.toString();
  		if (isDataPolicy)
  			action.visible = 'ignore';
  		else
  			action.visible = actionGR.visible.toString();

  		action.disabled = actionGR.disabled.toString();
  		action.cleared = actionGR.cleared.toString();
  		actions.push(action);
  	}

  	//add related list actions
  	var listActionGR = new GlideRecord('sys_ui_policy_rl_action');
  	listActionGR.addQuery('ui_policy', gr.sys_id);
  	listActionGR.query();

  	while (listActionGR.next()) {
  		var action = {};
  		action.name = listActionGR.list.toString();
  		action.visible = listActionGR.visible.toString();
  		action.sys_id = listActionGR.getUniqueValue();
  		list_actions.push(action);
  	}

  	// set of fields that have conditions attached
  	var fields = [];
  	fieldPolicy.condition_fields = fields;
  	var iter = set.iterator();
  	while (iter.hasNext())
  		fields.push(iter.next());

  	set.clear();
  },

  /**
  * Update any values in the ui policy that contain any javascript: parts
  */
  updateValues: function() {
  	// regex used to determine if things look like a date time
  	var dateTimeRegEx = new RegExp("[12][0-9]{3}-[01][0-9]-[0-3][0-9] [0-2][0-9]:[0-5][0-9]:[0-5][0-9]");
  	var gdt = new GlideDateTime();
  	var controller = GlideController;

  	for (var i = 0; i != this.uiPolicy.fieldPolicies.length; i++) {
  		var conditions = this.uiPolicy.fieldPolicies[i].conditions;
  		for (var j = 0; j != conditions.length; j++) {
  			var condition = conditions[j];
  			if (condition.type == "__preevaluated__")
  				continue;

  			var value = condition.value;
  			if (!value)
  				continue;
  			if (value.indexOf('javascript:') == -1)
  				continue;

  			var parts = value.split("@");
  			for (var k = 0; k != parts.length; k++) {
  				if (parts[k].indexOf('javascript:') != 0)
  					continue;

  				parts[k] = controller.evaluateString(parts[k].substring(11));

  				// dates come back as yyyy-mm-dd hh:mm:ss but in GMT
  				// we have to convert these to session TZ so that we have a
  				// chance of using them for comparisons
  				if (condition.type != 'glide_duration' && dateTimeRegEx.test(parts[k])) {
  					gdt.setValue(parts[k]);
  					parts[k] = gdt.getDisplayValue();
  				}
  			}
  			condition.value = parts.join("@");
  		}
  	}
  },

  preEvaluate: function(/* GlideRecord */ gr, fieldsOnForm) {
  	if (gr == null || fieldsOnForm == null)
  		return;

  	var fields = GlideStringUtil.split(fieldsOnForm);

  	for (var i = 0; i != this.uiPolicy.fieldPolicies.length; i++) {
  		var conditions = this.uiPolicy.fieldPolicies[i].conditions;
  		for (var j = 0; j != conditions.length; j++) {
  			var condition = conditions[j];

  			// Don't pre-evaluate conditions for GlideVar elements
  			// legacy GlideVars always started with "vars."
  			// but newer ones can start with anything(e.g. atf vars start with "inputs.")
  			if (this._containsAny(["var__m", "vars."], condition.field))
  				continue;

  			if (!fields.contains(condition.field)) {
  				condition.type = "__preevaluated__";
  				var f = new GlideFilter(condition.term, "UI Policy Filter");
  				condition.value = f.match(gr, true);
  			}
  		}
  	}
  },

  _containsAny: function(needles, hay) {

  	for (var i = 0, len = needles.length; len > i; i++) {
  		if (this._contains(needles[i], hay))
  			return true;
  	}

  	return false;
  },

  _contains: function(needle, hay) {

  	return hay.indexOf(needle) !== -1;
  },

  _getAttribute: function(e, name) {
  	return e.getAttribute(name) + '';
  },

  _escapeScript: function(script) {
  	if (script.indexOf("</script>") == -1)
  		return script;

  	return script.split("</script>").join("</script>");
  },

  _convertOper: function(oper) {
  	if (oper == "CONTAINS")
  		return "LIKE";

  	if (oper == "DOES NOT CONTAIN")
  		return "NOT LIKE";

  	return oper;
  },

  type: 'UIPolicyBuilder'
}

Sys ID

52530896c0a801661b63af1594cab98e

Offical Documentation

Official Docs: