diff --git a/cc/export.php b/cc/export.php index a92225af29..1b4f18f7af 100644 --- a/cc/export.php +++ b/cc/export.php @@ -58,10 +58,10 @@

diff --git a/cc/index.php b/cc/index.php index 6591e2aeb9..8e279c79c4 100644 --- a/cc/index.php +++ b/cc/index.php @@ -66,10 +66,10 @@

@@ -129,10 +129,10 @@

diff --git a/lti/store/index.php b/lti/store/index.php index 80e6354a1b..fa9a33612b 100644 --- a/lti/store/index.php +++ b/lti/store/index.php @@ -802,6 +802,7 @@

+ diff --git a/vendor/tsugi/lib/src/Core/Launch.php b/vendor/tsugi/lib/src/Core/Launch.php index d19b2fd34f..c13b56ffa3 100644 --- a/vendor/tsugi/lib/src/Core/Launch.php +++ b/vendor/tsugi/lib/src/Core/Launch.php @@ -339,6 +339,41 @@ public function isCoursera() { } } + /** + * Return the document target + * The value for this property MUST be one of: frame, iframe, or window. + */ + public function documentTarget() { + $claim = $this->ltiJWTClaim(LTI13::PRESENTATION_CLAIM, null); + if ( is_object($claim) ) { + $target = null; + if ( isset($claim->{LTI13::DOCUMENT_TARGET}) ) { + $target = $claim->{LTI13::DOCUMENT_TARGET}; + } + return $target; + } else { + $target = $this->ltiRawParameter(LTIConstants::LAUNCH_PRESENTATION_DOCUMENT_TARGET, null); + return $target; + } + } + + /** + * Return the return Url + */ + public function returnUrl() { + $claim = $this->ltiJWTClaim(LTI13::PRESENTATION_CLAIM, null); + if ( is_object($claim) ) { + $target = null; + if ( isset($claim->{LTI13::RETURN_URL}) ) { + $target = $claim->{LTI13::RETURN_URL}; + } + return $target; + } else { + $target = $this->ltiRawParameter(LTIConstants::LAUNCH_PRESENTATION_RETURN_URL, null); + return $target; + } + } + /** * Return a boolean is this is an LTI Advantage launch */ diff --git a/vendor/tsugi/lib/src/UI/Output.php b/vendor/tsugi/lib/src/UI/Output.php index ed5b402664..e11a2c6cdc 100644 --- a/vendor/tsugi/lib/src/UI/Output.php +++ b/vendor/tsugi/lib/src/UI/Output.php @@ -266,7 +266,7 @@ function headerData() { $websocket_token = (WebSocket::enabled() && $LINK) ? '"'.WebSocket::getToken($LINK->launch).'"' : 'false'; $retval .= "websocket_token: ".$websocket_token.",\n"; $retval .= "react_token: \"".session_id()."\",\n"; - $retval .= "window_close_message: \""._m('Application complete')."\",\n"; + $retval .= "window_close_message: \""._m('Application complete - You can close this tab.')."\",\n"; $retval .= "session_expire_message: \""._m('Your session has expired')."\"\n"; $retval .= "\n}\n\n"; return $retval; @@ -847,7 +847,15 @@ function topNav($tool_menu=false) { global $CFG, $TSUGI_LAUNCH; $sess_key = 'tsugi_top_nav_'.$CFG->wwwroot; - $launch_return_url = LTIX::ltiRawParameter('launch_presentation_return_url', false); + // $launch_target = LTIX::ltiRawParameter('launch_presentation_document_target', false); + // $launch_return_url = LTIX::ltiRawParameter('launch_presentation_return_url', false); + $launch_target = null; + $launch_return_url = null; + if ( is_object($TSUGI_LAUNCH) ) { + $launch_target = $TSUGI_LAUNCH->documentTarget(); + $launch_return_url = $TSUGI_LAUNCH->returnUrl(); + } + // Ways to know if this was a launch or are we stand alone $user_id = LTIX::ltiRawParameter('user_id', false); $oauth_nonce = LTIX::ltiRawParameter('oauth_nonce', false); @@ -857,7 +865,6 @@ function topNav($tool_menu=false) { if ( $CFG->wwwroot && startsWith($launch_return_url, $CFG->wwwroot) ) $same_host = true; // Canvas bug: launch_target is iframe even in new window (2017-01-10) - $launch_target = LTIX::ltiRawParameter('launch_presentation_document_target', false); $menu_set = false; if ( $menu_set === false && $this->session_get($sess_key) ) { $menu_set = \Tsugi\UI\MenuSet::import($this->session_get($sess_key)); @@ -866,15 +873,19 @@ function topNav($tool_menu=false) { } else if ( $same_host && $launch_return_url ) { // If we are in an iframe we will be hidden $menu_set = self::returnMenuSet($launch_return_url); - } else if ( $launch_target !== false && strtolower($launch_target) == 'window' ) { + } else if ( is_string($launch_target) && strtolower($launch_target) == 'window' ) { + $menu_set = self::closeMenuSet(); + // Since Sakai sets returnUrl but really does nothing with it except tell the user + // to close the tab + } else if ( is_object($TSUGI_LAUNCH) && $TSUGI_LAUNCH->isSakai() ) { $menu_set = self::closeMenuSet(); - // Since Coursers sets precious little + // Since Coursera sets precious little } else if ( is_object($TSUGI_LAUNCH) && $TSUGI_LAUNCH->isCoursera() ) { $menu_set = self::closeMenuSet(); - // Since canvas does not set launch_target properly - } else if ( $launch_target !== false && is_object($TSUGI_LAUNCH) && ( $TSUGI_LAUNCH->isCanvas() || $TSUGI_LAUNCH->isCoursera() ) ) { + // Since Canvas does not set launch_target properly + } else if ( is_string($launch_target) && is_object($TSUGI_LAUNCH) && ( $TSUGI_LAUNCH->isCanvas() || $TSUGI_LAUNCH->isCoursera() ) ) { $menu_set = self::closeMenuSet(); - } else if ( $launch_return_url !== false && strlen($launch_return_url) > 0 ) { + } else if ( is_string($launch_return_url) && strlen($launch_return_url) > 0 ) { $menu_set = self::returnMenuSet($launch_return_url); // We are running stand alone (i.e. not from a real LTI Launch) } else if ( $user_id === false ) { diff --git a/vendor/tsugi/lib/src/Util/LTI13.php b/vendor/tsugi/lib/src/Util/LTI13.php index 3da9edc597..b06f1c9540 100644 --- a/vendor/tsugi/lib/src/Util/LTI13.php +++ b/vendor/tsugi/lib/src/Util/LTI13.php @@ -24,6 +24,13 @@ class LTI13 { const DEPLOYMENT_ID_CLAIM = 'https://purl.imsglobal.org/spec/lti/claim/deployment_id'; const ROLES_CLAIM = 'https://purl.imsglobal.org/spec/lti/claim/roles'; const PRESENTATION_CLAIM = 'https://purl.imsglobal.org/spec/lti/claim/launch_presentation'; + // The value for this property MUST be one of: frame, iframe, or window. + const DOCUMENT_TARGET = 'document_target'; + const DOCUMENT_TARGET_FRAME = 'frame'; + const DOCUMENT_TARGET_IFRAME = 'iframe'; + const DOCUMENT_TARGET_WINDOW = 'window'; + const RETURN_URL = 'return_url'; + const LTI11_TRANSITION_CLAIM = 'https://purl.imsglobal.org/spec/lti/claim/lti1p1'; const FOR_USER_CLAIM = 'https://purl.imsglobal.org/spec/lti/claim/for_user'; @@ -39,6 +46,7 @@ class LTI13 { const SCORE_TYPE = 'application/vnd.ims.lis.v1.score+json'; const RESULTS_TYPE = 'application/vnd.ims.lis.v2.resultcontainer+json'; + // https://www.imsglobal.org/spec/lti/v1p3/#platform-instance-claim const TOOL_PLATFORM_CLAIM = 'https://purl.imsglobal.org/spec/lti/claim/tool_platform'; const PRODUCT_FAMILY_CODE = "product_family_code";