Join the #BuildWithBuildAgent Challenge! Get recognized, earn exclusive swag, and inspire the ServiceNow Community with what you can build using Build Agent.  Join the Challenge.

Customizing widget to pull description (standard ticket header)

John-Eilif
Giga Contributor

Hi, 

First time poster - long time troubleshooter. Hoping somebody can point me in the correct direction.

I'm trying to customize the 'standard ticket header' to show the full description in a separate panel. Ref; attached picture. The page is partially in Norwegian because our production environment is in Norwegian.

What I've done so far is, with empty result is:

  • Clone the Standard ticket header widget
  • Added a panel
  • Tried to pull the {{::data.description}} into this panel.

I tried following this guide, with no success.

 

 

This is the code from the widget: 

<div ng-if ="data.canRead && data.headless && data.urLink" class="alert alert-info" ng-class="{'none': c.hide}">
  <span class="notification-icon icon-info"><span class="sr-only">Info Message</span></span>
  ${Some of these comments were hidden during ticket routing to protect your privacy. Refer to the originating ticket for current status and updates - }
  <a href={{data.urLink}} class="alert-link alert-text">{{::data.number.display_value}}</a>
  <button type="button" class="close btn-icon icon-cross" aria-label="Close" ng-click="hideMessage()"></button>
</div>
<div ng-if="data.canRead && !data.hideHeader">
  <div ng-if="data.primary_ticket_link" class="alert alert-warning">
    <span class="notification-icon icon-alert"><span class="sr-only">Info Message</span></span>
    ${The information shown below may have additional updates. To view the latest record, <a href={{data.primary_ticket_link}} class="alert-link alert-text">click here</a>}
  </div>
  <div class="panel-body no-padder">

    <div ng-if="!data.isEmpty" class= "form-group pull-left m-n">
      <label class="label-color m-n text-xs" for="data.number.name">{{::data.number.label}}</label>
      <div class="form-control no-padder no-border no-bg" id="data.number.name">{{::data.number.display_value}}</div>
    </div>

    <div ng-if="data.headerFields.length > 0" class="pull-right">
      <div class= "form-group inline m-n" 
           ng-if="field.value && (field.type != 'decimal' || field.type == 'decimal' && field.value != 0)" 
           ng-repeat="field in data.headerFields"
           ng-class="{'padder-md-r': !$last}">
        <label class="label-color m-n text-xs" for="field.name">{{::field.label}}</label>
        <div ng-switch="field.type">
          <div ng-switch-when="glide_date_time" title="{{::field.display_value}}" class="form-control no-padder no-border no-bg">
            <sn-time-ago timestamp="::field.value"></sn-time-ago>
          </div>
          <div ng-switch-default ng-class="{'font-bold': field.name == 'state'}" class="form-control no-padder no-border no-bg">{{::field.display_value}}</div>
        </div>
      </div>
    </div>
  </div>

  <div class="panel b">

    <div class="panel-heading bg-primary panel-la-jolla-default clearfix">
      <div class="flex-display title-padding">
        <h2 class="inline m-n m-r-sm" style="word-break: break-word;">{{::data.title}}</h2>
      	<div ng-if="!data.primary_ticket_link && c.data.currentActionWidget" class="inline pull-right" style="margin-left: auto;">
        	<sp-widget widget="c.data.currentActionWidget" page="{table:data.table, sys_id: data.sys_id}"></sp-widget>
      	</div>
      </div>
      
      <div ng-if="data.description" ng-init="c.description_toggle = false">
        <div ng-if="c.description_toggle" id="description-toggle" aria-hidden="{{!c.description_toggle}}">
          <h4 class="title-padding break-word" ng-bind-html="::data.description"></h4>
        </div>
        <button class="options-btn pull-left" id="wrapper" ng-click="c.description_toggle = !c.description_toggle" aria-expanded="{{c.description_toggle}}" aria-controls="description-toggle">
          <div ng-show="!c.description_toggle">${Show more}</div>
          <div ng-show="c.description_toggle">${Show less}</div>
          <span style="font-size: 10px; padding-left:10px" class="glyphicon" ng-class="c.description_toggle ? 'glyphicon-chevron-up' : 'glyphicon-chevron-down'"></span>
        </button>
      </div>
    </div>

    <div ng-if="!data.show_info_widget && data.fields.length > 0">
      <div class="panel-body">
        <div class="ticket-fields" ng-if="data.fields.length > 0">
          <div class= "col-md-2 col-sm-3 col-xs-4 break-word adjust-height"
               ng-if="(field.type != 'decimal' || field.type == 'decimal' && field.value != 0)" 
               ng-repeat="field in data.fields| filter: {type:'!workflow'}">
            <div ng-switch="field.type">
              <div ng-switch-when="glide_date_time" title="{{field.display_value}}">
                <p class="label-color size text-xs header-text">{{::field.label}}</p>
                <span class="padding-sm" ng-if="field.name == 'due_date' || field.name == 'estimated_delivery'" data-toggle="tooltip" title="{{field.display_value}}">{{::field.display_value}}</span>
                <span ng-if="field.name != 'due_date' && field.name != 'estimated_delivery'"><sn-time-ago class="padding-sm" timestamp="::field.value"/></span>
              </div>
              <div ng-switch-when="glide_list">
                <p class="label-color size header-text text-xs">{{::field.label}}</p>
                <span ng-if="field.reference == 'sys_user' && field.value" ng-repeat="user in field.user" data-toggle="tooltip" title="{{::user.name}}">
                  <sn-avatar ng-click="openProfile(user.userID)" primary="user" enable-tooltip="false" enable-context-menu="true" show-presence="true" ng-style="{'cursor':data.isExternalUser?'default':'pointer'}"></sn-avatar>
                </span>
                <span ng-if="field.reference != 'sys_user' && field.value">
                  <span  ng-repeat="item in field.display_value"  class="header-text">
	                  <span data-toggle="tooltip" title="{{::item}}">{{::item}}</span>
  	                <span ng-if="!$last">,</span>
                  </span>
                </span>
              </div>
              <div ng-switch-default ng-if="field.type != 'glide_list'">
                <span ng-if="field.reference == 'sys_user' && field.value" class="pull-left avatar" data-toggle="tooltip" title="{{::field.user.name}}">
                  <sn-avatar ng-click="openProfile(field.user.userID)" primary=field.user enable-tooltip="false" enable-context-menu="true" show-presence="true" ng-style="{'cursor':data.isExternalUser?'default':'pointer'}"></sn-avatar>
                </span>
                <p class="label-color size header-text text-xs">{{::field.label}}</p>
                <span ng-if="field.reference != 'sys_user' && field.value" class="header-text"><span data-toggle="tooltip" title="{{::field.display_value}}">{{::field.display_value}}</span></span>
                <a ng-if="field.reference == 'sys_user' && field.value" aria-label="{{::field.display_value}}" ng-click="openProfile(field.user.userID)"  class="header-text align-tooltip" ng-style="{'cursor':data.isExternalUser?'default':'pointer'}"><span data-toggle="tooltip" title="{{::field.display_value}}">{{::field.display_value}}</span></a>
              </div>
            </div>
          </div>
        </div>
      </div>
      <div ng-if="field.reference != 'sys_user' && field.value">
        <div class="panel-body padder-t-none">
          <p class="label-color size header-text text-xs">{{::field.label}}</p>
          <div class="padding-sm">
          <sp-widget widget="field.stageWidget"></sp-widget></div>
        </div>
      </div>
    </div>
    <div ng-if="data.show_info_widget">
      <hr>
      <div class="panel-body">
        <sp-widget widget= "c.data.info_widget" page="{table:data.table, sys_id: data.sys_id}"></sp-widget>
      </div>
    </div>
  </div>

  

  <!--- FULL DESCRIPTION --->
  <div class="panel b">
    <div class="panel-heading bg-primary panel-la-jolla-default clearfix">
      <div class="flex-display title-padding">
        <h2 class="inline m-n m-r-sm" style="word-break: break-word;">Henvendelse</h2>
      </div>
    </div>

    <div>
      <div class="panel-body">
       	<p>{{::data.description}}  
        </p>
      </div>
    </div>
    
  </div>
   <!--- /FULL DESCRIPTION --->

