Skip to content

Commit fe14a7d

Browse files
authored
Merge branch 'ServiceNowDevProgram:main' into feature/new-snippet-v1
2 parents 098ad4e + d2bb5ce commit fe14a7d

File tree

15 files changed

+732
-0
lines changed

15 files changed

+732
-0
lines changed
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
# Auto Save Draft Feature for Catalog Items
2+
3+
This snippet provides automatic draft saving functionality for ServiceNow Catalog Items, helping prevent data loss by automatically saving form data at regular intervals.
4+
5+
## Overview
6+
7+
The feature includes two implementations:
8+
1. Basic Implementation (`basic_implementation.js`)
9+
2. Advanced Implementation (`advanced_implementation.js`)
10+
11+
## Basic Implementation
12+
13+
### Features
14+
- Auto-saves form data every minute
15+
- Stores single draft in sessionStorage
16+
- Provides draft restoration on form load
17+
- Basic error handling and user feedback
18+
19+
### Usage
20+
```javascript
21+
// Apply in Catalog Client Script
22+
// Select "onLoad" for "Client script runs"
23+
// Copy content from basic_implementation.js
24+
```
25+
26+
## Advanced Implementation
27+
28+
### Enhanced Features
29+
- Multiple draft support (keeps last 3 drafts)
30+
- Advanced draft management
31+
- Draft selection dialog
32+
- Detailed metadata tracking
33+
- Improved error handling
34+
- User-friendly notifications
35+
36+
### Usage
37+
```javascript
38+
// Apply in Catalog Client Script
39+
// Select "onLoad" for "Client script runs"
40+
// Copy content from advanced_implementation.js
41+
```
42+
43+
## Technical Details
44+
45+
### Dependencies
46+
- ServiceNow Platform UI Framework
47+
- GlideForm API
48+
- GlideModal (advanced implementation only)
49+
50+
### Browser Support
51+
- Modern browsers with sessionStorage support
52+
- ES5+ compatible
53+
54+
### Security Considerations
55+
- Uses browser's sessionStorage (cleared on session end)
56+
- No sensitive data transmission
57+
- Instance-specific storage
58+
59+
## Implementation Guide
60+
61+
1. Create a new Catalog Client Script:
62+
- Table: Catalog Client Script [catalog_script_client]
63+
- Type: onLoad
64+
- Active: true
65+
66+
2. Choose implementation:
67+
- For basic needs: Copy `basic_implementation.js`
68+
- For advanced features: Copy `advanced_implementation.js`
69+
70+
3. Apply to desired Catalog Items:
71+
- Select applicable Catalog Items
72+
- Test in dev environment first
73+
74+
## Best Practices
75+
76+
1. Testing:
77+
- Test with various form states
78+
- Verify draft restoration
79+
- Check browser storage limits
80+
81+
2. Performance:
82+
- Default 60-second interval is recommended
83+
- Adjust based on form complexity
84+
- Monitor browser memory usage
85+
86+
3. User Experience:
87+
- Clear feedback messages
88+
- Confirmation dialogs
89+
- Error notifications
90+
91+
## Limitations
92+
93+
- Browser session dependent
94+
- Storage size limits
95+
- Form field compatibility varies
96+
97+
## Troubleshooting
98+
99+
Common issues and solutions:
100+
1. Draft not saving
101+
- Check browser console for errors
102+
- Verify sessionStorage availability
103+
- Check form modification detection
104+
105+
2. Restoration fails
106+
- Validate stored data format
107+
- Check browser storage permissions
108+
- Verify form field compatibility
109+
110+
## Version Information
111+
112+
- Compatible with ServiceNow: Rome and later
113+
- Browser Requirements: Modern browsers with ES5+ support
114+
- Last Updated: October 2025
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/**
2+
* Advanced Auto-save Draft Implementation with Enhanced Features
3+
* This version adds multi-draft support and advanced error handling
4+
*/
5+
6+
function onLoad() {
7+
var autosaveInterval = 60000; // 1 minute
8+
var maxDrafts = 3; // Maximum number of drafts to keep
9+
10+
// Initialize draft manager
11+
initializeDraftManager();
12+
13+
// Try to restore previous draft
14+
restoreLastDraft();
15+
16+
// Set up auto-save interval
17+
setInterval(function() {
18+
if (g_form.isModified()) {
19+
saveAdvancedDraft();
20+
}
21+
}, autosaveInterval);
22+
}
23+
24+
function initializeDraftManager() {
25+
window.draftManager = {
26+
maxDrafts: 3,
27+
draftPrefix: 'catalogDraft_' + g_form.getUniqueValue() + '_',
28+
29+
getAllDrafts: function() {
30+
var drafts = [];
31+
for (var i = 0; i < sessionStorage.length; i++) {
32+
var key = sessionStorage.key(i);
33+
if (key.startsWith(this.draftPrefix)) {
34+
drafts.push({
35+
key: key,
36+
data: JSON.parse(sessionStorage.getItem(key))
37+
});
38+
}
39+
}
40+
return drafts.sort((a, b) => b.data.timestamp - a.data.timestamp);
41+
},
42+
43+
cleanup: function() {
44+
var drafts = this.getAllDrafts();
45+
if (drafts.length > this.maxDrafts) {
46+
drafts.slice(this.maxDrafts).forEach(function(draft) {
47+
sessionStorage.removeItem(draft.key);
48+
});
49+
}
50+
}
51+
};
52+
}
53+
54+
function saveAdvancedDraft() {
55+
try {
56+
var draftData = {};
57+
g_form.serialize(draftData);
58+
59+
// Add metadata
60+
var draftKey = window.draftManager.draftPrefix + new Date().getTime();
61+
var draftInfo = {
62+
timestamp: new Date().getTime(),
63+
data: draftData,
64+
user: g_user.userName,
65+
catalog_item: g_form.getTableName(),
66+
fields_modified: g_form.getModifiedFields()
67+
};
68+
69+
sessionStorage.setItem(draftKey, JSON.stringify(draftInfo));
70+
window.draftManager.cleanup();
71+
72+
// Show success message with draft count
73+
var remainingDrafts = window.draftManager.getAllDrafts().length;
74+
g_form.addInfoMessage('Draft saved. You have ' + remainingDrafts + ' saved draft(s).');
75+
76+
} catch (e) {
77+
console.error('Error saving draft: ' + e);
78+
g_form.addErrorMessage('Failed to save draft: ' + e.message);
79+
}
80+
}
81+
82+
function restoreLastDraft() {
83+
try {
84+
var drafts = window.draftManager.getAllDrafts();
85+
86+
if (drafts.length > 0) {
87+
// If multiple drafts exist, show selection dialog
88+
if (drafts.length > 1) {
89+
showDraftSelectionDialog(drafts);
90+
} else {
91+
promptToRestoreDraft(drafts[0].data);
92+
}
93+
}
94+
} catch (e) {
95+
console.error('Error restoring draft: ' + e);
96+
g_form.addErrorMessage('Failed to restore draft: ' + e.message);
97+
}
98+
}
99+
100+
function showDraftSelectionDialog(drafts) {
101+
var dialog = new GlideModal('select_draft_dialog');
102+
dialog.setTitle('Available Drafts');
103+
104+
var html = '<div class="draft-list">';
105+
drafts.forEach(function(draft, index) {
106+
var date = new Date(draft.data.timestamp).toLocaleString();
107+
html += '<div class="draft-item" onclick="selectDraft(' + index + ')">';
108+
html += '<strong>Draft ' + (index + 1) + '</strong> - ' + date;
109+
html += '<br>Modified fields: ' + draft.data.fields_modified.join(', ');
110+
html += '</div>';
111+
});
112+
html += '</div>';
113+
114+
dialog.renderWithContent(html);
115+
}
116+
117+
function promptToRestoreDraft(draftInfo) {
118+
var timestamp = new Date(draftInfo.timestamp);
119+
if (confirm('A draft from ' + timestamp.toLocaleString() + ' was found. Would you like to restore it?')) {
120+
Object.keys(draftInfo.data).forEach(function(field) {
121+
g_form.setValue(field, draftInfo.data[field]);
122+
});
123+
g_form.addInfoMessage('Draft restored from ' + timestamp.toLocaleString());
124+
}
125+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/**
2+
* Basic Auto-save Draft Implementation
3+
* This version provides core functionality for auto-saving catalog item form data
4+
*/
5+
6+
function onLoad() {
7+
var autosaveInterval = 60000; // 1 minute
8+
9+
// Try to restore previous draft
10+
restoreLastDraft();
11+
12+
// Set up auto-save interval
13+
setInterval(function() {
14+
if (g_form.isModified()) {
15+
saveDraft();
16+
}
17+
}, autosaveInterval);
18+
}
19+
20+
function saveDraft() {
21+
try {
22+
var draftData = {};
23+
g_form.serialize(draftData);
24+
25+
var draftKey = 'catalogDraft_' + g_form.getUniqueValue();
26+
sessionStorage.setItem(draftKey, JSON.stringify({
27+
timestamp: new Date().getTime(),
28+
data: draftData
29+
}));
30+
31+
g_form.addInfoMessage('Draft saved automatically');
32+
} catch (e) {
33+
console.error('Error saving draft: ' + e);
34+
}
35+
}
36+
37+
function restoreLastDraft() {
38+
try {
39+
var draftKey = 'catalogDraft_' + g_form.getUniqueValue();
40+
var savedDraft = sessionStorage.getItem(draftKey);
41+
42+
if (savedDraft) {
43+
var draftData = JSON.parse(savedDraft);
44+
var timestamp = new Date(draftData.timestamp);
45+
46+
if (confirm('A draft from ' + timestamp.toLocaleString() + ' was found. Would you like to restore it?')) {
47+
Object.keys(draftData.data).forEach(function(field) {
48+
g_form.setValue(field, draftData.data[field]);
49+
});
50+
g_form.addInfoMessage('Draft restored from ' + timestamp.toLocaleString());
51+
} else {
52+
sessionStorage.removeItem(draftKey);
53+
}
54+
}
55+
} catch (e) {
56+
console.error('Error restoring draft: ' + e);
57+
}
58+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/**
2+
* Auto-save draft feature for Catalog Client Script
3+
*
4+
* This script automatically saves form data as a draft in the browser's sessionStorage
5+
* every minute if changes are detected. It also provides functionality to restore
6+
* the last saved draft when the form is loaded.
7+
*/
8+
9+
// Executes when the form loads
10+
function onLoad() {
11+
var autosaveInterval = 60000; // 1 minute
12+
13+
// Try to restore previous draft
14+
restoreLastDraft();
15+
16+
// Set up auto-save interval
17+
setInterval(function() {
18+
if (g_form.isModified()) {
19+
saveDraft();
20+
}
21+
}, autosaveInterval);
22+
}
23+
24+
// Saves the current form state as a draft
25+
function saveDraft() {
26+
try {
27+
var draftData = {};
28+
g_form.serialize(draftData);
29+
30+
var draftKey = 'catalogDraft_' + g_form.getUniqueValue();
31+
sessionStorage.setItem(draftKey, JSON.stringify({
32+
timestamp: new Date().getTime(),
33+
data: draftData
34+
}));
35+
36+
g_form.addInfoMessage('Draft saved automatically');
37+
} catch (e) {
38+
console.error('Error saving draft: ' + e);
39+
}
40+
}
41+
42+
// Restores the last saved draft if available
43+
function restoreLastDraft() {
44+
try {
45+
var draftKey = 'catalogDraft_' + g_form.getUniqueValue();
46+
var savedDraft = sessionStorage.getItem(draftKey);
47+
48+
if (savedDraft) {
49+
var draftData = JSON.parse(savedDraft);
50+
var timestamp = new Date(draftData.timestamp);
51+
52+
// Ask user if they want to restore the draft
53+
if (confirm('A draft from ' + timestamp.toLocaleString() + ' was found. Would you like to restore it?')) {
54+
Object.keys(draftData.data).forEach(function(field) {
55+
g_form.setValue(field, draftData.data[field]);
56+
});
57+
g_form.addInfoMessage('Draft restored from ' + timestamp.toLocaleString());
58+
} else {
59+
// Clear the draft if user chooses not to restore
60+
sessionStorage.removeItem(draftKey);
61+
}
62+
}
63+
} catch (e) {
64+
console.error('Error restoring draft: ' + e);
65+
}
66+
}

0 commit comments

Comments
 (0)