
- Post History
- Subscribe to RSS Feed
- Mark as New
- Mark as Read
- Bookmark
- Subscribe
- Printer Friendly Page
- Report Inappropriate Content
06-27-2025 02:03 AM - edited 06-27-2025 04:34 AM
Before BR, Update - true
Condition: current.description.changes();
Choose the table name (Incident or Story, etc.) and field name (description) on the condition - as per your requirement.
(function executeRule(current, previous) {
if (!current.description.changes()) return;
var oldDesc = (previous.description || '').trim();
var newDesc = (current.description || '').trim();
function tokenize(text) {
return text
.replace(/\r\n/g, '\n')
.split(/(\n+)/)
.map(function(chunk) {
return chunk.match(/^\n+$/) ? chunk : chunk.trim().split(/\s+/);
})
.reduce(function(a, b) { return a.concat(b); }, [])
.filter(function(w) { return w !== ''; });
}
var oldWords = tokenize(oldDesc),
newWords = tokenize(newDesc),
m = oldWords.length,
n = newWords.length;
// LCS matrix
var L = [];
for (var i = 0; i <= m; i++) L[i] = Array(n + 1).fill(0);
for (i = m - 1; i >= 0; i--) {
for (var j = n - 1; j >= 0; j--) {
L[i][j] = oldWords[i] === newWords[j]
? L[i + 1][j + 1] + 1
: Math.max(L[i + 1][j], L[i][j + 1]);
}
}
// Backtrack into diff
var ops = [], i = 0, j = 0;
while (i < m || j < n) {
if (i < m && j < n && oldWords[i] === newWords[j]) {
ops.push({ op: 'equal', word: oldWords[i] }); i++; j++;
} else if (j < n && (i === m || L[i][j + 1] >= L[i + 1][j])) {
ops.push({ op: 'insert', word: newWords[j] }); j++;
} else {
ops.push({ op: 'delete', word: oldWords[i] }); i++;
}
}
// Format spans
var newHtml = '', oldHtml = '';
ops.forEach(function(o) {
if (o.op === 'equal') {
newHtml += o.word + ' ';
oldHtml += o.word + ' ';
} else if (o.op === 'insert') {
newHtml += '<span style="color:blue;">' + o.word + '</span> ';
} else if (o.op === 'delete') {
oldHtml += '<span style="color:red;text-decoration:line-through;">' + o.word + '</span> ';
}
});
// Timestamps
var newTimestamp = new GlideDateTime().getDisplayValue(); // now
var oldTimestamp = previous.sys_updated_on.getDisplayValue(); // when previous was saved
// Build output with labeled timestamps
var journalHtml =
'[code]' +
'<div style="color:gray;font-size:smaller;">New text as of: ' + newTimestamp + '</div>' +
'<div>' + newHtml.trim() + '</div>' +
'<br/>' +
'<div style="font-style:italic;">was</div>' +
'<br/>' +
'<div style="color:gray;font-size:smaller;">Old text as of: ' + oldTimestamp + '</div>' +
'<div>' + oldHtml.trim() + '</div>' +
'[/code]';
// Write to work notes (respects journal + HTML rendering)
current.work_notes = journalHtml;
})(current, previous);
OUTPUT:
OUTPUT AFTER IMPROVISATION:
Fig: Differentiate Work notes with timestamp
Note - The reason why we didn't fetch the input from Work notes rather choose a string field (Description) as input and performed the required HTML operation on it, and then output it into a journal entry field like 'Work notes' is because we don't want to alter the very basic structure of the journal entry field 'Work notes' here. I have rather chose 'Work notes' just as a medium to display the formatted string, which ultimately serves the purpose.
Regards,
Anish Reghu
(Hit Like, if the solution helps you)
Don't forget to Bookmark, for easy access in future.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Be aware that updating journal fields with this kind of HTML tagging can be impossible on some instances, since there's a security property to prevent this. ServiceNow even states that that property should be set.

- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Unfortunately, there is no way that we could restrict the HTML tagging to one table and one field, and the solution could prove quite handy, but unfortunately the HTML tagging (allow or not) is set for a global context and cannot be applied explicitly or be overridden on some table, where the approach is needed.
Probably a case to suggest an idea!
Regards,
Anish