</div>

<div ng-if="!data.canRead || !data.canReadConfig" class="panel">
  <h3>
    ${Sorry, either the data don't exist or you don't have the access}
  </h3>
</div>

 

find_real_file.png

 

1 ACCEPTED SOLUTION

John-Eilif
Giga Contributor

I waited a day and when testing again with charged motivation, it worked... could it be that the testing was done towards a cached version of the widget? Anyways, what i did was simply

Server script:

data.desc = $sp.getField(record, 'description').display_value;

 

Html:

{{::data.desc}} 

View solution in original post

9 REPLIES 9

Jaspal Singh
Mega Patron
Mega Patron

Can you also share Server side script.

I added server script - hoping for some assistance on this one from a brilliant mind.

John-Eilif
Giga Contributor

Of course, I'm sorry! 

(function(){
	var tableName = $sp.getParameter('table');
	var sysId = $sp.getParameter('sys_id');
	var record = sn_std_tkt_api.TicketConfig.getTicketRecord(tableName, sysId);
	data.isExternalUser = !gs.hasRole('snc_internal');
	data.is_new_order = (($sp.getParameter("is_new_order") + '') === "true");
	
	data.canRead = hasReadAcces(record);
	if (!data.canRead)
		return;
	
	if ($sp.getParameter('headless') == 'true')
		data.headless = true;
	else if ($sp.getParameter('headless') == 'false')
		data.headless = false;
	else if ($sp.getParameter('headless') == null)
		data.headless = false;
	else
		return;

	if (data.headless)
		data.hideHeader = true;

	tableName = record.getTableName();
	sysId = record.getUniqueValue();
	
	var sdField;
	var headerFields = [];
	var showDomainState = false;
	
	//URL has domain table
	if (tableName != 'universal_request') {
		//Check if universal_request field is present and it is a universal request
		if (record.isValidField('universal_request') && !record.universal_request.nil()) {
			data.urLink = '?id=standard_ticket&table=universal_request&sys_id=' + record.universal_request.sys_id;
			var ur = sn_std_tkt_api.TicketConfig.getTicketRecord('universal_request', record.universal_request);
			if (!hasReadAcces(ur)) {
				readHeaderFields(record);
				showDomainState = true;
			}
			else {
				data.number = $sp.getField(ur, 'number');
				headerFields.push($sp.getField(ur, 'sys_created_on'));
				headerFields.push($sp.getField(record, 'sys_updated_on'));
				headerFields.push($sp.getField(ur, 'state'));
				sdField = $sp.getField(ur, 'short_description');
			}
			//URL-non primary ticket
			if (record.universal_request.primary_task != record.sys_id)
						data.primary_ticket_link = '?id=standard_ticket&table=universal_request&sys_id=' + record.universal_request;
		}
		//It is a domain ticket
		else {
			readHeaderFields(record);
			showDomainState = true;
		}
 }
  //URL-Table name is universal request
	else {
		//Domain ticket is created
		if (!record.primary_task.nil()) {
			data.urLink = '?id=standard_ticket&table=universal_request&sys_id=' + record.sys_id;
			var primary_table = record.primary_task.getRefRecord().getTableName();
			var primaryGR = sn_std_tkt_api.TicketConfig.getTicketRecord(primary_table, record.primary_task + '');
			data.canReadPrimary = hasReadAcces(primaryGR);
			if (!data.canReadPrimary) {
				readHeaderFields(record);
				record = sn_std_tkt_api.TicketConfig.getTicketRecord(primary_table, record.primary_task);
			}
			else { //can read primary ticket
				sdField = $sp.getField(record, 'short_description');
				data.number = $sp.getField(record, 'number');
				data.description = $sp.getField(record, 'description');
				headerFields.push($sp.getField(record, 'sys_created_on'));
				headerFields.push($sp.getField(primaryGR, 'sys_updated_on'));
				headerFields.push($sp.getField(record, 'state'));

				record = sn_std_tkt_api.TicketConfig.getTicketRecord(primary_table, record.primary_task);
				tableName = record.getTableName();
				sysId = record.getUniqueValue();
			}
		}
		//No domain ticket assigned
		else
			readHeaderFields(record);
	}
	
	if (sdField == null || !sdField.value) {//Use number if SD is not there
		data.isEmpty = true;
		sdField = data.number;
	}

	data.title = sdField.display_value;
	data.headerFields = headerFields;
	data.requestSubmitMsg = gs.getMessage("Thank You. Your request {0} has been submitted." , data.number.display_value);
	
	data.canReadConfig = hasReadAcces(record);
	if (!data.canReadConfig)
		return;

	var config = sn_std_tkt_api.TicketConfig.getConfig(tableName, record.sys_domain);

	if (config) {
		if (showDomainState && config.state_field != 'state') {
			var configState = $sp.getField(record, config.state_field);
			headerFields.forEach(function(field, index, that) {
				if (field.name == 'state') {
					that[index] = configState;
				}
			})
		}
		data.show_info_widget = config.show_info_widget;
		if (!data.show_info_widget)
			showConfigTicketFields (config, record);
		else
			showTicketWidget(config, tableName, sysId);

		data.table = tableName;
		data.sys_id = sysId;

		showActionWidget(config, tableName, sysId);
		if (!record.description.canRead())
			return;
		showDescription(config, record);
	}
	
	function hasReadAcces(record) {
		return (record != null && record.isValid() && record.canRead());
	}
	
	function readHeaderFields(record) {
		sdField = $sp.getField(record, 'short_description');
		data.number = $sp.getField(record, 'number');
		headerFields = $sp.getFields(record, 'sys_created_on, sys_updated_on, state');
	}
	
	function showConfigTicketFields(config, record) {
		var fieldNames = [];
			if (config.info_fields)
				fieldNames = config.info_fields.split(',');
		var fields = [];
		if (record.getTableName() == 'sc_req_item' && !record.cat_item.nil()) {
			var catalogItemJS = new sn_sc.CatItem(record.cat_item);
			var cartItemDetail = catalogItemJS.getItemSummary(true);
		}
			fieldNames.forEach(function (fName) {
				if ((!fName || fName == ''))
					return;
				var hidePrice = (fName == 'price' || fName == 'recurring_price') && !cartItemDetail.show_price;
				if (hidePrice)
					return;
				var hideQuantity = (fName == 'quantity') && !cartItemDetail.show_quantity;
				if (hideQuantity)
					return;
				var fElement = record.getElement(fName);
				if (!fElement)
					return;

				if (!fElement.canRead())
					return;
				
			
				var type = fElement.getED().getInternalType();
				if (type == 'glide_list')
					loadGlideListFieldInfo(fElement, fName, type, record, fields);
				else if (type == 'workflow')
					loadWorkflowFieldInfo(fElement, fName, type, record, fields);
				else {
					var f = {
						display_value: (fName == 'recurring_price' && !record.recurring_frequency.nil()) ? (fElement.getDisplayValue() + " " + record.getDisplayValue('recurring_frequency')) : fElement.getDisplayValue(),
						label: fElement.getLabel(),
						name: fElement.getName(),
						type: type,
						value: (fName == 'sys_updated_on' && record.getValue("sys_mod_count") <= 0) ? '' : fElement.toString()
					};
					
					if (!f.value)
						return;

					if (type == 'reference') {
						var reference = fElement.getReferenceTable();
						f.reference = reference;

						if (reference == 'sys_user') {
							f.user = {
								userID: f.value,
								name: f.display_value,
								avatar: GlideAvatarFinder.getAvatarPath(f.value),
								initials: buildInitials(f.display_value)
							}
						}
					}
					fields.push(f);
				}
			});

			data.fields = fields;
	}
	
	function loadGlideListFieldInfo(fElement, fName, type, record, fields) {
		var val = fElement.toString();
		var f = {
			display_value: fElement.getDisplayValue() ? fElement.getDisplayValue().split(",") : '',
			label: fElement.getLabel(),
			type: type,
			value: val ? val.split(",") : '',
			reference: fElement.getED().getReference()
		};
		if (!f.value)
			return;

		var gReference = fElement.getED().getReference();
		if (gReference == 'sys_user') {
			f.user = [];
			for(var u = 0; u < f.value.length; u++){
				f.user.push(person = {
					userID: f.value[u],
					name: f.display_value[u],
					avatar: GlideAvatarFinder.getAvatarPath(f.value[u]),
					initials: buildInitials(f.display_value[u])
				})
			}
		}
		fields.push(f);
	}
	
	function loadWorkflowFieldInfo(fElement, fName, type, record, fields) {
		var f = {
			display_value: fElement.getDisplayValue(),
			label: fElement.getLabel(),
			type: type,
			value: fElement.toString()
		};
		f.stageWidget = $sp.getWidget('request_item_workflow_stages', {req_item_id: sysId});
		fields.push(f);
	}
	
	function showTicketWidget(config, tableName, sysId) {
		var widgetParam = config.info_widget_param
			if (widgetParam)
				widgetParam = JSON.parse(widgetParam)
			else
				widgetParam = {};
		
			widgetParam.table = tableName;
			widgetParam.sys_id = sysId;
			
			data.info_widget = $sp.getWidget(config.info_widget, widgetParam);
	}
	
	function showActionWidget(config, tableName, sysId) {
		var widgetParam = config.action_widget_param
		if (widgetParam)
			widgetParam = JSON.parse(widgetParam)
		else
			widgetParam = {};

		widgetParam.table = tableName;
		widgetParam.sys_id = sysId;

		data.actionWidget = $sp.getWidget(config.action_widget, widgetParam);
	}
	
	function showDescription(config, record) {
		if (config.show_description == 'always')
			data.description = $sp.getField(record, 'description').display_value;
		else if (config.show_description == 'no_variable') {
			var variables = record.variables.getElements(true);
			if (variables.length == 0)
				data.description = $sp.getField(record, 'description').display_value;
		}
	}
	
	function buildInitials(name) {
		if (!name)
			return "--";

		var initialMatchRegex = /^[A-ZÀ-Ÿ]|^[\u3040-\u309f]|^[\u30a0-\u30ff]|^[\uff66-\uff9f]|^[\u4e00-\u9faf]/;
		// Included Hiragana, Katakana, CJK Unified Ideographs and Halfwidth and Fullwidth Forms Blocks 
		// Hiragana -> Japanese words, Katakana -> foreign words
		// CJK Unified Ideographs -> modern Chinese, Japanese, Korean and Vietnamese characters 
		
		var initials = name.split(" ").map(function(word) {
			return word.toUpperCase();
		}).filter(function(word) {
			return word.match(initialMatchRegex);
		}).map(function(word) {
			return word.substring(0,1);
		}).join("");
		return (initials.length > 3) ? initials.substr(0, 3) : initials;
	}
	
})()

