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;
	}
	
})()