Client Messaging
Application extensions and the Onshape JavaScript web client need to communicate directly, calling across the iframe containing the application extension using post message.
Onshape Client Messaging examples can be split into those that are initiated from the application extension and those that are initiated from the Onshape client.
Messages from the Extension
These Client Messaging examples can be initiated from the application extension:
- Click/close flyouts events: Notify the Onshape client that the user has clicked in the application extension, which should cause Onshape flyouts (versions, history, uploads, etc.) and dropdown menus (profile dropdown menu, document menu) to close. Without this, flyouts and menus might remain open over the application extension.
- Shortcut keyboard events: Shortcut keys (such as
?
, which opens the Onshape Help dialog), can be handled by the application extension by posting a message to the Onshape client to open the dialog. - keepAlive: Notify the Onshape client that the user is actively working in the application extension, which triggers the Onshape client to send a message to the server to keep the browser session alive. Without this, the Onshape browser session will timeout and ask the user to sign in again.
- Standard Onshape dialogs: Request from the application extension to the Onshape client to open one of the Onshape standard dialogs and send the user’s choices back to the application extension. For example, if the application extension needs the user to choose a part or assembly to be operated on, the application extension can post a message to the Onshape client requesting that dialog be opened and the selected part or assembly information sent back to the application extension.
- UI customization": Request from the application extension to the Onshape client to customize the Onshape UI (e.g., add commands to menus, add buttons to the toolbars, etc). When these commands or toolbar buttons are clicked, the Onshape client posts a message to the application extension with the available context.
- Note: This is limited to cases where the application extension is made active by the user; application extensions are not automatically loaded when a document is opened. Most UI customizations should be done when you register the application with Onshape, as those change the Onshape client automatically without needing to load the application extension first.
- Content/material insertion: Request from the application extension to insert content into the Onshape document. For example, insert a part into a new or existing Part Studio, apply a material to a part, add a material to a material library, etc.
Messages from Onshape
The following examples can be initiated from the Onshape client:
- User action notification: The Onshape client can notify an application extension when various user actions occur. For example, the Onshape client might notify when the user has made the application extension active or inactive (when the user clicks on document tabs). When an application extension is made inactive, it is moved off the edges of the browser, so it cannot be seen, but is still active, preserving its state.
- Printing: The Onshape client can notify an application extension when the user has chosen the Print command from the main Onshape document menu, enabling the application extension to perform a print operation.
Security Considerations
To ensure security, an application extension must:
- Parse for document, workspace, and element IDs: Parse for the
documentId
,workspaceId
, andelementId
that were passed as query parameters within the application extension’s iframesrc
URL. You must post these back in eachPOST
message. - Parse for the server: Parse for the
server
that was passed as a query parameter within the application extension’s iframesrc
URL. You must use this to validate messages received.- If the application extension uses a JavaScript library or framework (e.g., BackboneJS or AngularJS), it can parse the query parameters and maintain state in other ways.
- Not redirect to another base URL: The browser tells the Onshape client the origin base URL from which a
POST
message is received. The Onshape client ignores messages posted from an origin URL that doesn’t match the original iframesrc
URL. It is extremely important to the security of your application that you verify that the origin of all messages you receive is the same as the original server query parameter in the iframesrc
(i.e.,if (server === e.origin)
). In production operation especially, the message IS NOT SAFE if the message origin does not match the iframesrc
server query parameter. Application extensions should not redirect to another base URL after the iframe has been opened, or the messages will be ignored. - Post a message on startup: Onshape will not post messages until a newly started application extension has first posted a valid message to Onshape. This constraint is in effect anytime an application extension is (re)started and exists to avoid posting messages to application extensions that are not ready to handle them, are not fully loaded, etc. After your application extension is fully loaded and ready to receive messages, post a message to Onshape. A
keepAlive
message is a great first message to send to Onshape. Once Onshape receives a valid message, Onshape will start posting messages to the application extension. If the application extension later sends an invalid message Onshape will stop sending messages until a valid message is posted to Onshape.
POST
messages submitted by application extensions to Onshape will be ignored if any of the following are true:
- The documentId, workspaceId, or elementId are missing or not valid.
- The message name is missing or not recognized.
- The origin of the
POST
message does not match the original iframesrc
URL.
Element Tab
Messages may be sent and received by element tab application extensions.
The following messages can be sent by Element tab application extensions:
messageName (case sensitive) | other message properties? | comment |
applicationInit | yes
| Send once on application startup. |
closeFlyoutsAndMenus | no | Send when a mouse click or other event happens in the application extension. Closes Onshape flyouts and dropdown menus. |
closeSelectItemDialog | no | Closes the select item dialog. |
connectionLost | no | Displays the standard Onshape connection lost message in a message bubble, forcing the user to either reload the document or return to the documents page. |
errorReload | yes
| Similar to the connectionLost message, but enables an application to specify the first part of the message, which will be used instead of "Onshape is not connected." The user must reload the document or return to the documents page. |
finishedSaving | yes
| Response to a 'saveChanges' message sent from Onshape. Should be sent after application has cleaned up any pending edits. |
keepAlive | no | Send periodically while while the user is actively working to avoid the session from timing out. |
saveAVersion | no | Send when the user types “Shift-S” in the application extension, the keyboard shortcut for save a version. |
showKeyboardShortcutsHelp | no | Send when the user types “?” (Shift-? on most keyboards) in the application extension, the keyboard shortcut for the keyboard shortcuts help dialog. |
showMessageBubble | yes
| Send when you want to show a string in the blue message bubble at the top of the Onshape app. |
startLoadingSpinner | yes
| Send to start a large spinner in the middle of the browser window with your message underneath it. |
stopLoadingSpinner | no | Send to stop the large spinner. |
startWorkingSpinner | no | Send to start a small spinner in the middle bottom of the browser window. |
stopWorkingSpinner | no | Send to stop the small spinner. |
openSelectItemDialog | yes
| Send when your application wants to open a dialog in which the user will select one or multiple items - blobs, parts, part studios or assemblies. |
requestCameraProperties | yes
| Send to request camera properties of a specific part studio or assembly element. Note: The element should have been opened at least once in the current session. The messageName of the response is cameraProperties |
The following messages can be received by Element tab application extensions:
messageName (case sensitive) | other message properties? | comment |
show | no | Sent when an element tab application extension is shown (made active) within the Onshape client. This message is NOT sent when the element tab application extension is created. |
hide | no | Sent when an element tab application extension is made inactive within the Onshape client. This message is NOT sent when an element tab application extension is deleted. |
itemSelectedInSelectItemDialog | yes
| Sent when the user selects an item (blob, part, part studio or assembly) in the select item dialog that was opened due to an openSelectItemDialog message sent earlier. When a part is not selected, the partXxx message properties will be empty strings. |
no | Sent when the user chooses the Print command while the application is the active element. The application can choose to handle this as either a print or an export to a PDF or other format. | |
selectItemDialogClosed | no | Sent when the select item dialog closes, either because the user selected an item and selectMultiple is false, or the user changed the active element or the user closed the dialog with the "X" button. |
startFirstViewCommand | yes
| Sent to a drawings application extension when the drawing is created with zero views. If other types of applications need a message posted to them with creation context, contact Onshape and we can discuss using this sort of message for your application also. |
export | yes
| Sent when the user chooses a command to export the contents of the application to a file. |
cameraProperties | yes
| Sent when application posts a requestCameraProperties message |
takeFocus | no | Sent when the Onshape client sets focus on the content window of the element tab application extension. |
saveChanges | yes
| Sent if the application specified 'notifyWhenSaveRequired' in the 'applicationInit' message. Indicates that the application should cleanup any pending edits before an Onshape process continues (i.e. version save). |
Element Right Panel
Most client messaging functionality had been limited to that occurring between the Onshape client and application elements (the Element tab location). Limited functionality in now also available for client messaging to work with application extensions in the Element right panel location.
Enabled messaging to Element right panel extensions includes the communication of selections that the user makes for the following application extension contexts:
- Part Studio
- Assembly
- Document
All Security Considerations above apply to both Element tab and Element right panel extensions, with the following notes:
- Initial message from the application extension to the Onshape client, in the form of an
applicationInit
message (or one of any other messages supported by the element right panel extensions), is required to ensure the Onshape client does not send messages to the extension until it is ready. - Once a valid
applicationInit
message is received by the Onshape client, it will start sending messages with themessageName
valueSELECTION
upon user selection interactions. - Prior to accepting any message from the Onshape client as secure, the
origin
attribute value included in incoming messages must be validated as equal to the originalserver
query parameter value used to load the application extension.
Code Snippets
Parse query parameters
This JavaScript code parses the iframe src
query parameters and uses them to post a message:
var documentId;
var workspaceId;
var elementId;
var server;
// Parse query parameters
var queryParameters = decodeURIComponent(window.location.search.substr(1));
var queryParametersArray = queryParameters.split('&');
for (var i = 0; i < queryParametersArray.length; i++) {
var parameterArray = queryParametersArray[i].split('=');
if (parameterArray.length === 2) {
switch (parameterArray[0]) {
case 'documentId':
documentId = parameterArray[1];
break;
case 'workspaceId':
workspaceId = parameterArray[1];
break;
case 'elementId':
elementId = parameterArray[1];
break;
case 'server':
server = parameterArray[1];
break;
}
}
}
// Listen for clicks and post a message to the Onshape client
document.getElementById('<id of your topmost element>').
addEventListener('click', function() {
var message = {documentId: documentId,
workspaceId: workspaceId,
elementId: elementId,
messageName: 'closeFlyoutsAndMenus'};
window.parent.postMessage(message, '*');
}, true);
Create a message object
The message object posted to the Onshape client is of the form:
{
documentId: documentId,
workspaceId: workspaceId,
elementId: elementId,
messageName: '<message name>',
// … other properties as needed for other message types …
}
The message data object posted to the application extension is of the form:
{
messageName: '<message name>',
// … other properties as needed for other message types …
}
The message will always have a messageName
property.
Listen for messages
To listen for messages from the Onshape client:
// server is one of the iframe src query parameters - see above
var handlePostMessage = function(e) {
console.log("Post message received in application extension.");
console.log("e.origin = " + e.origin);
// Verify the origin matches the server iframe src query parameter
if (server === e.origin) {
console.log("Message safe and can be handled as it is from origin '"
+ e.origin +
"', which matches server query parameter '"
+ server + "'.");
if (e.data && e.data.messageName) {
console.log("Message name = '" + e.data.messageName + "'");
} else {
console.log("Message name not found. Ignoring message.");
}
} else {
console.log("Message NOT safe and should be ignored.");
}
};
window.addEventListener('message', handlePostMessage, false);
Send and handle messages
The following is an example of how one might send an initialization message to, and handle post messages from, the Onshape client.
Note: Proper clean-up of event listeners is not included in the snippet
function handlePostMessage(event) {
// ensure that the event data is from a legit source:
if(theServerStringFromActionUrl !== event.origin) {
console.error('origin of message is not legitimate');
return;
}
// branch based on messageName attribute
switch(event.data.messageName) {
case 'SELECTION':
console.debug('SELECTION event data: %o', event.data);
break;
default:
console.debug(`${event.data.messageName} not handled`);
}
}
window.addEventListener('message', handlePostMessage);
const initMessage = {
documentId: theDocumentId, // required - parsed from action url
workspaceId: theWorkspaceId, // required - parsed from action url
elementId: theElementId, // required - parsed from action url
messageName: 'applicationInit' // required
};
window.parent.postMessage(initMessage, '*');
Right panel interaction sequence
The sequence diagram below illustrates the interaction between an Element right panel application extension and the Onshape client:
%%{ init: { "theme": "default", "sequence": { "mirrorActors": false, "showSequenceNumbers": false, "width": 75, "height": 60, "actorMargin": 25, "messageFontSize": 13, "messageFontFamily": "monospace", "messageFontWeight": 2 } } }%% sequenceDiagram actor user participant OSC AS Onshape Client participant AE AS Application Extension user->>+OSC: start element right panel extension Note right of user: via configured button OSC->>+AE: invoke action url (with query params) AE->>OSC: postMessage(messageName: 'applicationInit') loop selection interactions user->>OSC: select OSC->>AE: postMessage(messageName: 'SELECTION') end user->>OSC: stop element right panel extension Note right of user: via configured button deactivate AE OSC-XAE: destroy deactivate OSC
Right panel message exchange
The following messages are exchanged for application extensions located in the element right panel and configured for Part Studio, Assembly, or Document contexts.
The first message with messageName
attribute set to applicationInit
is sent to the Onshape client by an application extension once it is loaded and ready to receive and process incoming messages:
{
documentId: '<document id>',
workspaceId: '<workspace id>',
elementId: '<element id>',
messageName: 'applicationInit'
}
The values <document id>
, <workspace id>
, <element id>
, and <server id>
:
- Are originally included as query parameters in the action URL used to request the content of the application extension
- Must be included in messages sent to the Onshape client
While initialization is the specific intent of the applicationInit
message, other supported messageName
attributes have the same initialization effect upon their first receipt by the Onshape client.
Next, as the user interacts with Onshape by selecting various parts of the model, messages with the messageName
attribute set to SELECTION
are sent to the application extension:
{
messageName: 'SELECTION',
selections: [
{
selectionType: 'ENTITY',
selectionId: 'KRiB',
entityType: 'FACE',
occurrencePath: [
'MfOieM8xKIDGHe37c'
],
workspaceMicroversionId: 'a781c53fbd1095e3462d2b70'
},
{
selectionType: 'ENTITY',
selectionId: 'KRdC',
entityType: 'EDGE',
occurrencePath: [
'MfOieM8xKIDGHe37c'
],
workspaceMicroversionId: 'a781c53fbd1095e3462d2b70'
}
]
}
Notes
Keyboard focus
Keyboard focus will not be transferred to an application until the user clicks in the application or the application programmatically takes focus. An application should programmatically take focus when it is first loaded and when it receives a show
message from Onshape. Shortcut keys will work immediately when the application is shown.
Future work
- New message types will be added as needed. If your application extension needs a message not listed in this document, please notify us, and we’ll work with you on it.
- Mobile client support is unclear at this time.
- Onshape is considering using promises to wrap
POST
messages, which would make the application extension’s JavaScript simpler and enable chainingPOST
s with other operations. Promises would make some interactions with multiple responses difficult (e.g., when you open a dialog, like the Select Item dialog, and want to receive multiplePOST
messages back due to the user clicking on multiple items in the dialog).