fix iframe height when the viewport is smaller than 450px

why:
  The iframe used for LTI messages has 450px as minimum height

  When the user has a viewport smaller than the min-height (450px)
  and launches a tool in a fullscreen placement, the iframe is
  not resized

previous commit
  https://gerrit.instructure.com/c/canvas-lms/+/291039/8

  ignore PS 9 it got messed up

refs INTEROP-7431
flag=none

--------------------------------------------------
Test plan
--------------------------------------------------
* Compile the CSS and JS. Run:
  ```
  rake canvas:compile_assets_dev
  ```

* Open the Browser Developer Tools (F12)

* Open the Responsive Design Mode

* Choose a viewport smaller than 450px

* Launch any LTI tool from a fullscreen placement like global
  navigation

* The tool should fit the available height

* Exit the Responsive Design Mode and launch the tool from the
  same placement and the tool must also fit the available height

Change-Id: I043c9fb6e3a772f1237ba30d1a59162e3ae6da9a
Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/292646
Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
Reviewed-by: Evan Battaglia <ebattaglia@instructure.com>
QA-Review: Evan Battaglia <ebattaglia@instructure.com>
QA-Review: Ryan Hawkins <ryan.hawkins@instructure.com>
Product-Review: Alexis Nast <alexis.nast@instructure.com>
This commit is contained in:
Alexandre Trindade 2022-05-25 14:14:31 -03:00
parent 95963e668a
commit 32a9372888
4 changed files with 79 additions and 35 deletions

View File

