allow lti postMessage on assignment show page
why: * requested by studio, and it makes sense to respond to these messages in more places * possibly down the road monitor for messages on all pages instead of piecemeal * make sure only one message listener is active at a time closes INTEROP-7422 flag=none test plan: * edit an assignment and add a deep link to its description that points to the 1.3 test tool - make sure to include `{"width":400,"height":400}` in the iframe box so that it launches the tool in an iframe instead of a new window * save the assignment * open the browser dev tools console * in the assignment description, scroll to the bottom of the tool's iframe and send this postMessage: `{"subject":"lti.fetchWindowSize"}` * the console should show "message sent" and "message received" once * repeat the postMessage send while editing the assignment, should get the same result * turn on the assignments_2_student and assignments_2_teacher flags and make sure they are unlocked * repeat the postMessage while viewing the assignment, both as a student and as a teacher, should get one response message * as a teacher/admin, click into the description to edit it, and repeat the postMessage, should get one response message Change-Id: I5c8986d248cd1b9a344fba1060094aa97bfd7a86 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/291323 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> QA-Review: Tucker Mcknight <tmcknight@instructure.com> Product-Review: Alexis Nast <alexis.nast@instructure.com> Reviewed-by: Tucker Mcknight <tmcknight@instructure.com>
This commit is contained in:
parent
6194946c61
commit
b9dba671db
|
@ -1,5 +1,4 @@
|
|||
Using window.postMessage in LTI Tools
|
||||
=====================================
|
||||
# Using window.postMessage in LTI Tools
|
||||
|
||||
Canvas listens for events sent through the `window.postMessage` Javascript
|
||||
API (docs <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage" target="_blank">here</a>)
|
||||
|
@ -15,8 +14,10 @@ This token is present in the launch as a custom variable, `$com.instructure.Post
|
|||
should be passed in postMessage calls if it's present.
|
||||
|
||||
If the LTI tool is launched in a iframe, as is most common, then postMessages should be sent to
|
||||
`window.parent`. However, if the tool is launched in a new tab, window, or popup, then postMessages
|
||||
should be directed to `window.opener`. The examples will use `window.parent`.
|
||||
`window.top`. Usually `window.parent` should suffice, but there are some situations where that may
|
||||
not refer to the Canvas window. `window.top` refers to the topmost parent window, which should always
|
||||
be Canvas. However, if the tool is launched in a new tab, window, or popup, then postMessages
|
||||
should be directed to `window.opener`. The examples will use `window.top`.
|
||||
|
||||
# Message Types
|
||||
|
||||
|
@ -26,6 +27,7 @@ Launches the tool that sent the event in a full-window context (ie not inside a
|
|||
Mainly used for Safari launches, since Safari disables setting cookies inside iframes.
|
||||
|
||||
**Required properties:**
|
||||
|
||||
- subject: "requestFullWindowLaunch"
|
||||
- data: either a string or an object
|
||||
- if a string, a url for relaunching the tool
|
||||
|
@ -35,6 +37,7 @@ Mainly used for Safari launches, since Safari disables setting cookies inside if
|
|||
under the custom claim section (`https://www.instructure.com/placement`).
|
||||
|
||||
**Optional properties:**
|
||||
|
||||
- data.launchType: defaults to "same_window"
|
||||
- "same_window": launches the tool in the same window, replacing Canvas entirely
|
||||
- "new_window": launches the tool in a new tab/window, which depends on user preference
|
||||
|
@ -43,20 +46,20 @@ Mainly used for Safari launches, since Safari disables setting cookies inside if
|
|||
- data.launchOptions.height: for launchType: popup, defines the popup window's height. Defaults to 600.
|
||||
|
||||
```js
|
||||
window.parent.postMessage(
|
||||
window.top.postMessage(
|
||||
{
|
||||
subject: "requestFullWindowLaunch",
|
||||
subject: 'requestFullWindowLaunch',
|
||||
data: {
|
||||
url: "https://example-tool.com/launch",
|
||||
placement: "course_navigation",
|
||||
launchType: "new_window",
|
||||
url: 'https://example-tool.com/launch',
|
||||
placement: 'course_navigation',
|
||||
launchType: 'new_window',
|
||||
launchOptions: {
|
||||
width: 1000,
|
||||
height: 800
|
||||
}
|
||||
}
|
||||
},
|
||||
"*"
|
||||
'*'
|
||||
)
|
||||
```
|
||||
|
||||
|
@ -65,10 +68,11 @@ window.parent.postMessage(
|
|||
Opens and closes the course navigation sidebar, giving more space for the tool to display.
|
||||
|
||||
**Required properties:**
|
||||
|
||||
- subject: "toggleCourseNavigationMenu"
|
||||
|
||||
```js
|
||||
window.parent.postMessage({ subject: "toggleCourseNavigationMenu" }, "*")
|
||||
window.top.postMessage({subject: 'toggleCourseNavigationMenu'}, '*')
|
||||
```
|
||||
|
||||
## lti.resourceImported
|
||||
|
@ -78,10 +82,11 @@ Canvas will respond by reloading the page, if the tool was present in the extern
|
|||
apps tray. Used on wiki pages.
|
||||
|
||||
**Required properties:**
|
||||
|
||||
- subject: "lti.resourceImported"
|
||||
|
||||
```js
|
||||
window.parent.postMessage({ subject: "lti.resourceImported" }, "*")
|
||||
window.top.postMessage({subject: 'lti.resourceImported'}, '*')
|
||||
```
|
||||
|
||||
## lti.hideRightSideWrapper
|
||||
|
@ -89,14 +94,15 @@ window.parent.postMessage({ subject: "lti.resourceImported" }, "*")
|
|||
Tells Canvas to remove the right side nav in the assignments view.
|
||||
|
||||
**Required properties:**
|
||||
|
||||
- subject: "lti.hideRightSideWrapper"
|
||||
|
||||
```js
|
||||
window.parent.postMessage(
|
||||
window.top.postMessage(
|
||||
{
|
||||
subject: "lti.hideRightSideWrapper",
|
||||
subject: 'lti.hideRightSideWrapper'
|
||||
},
|
||||
"*"
|
||||
'*'
|
||||
)
|
||||
```
|
||||
|
||||
|
@ -105,19 +111,21 @@ window.parent.postMessage(
|
|||
Tells Canvas to change the height of the iframe containing the tool.
|
||||
|
||||
**Required properties:**
|
||||
|
||||
- subject: "lti.frameResize"
|
||||
- height: integer, in px
|
||||
|
||||
**Optional properties:**
|
||||
|
||||
- token: postMessage token, discussed above.
|
||||
|
||||
```js
|
||||
window.parent.postMessage(
|
||||
window.top.postMessage(
|
||||
{
|
||||
subject: "lti.frameResize",
|
||||
subject: 'lti.frameResize',
|
||||
height: 400
|
||||
},
|
||||
"*"
|
||||
'*'
|
||||
)
|
||||
```
|
||||
|
||||
|
@ -127,9 +135,11 @@ Sends a postMessage event back to the tool with details about the window size of
|
|||
the tool's containing iframe.
|
||||
|
||||
**Required properties:**
|
||||
|
||||
- subject: "lti.fetchWindowSize"
|
||||
|
||||
Returning postMessage includes the following properties:
|
||||
|
||||
- subject: "lti.fetchWindowSize.response"
|
||||
- height: height of the iframe
|
||||
- width: width of the iframe
|
||||
|
@ -138,7 +148,7 @@ Returning postMessage includes the following properties:
|
|||
- scrollY: the number of px that the iframe is scrolled vertically
|
||||
|
||||
```js
|
||||
window.parent.postMessage({ subject: "lti.fetchWindowSize" }, "*")
|
||||
window.top.postMessage({subject: 'lti.fetchWindowSize'}, '*')
|
||||
```
|
||||
|
||||
## lti.showModuleNavigation
|
||||
|
@ -146,16 +156,17 @@ window.parent.postMessage({ subject: "lti.fetchWindowSize" }, "*")
|
|||
Toggles the module navigation footer based on the message's content.
|
||||
|
||||
**Required properties:**
|
||||
|
||||
- subject: "lti.showModuleNavigation"
|
||||
- show: Boolean, whether to show or hide the footer
|
||||
|
||||
```js
|
||||
window.parent.postMessage(
|
||||
window.top.postMessage(
|
||||
{
|
||||
subject: "lti.frameResize",
|
||||
subject: 'lti.frameResize',
|
||||
show: true
|
||||
},
|
||||
"*"
|
||||
'*'
|
||||
)
|
||||
```
|
||||
|
||||
|
@ -164,10 +175,11 @@ window.parent.postMessage(
|
|||
Scrolls the iframe all the way to the top of its container.
|
||||
|
||||
**Required properties:**
|
||||
|
||||
- subject: "lti.scrollToTop"
|
||||
|
||||
```js
|
||||
window.parent.postMessage({ subject: "lti.scrollToTop" }, "*")
|
||||
window.top.postMessage({subject: 'lti.scrollToTop'}, '*')
|
||||
```
|
||||
|
||||
## lti.setUnloadMessage
|
||||
|
@ -176,16 +188,17 @@ Sets a message to be shown in a browser dialog before page closes (ie
|
|||
"Do you really want to leave this page?")
|
||||
|
||||
**Required properties:**
|
||||
|
||||
- subject: "lti.setUnloadMessage"
|
||||
- message: The message to be shown in the dialog
|
||||
|
||||
```js
|
||||
window.parent.postMessage(
|
||||
window.top.postMessage(
|
||||
{
|
||||
subject: "lti.setUnloadMessage",
|
||||
message: "Are you sure you want to leave this app?"
|
||||
subject: 'lti.setUnloadMessage',
|
||||
message: 'Are you sure you want to leave this app?'
|
||||
},
|
||||
"*"
|
||||
'*'
|
||||
)
|
||||
```
|
||||
|
||||
|
@ -194,10 +207,11 @@ window.parent.postMessage(
|
|||
Clears any set message to be shown on page close.
|
||||
|
||||
Required properties
|
||||
|
||||
- subject: "lti.removeUnloadMessage"
|
||||
|
||||
```js
|
||||
window.parent.postMessage({ subject: "lti.removeUnloadMessage" }, "*")
|
||||
window.top.postMessage({subject: 'lti.removeUnloadMessage'}, '*')
|
||||
```
|
||||
|
||||
## lti.screenReaderAlert
|
||||
|
@ -205,16 +219,17 @@ window.parent.postMessage({ subject: "lti.removeUnloadMessage" }, "*")
|
|||
Shows an alert for screen readers.
|
||||
|
||||
**Required properties:**
|
||||
|
||||
- subject: "lti.screenReaderAlert"
|
||||
- body: The contents of the alert.
|
||||
|
||||
```js
|
||||
window.parent.postMessage(
|
||||
window.top.postMessage(
|
||||
{
|
||||
subject: "lti.screenReaderAlert",
|
||||
body: "An alert just for screen readers"
|
||||
subject: 'lti.screenReaderAlert',
|
||||
body: 'An alert just for screen readers'
|
||||
},
|
||||
"*"
|
||||
'*'
|
||||
)
|
||||
```
|
||||
|
||||
|
@ -224,23 +239,25 @@ Shows an alert using Canvas's alert system, and includes the name of the LTI
|
|||
tool that sent the message.
|
||||
|
||||
**Required properties:**
|
||||
|
||||
- subject: "lti.showAlert"
|
||||
- body: The contents of the alert - can either be a string, or JSON string.
|
||||
|
||||
**Optional properties:**
|
||||
|
||||
- alertType: "success", "warning", or "error". Defaults to "success".
|
||||
- title: A display name for the tool. If not provided, Canvas will attempt to
|
||||
supply the tool name or default to "External Tool".
|
||||
|
||||
```js
|
||||
window.parent.postMessage(
|
||||
window.top.postMessage(
|
||||
{
|
||||
subject: "lti.showAlert",
|
||||
alertType: "warning",
|
||||
body: "An warning to be shown",
|
||||
title: "Tool Name"
|
||||
subject: 'lti.showAlert',
|
||||
alertType: 'warning',
|
||||
body: 'An warning to be shown',
|
||||
title: 'Tool Name'
|
||||
},
|
||||
"*"
|
||||
'*'
|
||||
)
|
||||
```
|
||||
|
||||
|
@ -250,12 +267,14 @@ Sends a debounced postMessage event to the tool every time its containing
|
|||
iframe is scrolled.
|
||||
|
||||
**Required properties:**
|
||||
|
||||
- subject: "lti.enableScrollEvents"
|
||||
|
||||
Returning postMessage includes the following properties:
|
||||
|
||||
- subject: "lti.scroll"
|
||||
- scrollY: the number of px that the iframe is scrolled vertically
|
||||
|
||||
```js
|
||||
window.parent.postMessage({ subject: "lti.enableScrollEvents" }, "*")
|
||||
window.top.postMessage({subject: 'lti.enableScrollEvents'}, '*')
|
||||
```
|
||||
|
|
|
@ -30,8 +30,10 @@ import GroupCategorySelector from '@canvas/groups/backbone/views/GroupCategorySe
|
|||
import PeerReviewsSelector from '@canvas/assignments/backbone/views/PeerReviewsSelector.coffee'
|
||||
import '@canvas/grading-standards'
|
||||
import LockManager from '@canvas/blueprint-courses/react/components/LockManager/index'
|
||||
import {monitorLtiMessages} from '@canvas/lti/jquery/messages'
|
||||
|
||||
ready(() => {
|
||||
monitorLtiMessages()
|
||||
const lockManager = new LockManager()
|
||||
lockManager.init({itemType: 'assignment', page: 'edit'})
|
||||
const lockedItems = lockManager.isChildContent() ? lockManager.getItemLocks() : {}
|
||||
|
|
|
@ -38,6 +38,7 @@ import DirectShareUserModal from '@canvas/direct-sharing/react/components/Direct
|
|||
import DirectShareCourseTray from '@canvas/direct-sharing/react/components/DirectShareCourseTray'
|
||||
import {setupSubmitHandler} from '@canvas/assignments/jquery/reuploadSubmissionsHelper'
|
||||
import ready from '@instructure/ready'
|
||||
import {monitorLtiMessages} from '@canvas/lti/jquery/messages'
|
||||
|
||||
const I18n = useI18nScope('assignment')
|
||||
|
||||
|
@ -45,6 +46,7 @@ ready(() => {
|
|||
const lockManager = new LockManager()
|
||||
lockManager.init({itemType: 'assignment', page: 'show'})
|
||||
renderCoursePacingNotice()
|
||||
monitorLtiMessages()
|
||||
})
|
||||
|
||||
let studentGroupSelectionRequestTrackers = []
|
||||
|
|
|
@ -17,8 +17,10 @@
|
|||
*/
|
||||
|
||||
import renderAssignmentsApp from './react/index'
|
||||
import $ from 'jquery'
|
||||
import ready from '@instructure/ready'
|
||||
import {monitorLtiMessages} from '@canvas/lti/jquery/messages'
|
||||
|
||||
$(() => {
|
||||
ready(() => {
|
||||
monitorLtiMessages()
|
||||
renderAssignmentsApp(ENV, $('<div/>').appendTo('#content')[0])
|
||||
})
|
||||
|
|
|
@ -18,8 +18,10 @@
|
|||
|
||||
import renderAssignmentsApp from './react/index'
|
||||
import ready from '@instructure/ready'
|
||||
import {monitorLtiMessages} from '@canvas/lti/jquery/messages'
|
||||
|
||||
ready(() => {
|
||||
monitorLtiMessages()
|
||||
const elt = document.getElementById('content')
|
||||
renderAssignmentsApp(ENV, elt)
|
||||
})
|
||||
|
|
|
@ -114,11 +114,17 @@ async function ltiMessageHandler(e, platformStorageFeatureFlag = false) {
|
|||
}
|
||||
}
|
||||
|
||||
let hasListener = false
|
||||
|
||||
function monitorLtiMessages() {
|
||||
const platformStorageFeatureFlag = ENV?.FEATURES?.lti_platform_storage
|
||||
window.addEventListener('message', e => {
|
||||
const cb = e => {
|
||||
if (e.data !== '') ltiMessageHandler(e, platformStorageFeatureFlag)
|
||||
})
|
||||
}
|
||||
if (!hasListener) {
|
||||
window.addEventListener('message', cb)
|
||||
hasListener = true
|
||||
}
|
||||
}
|
||||
|
||||
export {ltiState, SUBJECT_ALLOW_LIST, SUBJECT_IGNORE_LIST, ltiMessageHandler, monitorLtiMessages}
|
||||
|
|
Loading…
Reference in New Issue