Hello friend, try something like : 

(function(){
	var tableName = $sp.getParameter('table');
	var sysId = $sp.getParameter('sys_id');
	var record = sn_std_tkt_api.TicketConfig.getTicketRecord(tableName, sysId);
	data.isExternalUser = !gs.hasRole('snc_internal');
	data.is_new_order = (($sp.getParameter("is_new_order") + '') === "true");
	
	data.canRead = hasReadAcces(record);
	if (!data.canRead)
		return;
	
	if ($sp.getParameter('headless') == 'true')
		data.headless = true;
	else if ($sp.getParameter('headless') == 'false')
		data.headless = false;
	else if ($sp.getParameter('headless') == null)
		data.headless = false;
	else
		return;

	if (data.headless)
		data.hideHeader = true;

	tableName = record.getTableName();
	sysId = record.getUniqueValue();
	
	var sdField;
	var headerFields = [];
	var showDomainState = false;
	
	//URL has domain table
	if (tableName != 'universal_request') {
		//Check if universal_request field is present and it is a universal request
		if (record.isValidField('universal_request') && !record.universal_request.nil()) {
			data.urLink = '?id=standard_ticket&table=universal_request&sys_id=' + record.universal_request.sys_id;
			var ur = sn_std_tkt_api.TicketConfig.getTicketRecord('universal_request', record.universal_request);
			if (!hasReadAcces(ur)) {
				readHeaderFields(record);
				showDomainState = true;
			}
			else {
				data.number = $sp.getField(ur, 'number');
				headerFields.push($sp.getField(ur, 'sys_created_on'));
				headerFields.push($sp.getField(record, 'sys_updated_on'));
				headerFields.push($sp.getField(ur, 'state'));
				sdField = $sp.getField(ur, 'short_description');
                data.description = $sp.getField(record, 'description');
			}
			//URL-non primary ticket
			if (record.universal_request.primary_task != record.sys_id)
						data.primary_ticket_link = '?id=standard_ticket&table=universal_request&sys_id=' + record.universal_request;
		}
		//It is a domain ticket
		else {
			readHeaderFields(record);
			showDomainState = true;
		}
 }
  //URL-Table name is universal request
	else {
		//Domain ticket is created
		if (!record.primary_task.nil()) {
			data.urLink = '?id=standard_ticket&table=universal_request&sys_id=' + record.sys_id;
			var primary_table = record.primary_task.getRefRecord().getTableName();
			var primaryGR = sn_std_tkt_api.TicketConfig.getTicketRecord(primary_table, record.primary_task + '');
			data.canReadPrimary = hasReadAcces(primaryGR);
			if (!data.canReadPrimary) {
				readHeaderFields(record);
				record = sn_std_tkt_api.TicketConfig.getTicketRecord(primary_table, record.primary_task);
			}
			else { //can read primary ticket
				sdField = $sp.getField(record, 'short_description');
				data.number = $sp.getField(record, 'number');
				data.description = $sp.getField(record, 'description');
				headerFields.push($sp.getField(record, 'sys_created_on'));
				headerFields.push($sp.getField(primaryGR, 'sys_updated_on'));
				headerFields.push($sp.getField(record, 'state'));
                data.description = $sp.getField(record, 'description');
				record = sn_std_tkt_api.TicketConfig.getTicketRecord(primary_table, record.primary_task);
				tableName = record.getTableName();
				sysId = record.getUniqueValue();
			}
		}
		//No domain ticket assigned
		else
			readHeaderFields(record);
	}
	
	if (sdField == null || !sdField.value) {//Use number if SD is not there
		data.isEmpty = true;
		sdField = data.number;
	}

	data.title = sdField.display_value;
	data.headerFields = headerFields;
	data.requestSubmitMsg = gs.getMessage("Thank You. Your request {0} has been submitted." , data.number.display_value);
	
	data.canReadConfig = hasReadAcces(record);
	if (!data.canReadConfig)
		return;

	var config = sn_std_tkt_api.TicketConfig.getConfig(tableName, record.sys_domain);

	if (config) {
		if (showDomainState && config.state_field != 'state') {
			var configState = $sp.getField(record, config.state_field);
			headerFields.forEach(function(field, index, that) {
				if (field.name == 'state') {
					that[index] = configState;
				}
			})
		}
		data.show_info_widget = config.show_info_widget;
		if (!data.show_info_widget)
			showConfigTicketFields (config, record);
		else
			showTicketWidget(config, tableName, sysId);

		data.table = tableName;
		data.sys_id = sysId;

		showActionWidget(config, tableName, sysId);
		if (!record.description.canRead())
			return;
		showDescription(config, record);
	}
	
	function hasReadAcces(record) {
		return (record != null && record.isValid() && record.canRead());
	}
	
	function readHeaderFields(record) {
		sdField = $sp.getField(record, 'short_description');
		data.number = $sp.getField(record, 'number');
		headerFields = $sp.getFields(record, 'sys_created_on, sys_updated_on, state');
        data.description = $sp.getField(record, 'description');
	}
	
	function showConfigTicketFields(config, record) {
		var fieldNames = [];
			if (config.info_fields)
				fieldNames = config.info_fields.split(',');
		var fields = [];
		if (record.getTableName() == 'sc_req_item' && !record.cat_item.nil()) {
			var catalogItemJS = new sn_sc.CatItem(record.cat_item);
			var cartItemDetail = catalogItemJS.getItemSummary(true);
		}
			fieldNames.forEach(function (fName) {
				if ((!fName || fName == ''))
					return;
				var hidePrice = (fName == 'price' || fName == 'recurring_price') && !cartItemDetail.show_price;
				if (hidePrice)
					return;
				var hideQuantity = (fName == 'quantity') && !cartItemDetail.show_quantity;
				if (hideQuantity)
					return;
				var fElement = record.getElement(fName);
				if (!fElement)
					return;

				if (!fElement.canRead())
					return;
				
			
				var type = fElement.getED().getInternalType();
				if (type == 'glide_list')
					loadGlideListFieldInfo(fElement, fName, type, record, fields);
				else if (type == 'workflow')
					loadWorkflowFieldInfo(fElement, fName, type, record, fields);
				else {
					var f = {
						display_value: (fName == 'recurring_price' && !record.recurring_frequency.nil()) ? (fElement.getDisplayValue() + " " + record.getDisplayValue('recurring_frequency')) : fElement.getDisplayValue(),
						label: fElement.getLabel(),
						name: fElement.getName(),
						type: type,
						value: (fName == 'sys_updated_on' && record.getValue("sys_mod_count") <= 0) ? '' : fElement.toString()
					};
					
					if (!f.value)
						return;

					if (type == 'reference') {
						var reference = fElement.getReferenceTable();
						f.reference = reference;

						if (reference == 'sys_user') {
							f.user = {
								userID: f.value,
								name: f.display_value,
								avatar: GlideAvatarFinder.getAvatarPath(f.value),
								initials: buildInitials(f.display_value)
							}
						}
					}
					fields.push(f);
				}
			});

			data.fields = fields;
	}
	
	function loadGlideListFieldInfo(fElement, fName, type, record, fields) {
		var val = fElement.toString();
		var f = {
			display_value: fElement.getDisplayValue() ? fElement.getDisplayValue().split(",") : '',
			label: fElement.getLabel(),
			type: type,
			value: val ? val.split(",") : '',
			reference: fElement.getED().getReference()
		};
		if (!f.value)
			return;

		var gReference = fElement.getED().getReference();
		if (gReference == 'sys_user') {
			f.user = [];
			for(var u = 0; u < f.value.length; u++){
				f.user.push(person = {
					userID: f.value[u],
					name: f.display_value[u],
					avatar: GlideAvatarFinder.getAvatarPath(f.value[u]),
					initials: buildInitials(f.display_value[u])
				})
			}
		}
		fields.push(f);
	}
	
	function loadWorkflowFieldInfo(fElement, fName, type, record, fields) {
		var f = {
			display_value: fElement.getDisplayValue(),
			label: fElement.getLabel(),
			type: type,
			value: fElement.toString()
		};
		f.stageWidget = $sp.getWidget('request_item_workflow_stages', {req_item_id: sysId});
		fields.push(f);
	}
	
	function showTicketWidget(config, tableName, sysId) {
		var widgetParam = config.info_widget_param
			if (widgetParam)
				widgetParam = JSON.parse(widgetParam)
			else
				widgetParam = {};
		
			widgetParam.table = tableName;
			widgetParam.sys_id = sysId;
			
			data.info_widget = $sp.getWidget(config.info_widget, widgetParam);
	}
	
	function showActionWidget(config, tableName, sysId) {
		var widgetParam = config.action_widget_param
		if (widgetParam)
			widgetParam = JSON.parse(widgetParam)
		else
			widgetParam = {};

		widgetParam.table = tableName;
		widgetParam.sys_id = sysId;

		data.actionWidget = $sp.getWidget(config.action_widget, widgetParam);
	}
	
	function showDescription(config, record) {
		if (config.show_description == 'always')
			data.description = $sp.getField(record, 'description').display_value;
		else if (config.show_description == 'no_variable') {
			var variables = record.variables.getElements(true);
			if (variables.length == 0)
				data.description = $sp.getField(record, 'description').display_value;
		}
	}
	
	function buildInitials(name) {
		if (!name)
			return "--";

		var initialMatchRegex = /^[A-ZÀ-Ÿ]|^[\u3040-\u309f]|^[\u30a0-\u30ff]|^[\uff66-\uff9f]|^[\u4e00-\u9faf]/;
		// Included Hiragana, Katakana, CJK Unified Ideographs and Halfwidth and Fullwidth Forms Blocks 
		// Hiragana -> Japanese words, Katakana -> foreign words
		// CJK Unified Ideographs -> modern Chinese, Japanese, Korean and Vietnamese characters 
		
		var initials = name.split(" ").map(function(word) {
			return word.toUpperCase();
		}).filter(function(word) {
			return word.match(initialMatchRegex);
		}).map(function(word) {
			return word.substring(0,1);
		}).join("");
		return (initials.length > 3) ? initials.substr(0, 3) : initials;
	}
	
})()