@ -119,7 +119,13 @@ div.content_notice {
iframe.info_alert_outline {
border: 2px solid #0374B5 !important;
}
}
body.ic-full-screen-lti-tool iframe.tool_launch {
// gets the height of the parent element (div.tool_content_wrapper) which is calculated in
// ui/features/external_tools_show/jquery/tool_inline.js
min-height: 100%;
}
iframe.tool_launch {
min-height: 450px;

View File

@ -111,18 +111,30 @@ test('does not resize any other container', () => {
equal($('.tool_content_wrapper').height(), 300)
})
test('defaults the resize height to 450px', () => {
test('defaults the resize height to 450px if no `#tool_content` is found', () => {
document.querySelector('#second-wrapper').className = ''
document.querySelectorAll('#tool_content').forEach(element => {
element.id = 'another_tool_content'
})
const launchResizer = new ToolLaunchResizer()
launchResizer.resize_tool_content_wrapper()
equal($('.tool_content_wrapper').height(), 450)
document.querySelectorAll('#another_tool_content').forEach(element => {
element.id = 'tool_content'
})
document.querySelector('#second-wrapper').className = 'tool_content_wrapper'
})
test('defaults the resize height to 450px if non numeric value passed', () => {
test('defaults the resize height to 450px if non numeric value passed and no `#tool_content` is found', () => {
document.querySelector('#second-wrapper').className = ''
document.querySelectorAll('#tool_content').forEach(element => {
element.id = 'another_tool_content'
})
const launchResizer = new ToolLaunchResizer()
launchResizer.resize_tool_content_wrapper({a: 1})
equal($('.tool_content_wrapper').height(), 450)
document.querySelectorAll('#another_tool_content').forEach(element => {
element.id = 'tool_content'
})
document.querySelector('#second-wrapper').className = 'tool_content_wrapper'
})

View File

@ -17,7 +17,6 @@
*/
import $ from 'jquery'
import htmlEscape from 'html-escape'
import {trackEvent} from '@canvas/google-analytics'
import '@canvas/module-sequence-footer'
import MarkAsDone from '@canvas/util/jquery/markAsDone'
@ -27,10 +26,10 @@ import ready from '@instructure/ready'
ready(() => {
const $toolForm = $('#tool_form')
const launchToolManually = function() {
const $button = $toolForm.find('button')
const launchToolManually = function () {
const $button = $toolForm.find('button')
$toolForm.show()
// Firefox remembers disabled state after page reloads
@ -41,14 +40,12 @@ ready(() => {
$button.attr('disabled', true).text($button.data('expired_message'))
}, 60 * 2.5 * 1000)
$toolForm.submit(function() {
$(this)
.find('.load_tab,.tab_loaded')
.toggle()
})
}
$toolForm.submit(function () {
$(this).find('.load_tab,.tab_loaded').toggle()
})
}
const launchToolInNewTab = function() {
const launchToolInNewTab = function () {
$toolForm.attr('target', '_blank')
launchToolManually()
}
@ -62,12 +59,14 @@ ready(() => {
$toolForm.removeAttr('target')
try {
$toolForm.submit()
// eslint-disable-next-line no-empty
} catch (e) {}
break
default:
// Firefox throws an error when submitting insecure content
try {
$toolForm.submit()
// eslint-disable-next-line no-empty
} catch (e) {}
$('#tool_content').bind('load', () => {
@ -95,41 +94,65 @@ ready(() => {
trackEvent(messageType, toolName, toolPath)
// Iframe resize handler
let $tool_content_wrapper
let min_tool_height, canvas_chrome_height
const $tool_content_wrapper = $('.tool_content_wrapper')
let tool_height, canvas_chrome_height
const $window = $(window)
$tool_content_wrapper = $('.tool_content_wrapper')
const toolResizer = new ToolLaunchResizer(min_tool_height)
const $tool_content = $('iframe#tool_content')
const toolResizer = new ToolLaunchResizer(tool_height)
const $external_content_info_alerts = $tool_content_wrapper.find(
'.before_external_content_info_alert, .after_external_content_info_alert'
)
$external_content_info_alerts.on('focus', function(e) {
$external_content_info_alerts.on('focus', function () {
$tool_content_wrapper.find('iframe').css('border', '2px solid #0374B5')
$(this).removeClass('screenreader-only-tool')
})
$external_content_info_alerts.on('blur', function(e) {
$external_content_info_alerts.on('blur', function () {
$tool_content_wrapper.find('iframe').css('border', 'none')
$(this).addClass('screenreader-only-tool')
})
if (!$('body').hasClass('ic-full-screen-lti-tool')) {
const is_full_screen = $('body').hasClass('ic-full-screen-lti-tool')
if (!is_full_screen) {
canvas_chrome_height = $tool_content_wrapper.offset().top + $('#footer').outerHeight(true)
}
// Only calculate height on resize if body does not have
// .ic-full-screen-lti-tool class
if ($tool_content_wrapper.length && !$('body').hasClass('ic-full-screen-lti-tool')) {
if ($tool_content_wrapper.length) {
$window
.resize(() => {
.on('resize', () => {
// https://api.jquery.com/resize/
// https://developer.mozilla.org/en-US/docs/Web/API/Window/resize_event
if (!$tool_content_wrapper.data('height_overridden')) {
toolResizer.resize_tool_content_wrapper(
$window.height() - canvas_chrome_height - $('#sequence_footer').outerHeight(true)
)
if (is_full_screen) {
// divs from app/views/lti/_lti_message.html.erb that usually have 1px
const div_before_iframe =
document.querySelector('div.before_external_content_info_alert')?.offsetHeight || 0
const div_after_iframe =
document.querySelector('div.after_external_content_info_alert')?.offsetHeight || 0
// header#mobile-header
// hidden when screen width > 768px
// see app/stylesheets/base/_ic_app_header.scss
// see https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetHeight
const mobile_header_height =
document.querySelector('header#mobile-header')?.offsetHeight || 0
tool_height =
window.innerHeight - mobile_header_height - div_before_iframe - div_after_iframe
toolResizer.resize_tool_content_wrapper(tool_height, $tool_content_wrapper, true)
} else {
toolResizer.resize_tool_content_wrapper(
$window.height() -
canvas_chrome_height -
// module item navigation from PLAT-1687
$('#sequence_footer').outerHeight(true)
)
}
}
})
.triggerHandler('resize')
@ -143,7 +166,7 @@ ready(() => {
})
}
$('#content').on('click', '#mark-as-done-checkbox', function() {
$('#content').on('click', '#mark-as-done-checkbox', function () {
MarkAsDone.toggle(this)
})
})

View File

@ -29,18 +29,21 @@ export default class ToolLaunchResizer {
tool_content_wrapper(wrapperId) {
let container = $(`div[data-tool-wrapper-id*='${this.sanitizedWrapperId(wrapperId)}']`)
if (container.length <= 0 && $('.tool_content_wrapper').length === 1) {
container = $('.tool_content_wrapper')
const tool_content_wrapper = $('.tool_content_wrapper')
if (container.length <= 0 && tool_content_wrapper.length === 1) {
container = tool_content_wrapper
}
return container
}
resize_tool_content_wrapper(height, container) {
resize_tool_content_wrapper(height, container, force_height = false) {
let setHeight = height
if (typeof setHeight !== 'number') {
setHeight = this.minToolHeight
}
const toolWrapper = container || this.tool_content_wrapper()
toolWrapper.height(!height || this.minToolHeight > setHeight ? this.minToolHeight : setHeight)
if (force_height) toolWrapper.height(setHeight)
else
toolWrapper.height(!height || this.minToolHeight > setHeight ? this.minToolHeight : setHeight)
}
}