canvas-lms/ui/index.js

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

242 lines
8.8 KiB
JavaScript
Raw Normal View History

/*
* Copyright (C) 2018 - present Instructure, Inc.
*
* This file is part of Canvas.
*
* Canvas is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3 of the License.
*
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
Insert language polyfills at page load time Refs FOO-1891 flag=none Canvas officially supports a fixed set of languages and locales. Unfortunately, not all browsers support all of those (the worst offender oddly enough is Google Chrome). Fortunately, polyfills for almost all of the Canvas supported languages are available via a polyfill package. This commit introduces a function that asynchronously loads the polyfill for a requested language. It does nothing if it sees there is already native support in the browser for that language. The function can be imported and run to dynamically switch in and out the polyfills as necessary, but since Canvas never changes ENV.LOCALE except at page load time, it should suffice to call it at front end initialization time; this was added to ui/index.js as a part of its "readiness" checks. The missing one (that NO browser supports) is Haitian Creole; we will have to probably build our own locale data file for that one. This takes care of polyfilling DateTimeFormat, NumberFormat, and RelativeTimeFormat. We can always add other Intl systems if the need arises. Test plan: * Be on Chrome (which does not support the Welsh language) * In the browser console, verify no native support for Welsh: Intl.DateTimeFormat.supportedLocalesOf(['cy']) ... should return an empty array * Go into your user settings on Canvas and change your language to Welsh (Cymraeg). Reload the page to make it take effect. Now your settings page should appear in Welsh. * In the browser console, verify that dates and times can be formatted correctly in Welsh (thanks to the polyfill): Intl.DateTimeFormat('cy', { dateStyle: 'long', timeStyle: 'long' }).format(new Date()) * That should display a date and time in Welsh (most prominently seen in the name of the month). Change-Id: I40632344ba1d8679aba1a976fcb55af97636be4b Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/267359 Reviewed-by: Ahmad Amireh <ahmad@instructure.com> Product-Review: Charley Kline <ckline@instructure.com> Product-Review: Ahmad Amireh <ahmad@instructure.com> QA-Review: Ahmad Amireh <ahmad@instructure.com> Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
2021-06-17 10:43:17 +08:00
import './boot/initializers/setWebpackCdnHost'
import '@canvas/jquery/jquery.instructure_jquery_patches' // this needs to be before anything else that requires jQuery
Insert language polyfills at page load time Refs FOO-1891 flag=none Canvas officially supports a fixed set of languages and locales. Unfortunately, not all browsers support all of those (the worst offender oddly enough is Google Chrome). Fortunately, polyfills for almost all of the Canvas supported languages are available via a polyfill package. This commit introduces a function that asynchronously loads the polyfill for a requested language. It does nothing if it sees there is already native support in the browser for that language. The function can be imported and run to dynamically switch in and out the polyfills as necessary, but since Canvas never changes ENV.LOCALE except at page load time, it should suffice to call it at front end initialization time; this was added to ui/index.js as a part of its "readiness" checks. The missing one (that NO browser supports) is Haitian Creole; we will have to probably build our own locale data file for that one. This takes care of polyfilling DateTimeFormat, NumberFormat, and RelativeTimeFormat. We can always add other Intl systems if the need arises. Test plan: * Be on Chrome (which does not support the Welsh language) * In the browser console, verify no native support for Welsh: Intl.DateTimeFormat.supportedLocalesOf(['cy']) ... should return an empty array * Go into your user settings on Canvas and change your language to Welsh (Cymraeg). Reload the page to make it take effect. Now your settings page should appear in Welsh. * In the browser console, verify that dates and times can be formatted correctly in Welsh (thanks to the polyfill): Intl.DateTimeFormat('cy', { dateStyle: 'long', timeStyle: 'long' }).format(new Date()) * That should display a date and time in Welsh (most prominently seen in the name of the month). Change-Id: I40632344ba1d8679aba1a976fcb55af97636be4b Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/267359 Reviewed-by: Ahmad Amireh <ahmad@instructure.com> Product-Review: Charley Kline <ckline@instructure.com> Product-Review: Ahmad Amireh <ahmad@instructure.com> QA-Review: Ahmad Amireh <ahmad@instructure.com> Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
2021-06-17 10:43:17 +08:00
import './boot'
// true modules that we use in this file
import $ from 'jquery'
Now that we have streaming, execute JS sooner Closes: COREFE-302 This will actually start executing the JS as soon as it comes in the <head> instead of waiting until after the </html> for it to start. What this means is that for any page that is streamed, we will start running our javascript sooner, as soon as the <head> is sent to the browser. So we can begin executing code while the server is still working on sending back the rest of the document. Note: this change makes it necessary for any endpoint that is streamed to have a check for DOMContentLoaded before doing anything that assumes elements will be there. I added this `@instructure/ready` helper do to that in all the places I could see. If the DOM is already loaded, `@instructure/ready` run the callback immediately (not in a setTimeout) so theoretically load/execution order should be _exactly_ the same for any response that is not streamed, even if it is wrapped in a “ready(…)” callback QA test plan: * click around in prod mode, especially on pages that are streamed make sure there are no thrown javascript errors or pages that fail to render * try both on a fast network as well as simulating a slow network with browser caching turned off (if you don’t know how to change your network speed simulation settings in Chrome, I can show you) * specifically look at pages that are streamed (like courses/x/discussions/y, /courses, courses/x/modules) Change-Id: I49a74ab480095e50cfa08dca8e074848dce12012 Reviewed-on: https://gerrit.instructure.com/203198 Tested-by: Jenkins Reviewed-by: Clay Diffrient <cdiffrient@instructure.com> QA-Review: Jeremy Putnam <jeremyp@instructure.com> Product-Review: Ryan Shaw <ryan@instructure.com>
2019-07-31 07:04:16 +08:00
import ready from '@instructure/ready'
import Backbone from '@canvas/backbone'
import splitAssetString from '@canvas/util/splitAssetString'
Load mathjax if we find any inline LaTex If the LaTex the user enters in the equation editor has errors, MathJax will typeset it, with the bad parts in red. Unfortunately the services canvas uses to generate the equation image simply fails. The equation editor now verifies the image can be created and if not will insert the raw LaTex into the RCE delimited by \(...\). Once the content is saved MathJax will typeset it (includeing the red, but hey, that's better than what used to happen) now also looks for $$ or \( starting delimiters mathjax uses to identify equations and looks for math on wiki pages, which was missing before (that is not behind the flag) had to skip some screenreader_gradebook specs that started failing with this change. The gradebook team is as baffled as I am. Will create a ticket for them to investigate. if MathJax finds LaTex errors (which you'll see as red in the preview area), the service that generates the equation image fails. This detects that and puts the raw LaTex back into the RCE's content. On saving, MathJax can process it, though it will still show the red. This is better than losing the equation because the image was missing. closes LS-1488 flag=inline_math_everywhere test plan - turn on SiteAdmin feature "Updated math equation handling" (flag=new_math_equation_handling) and the RootAccount feature "Support LaTex math equations almost everywhere" (flag=inline_math_everywhere) - in the RCE, enter \(your equation here\) - enter $$your equation here$$ - save > expect the first equation to be typeset and inline > expect the second equation to be typeset and a block - the equations can span over multiple lines too - edit an eq with the eq editor > expect it to be typeset too - in the RCE, click on the equation toolbar button - in the advanced pane of the equation editor, enter \var = 27 > expect the \var part to be red in the preview area (because it's undefined) - click Insert Equation > expect the raw LaTex to be in the RCE, surrounded by \(...\) - save > expect the equation to get typeset (and \var will still be red) - have an assignment with a student submission - grade the submission and include an equation in the comments for example: \(y = x^2\) - view the assignment as the student > expect the equation to be renered in the comment - put some math in an assignment's title > expect to see it in the assignments page - create a page with inline math in it > expect the math to be typeset - create a discussion with math - reply to the discussion with inline math in it - edit the inline math in the reply > expect the math to be typeset each time - have a student submit an assignemnt - as the teacher go to speedgrader > expect typeset math everywhere - add a comment with math > expect it to get typeset - goto /assignments/:id/submissions/:user_id > expect comments with math to be typeset - add a comment with math > epxect it go get typeset - old quizzes mostly work. While editing a question, inline math is not typeset, but will be when previewed or being taken - new module items can have math in their title, but if you edit the title, it's not typeset (this has baffled me, but it's got to be an extremely rare case) - load the calendar and flipping between Week, Month, Agenda views > expect entries with inline math in their title to be typeset - loading the calendar in different initial Views > expect events with math to be typeset - create a new event with math (e.g. "\(x^2\)"in the title > expect it to be typeset when saved - open an event in the calendar that has math in its body > expect it to be typeset Change-Id: Id5e1e822fad29a52bf21573e62976a4482afcf43 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/248246 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Charley Kline <ckline@instructure.com> QA-Review: Robin Kuss <rkuss@instructure.com> Product-Review: Peyton Craighill <pcraighill@instructure.com>
2020-09-23 06:13:35 +08:00
import mathml from 'mathml'
import preventDefault from 'prevent-default'
import loadBundle from 'bundles-generated'
// these are all things that either define global $.whatever or $.fn.blah
// methods or set something up that other code expects to exist at runtime.
// so they have to be ran before any other app code runs.
import '@canvas/jquery/jquery.ajaxJSON'
import '@canvas/forms/jquery/jquery.instructure_forms'
Insert language polyfills at page load time Refs FOO-1891 flag=none Canvas officially supports a fixed set of languages and locales. Unfortunately, not all browsers support all of those (the worst offender oddly enough is Google Chrome). Fortunately, polyfills for almost all of the Canvas supported languages are available via a polyfill package. This commit introduces a function that asynchronously loads the polyfill for a requested language. It does nothing if it sees there is already native support in the browser for that language. The function can be imported and run to dynamically switch in and out the polyfills as necessary, but since Canvas never changes ENV.LOCALE except at page load time, it should suffice to call it at front end initialization time; this was added to ui/index.js as a part of its "readiness" checks. The missing one (that NO browser supports) is Haitian Creole; we will have to probably build our own locale data file for that one. This takes care of polyfilling DateTimeFormat, NumberFormat, and RelativeTimeFormat. We can always add other Intl systems if the need arises. Test plan: * Be on Chrome (which does not support the Welsh language) * In the browser console, verify no native support for Welsh: Intl.DateTimeFormat.supportedLocalesOf(['cy']) ... should return an empty array * Go into your user settings on Canvas and change your language to Welsh (Cymraeg). Reload the page to make it take effect. Now your settings page should appear in Welsh. * In the browser console, verify that dates and times can be formatted correctly in Welsh (thanks to the polyfill): Intl.DateTimeFormat('cy', { dateStyle: 'long', timeStyle: 'long' }).format(new Date()) * That should display a date and time in Welsh (most prominently seen in the name of the month). Change-Id: I40632344ba1d8679aba1a976fcb55af97636be4b Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/267359 Reviewed-by: Ahmad Amireh <ahmad@instructure.com> Product-Review: Charley Kline <ckline@instructure.com> Product-Review: Ahmad Amireh <ahmad@instructure.com> QA-Review: Ahmad Amireh <ahmad@instructure.com> Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
2021-06-17 10:43:17 +08:00
import './boot/initializers/ajax_errors'
import './boot/initializers/activateKeyClicks'
import './boot/initializers/activateTooltips'
import './boot/initializers/injectAuthTokenIntoForms'
window.canvasReadyState = 'loading'
window.dispatchEvent(new CustomEvent('canvasReadyStateChange'))
Redo the locale polyfiller using new features from @formatjs Fixes FOO-2330 flag=none Canvas supports locales that not all browsers support, so we have to check for those cases and pull in a polyfilled version of the Intl functions that we use (DateTimeFormat, NumberFormat, and RelativeTimeFormat) when a locale is called for that the browser does not support. The first time the locale polyfiller was implemented, a lot of tests had to be done to see if there was an available polyfill for the given locale; this somehow broke Chrome after Version 92 so it was disabled for Chrome. However, latest versions of the @formatjs polyfillers are much smarter and can perform those checks and fallbacks themselves, which makes the Canvas polyfiller code way simpler and more stable. An additional issue was uncovered: when the locale is being polyfilled, NONE of the native locales can be accessed any more, so code relying on being able to get at, say, 'en-US' to do date arithmetic was failing. So when a polyfill loads, we save the browser's version as Native* (so Intl.DateTimeFormat --> Intl.NativeDateTimeFormat) so it can be accessed if needed (shouldn't be anywhere except in the ui/shared datetime support code). Another issue uncovered is that when a polyfill is necessary, it seems to take a long time... it can be SECONDS before it is fully loaded and its Promises resolve, at least in dev. Unfortunately a lot of front-end code can start up and begin to use Intl functions during that time, possibly with unpredictable results. The only real answer is to make the execution of immediate bundles, and the call to ready() to finish front-end initialization, wait pending the resolution of the Promise indicating that the locales have loaded. This is a bit unfortunate as it delays the execution of front-end code, but will only be noticeable in locales that need polyfilling because if a native locale is detected, the bundle loading and call to ready() will happen immediately as before. This commit does the following: - changes the Rails js_env to include LOCALES instead of LOCALE. LOCALES is a full list of locale strings in fallback order, so that if `sv-SE-x-k12` isn't found, it will try `sv-SE` and `sv-x-k12` and `sv` before finally falling back to `en`. The front-end startup code backfills ENV.LOCALE to ENV.LOCALES[0] for backward compatibility. - up-revs @formatjs to a more recent version that implements the check if a polyfill is available and leverages the LOCALES list to find an available polyfill. - Rewrites intl-polyfills to be smarter about detecting when a polyfill is necessary and whether it is possible. - Makes it easier to add new Intl subsystems to the polyfill code should they start getting used in the Canvas code somewhere. - Fixes up the helpers that relied upon the 'en-US' locale specifically. They now specifically check for the Native version of an Intl subsystem first. - Fixes up the changeTimezone helpers in ui/shared/datetime because they relied on the `en-US` locale always being available, which is not true when the locale has been polyfilled. That was kind of sketchy anyway because it relied on new Date() parsing a fairly free-form English date and time string; it now constructs an ISO8601 string which is much more supported as an argument to new Date(). Test plan: * Try some different locale scenarios and observe the behavior of Canvas in that language in general, and also specifically how it formats dates and times (this may be faster to do in console). * Pay particular attention to places where datepickers are used, specifically, create a new assignment and fiddle with the due dates down near the bottom. * Locale scenarios to try: a native locale like de or es -should just work a native locale with an extension like sv-x-k12 -should just work a polyfillable locale like cy or nn -should work with a console message saying it is polyfilled the one non-polyfillable locale: Kreyòl Ayisyen -should work via a fallback all the way to 'en' on console Change-Id: I93a1f2c3f0b3002747f564aba24c93d77244383e Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/284509 Reviewed-by: Ahmad Amireh <ahmad@instructure.com> QA-Review: Charley Kline <ckline@instructure.com> Product-Review: Charley Kline <ckline@instructure.com> Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
2022-02-05 08:03:25 +08:00
// Backfill LOCALE from LOCALES
if (!ENV.LOCALE && ENV.LOCALES instanceof Array) ENV.LOCALE = ENV.LOCALES[0]
const readinessTargets = [
Insert language polyfills at page load time Refs FOO-1891 flag=none Canvas officially supports a fixed set of languages and locales. Unfortunately, not all browsers support all of those (the worst offender oddly enough is Google Chrome). Fortunately, polyfills for almost all of the Canvas supported languages are available via a polyfill package. This commit introduces a function that asynchronously loads the polyfill for a requested language. It does nothing if it sees there is already native support in the browser for that language. The function can be imported and run to dynamically switch in and out the polyfills as necessary, but since Canvas never changes ENV.LOCALE except at page load time, it should suffice to call it at front end initialization time; this was added to ui/index.js as a part of its "readiness" checks. The missing one (that NO browser supports) is Haitian Creole; we will have to probably build our own locale data file for that one. This takes care of polyfilling DateTimeFormat, NumberFormat, and RelativeTimeFormat. We can always add other Intl systems if the need arises. Test plan: * Be on Chrome (which does not support the Welsh language) * In the browser console, verify no native support for Welsh: Intl.DateTimeFormat.supportedLocalesOf(['cy']) ... should return an empty array * Go into your user settings on Canvas and change your language to Welsh (Cymraeg). Reload the page to make it take effect. Now your settings page should appear in Welsh. * In the browser console, verify that dates and times can be formatted correctly in Welsh (thanks to the polyfill): Intl.DateTimeFormat('cy', { dateStyle: 'long', timeStyle: 'long' }).format(new Date()) * That should display a date and time in Welsh (most prominently seen in the name of the month). Change-Id: I40632344ba1d8679aba1a976fcb55af97636be4b Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/267359 Reviewed-by: Ahmad Amireh <ahmad@instructure.com> Product-Review: Charley Kline <ckline@instructure.com> Product-Review: Ahmad Amireh <ahmad@instructure.com> QA-Review: Ahmad Amireh <ahmad@instructure.com> Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
2021-06-17 10:43:17 +08:00
['asyncInitializers', false],
['deferredBundles', false],
['localeFiles', false],
Insert language polyfills at page load time Refs FOO-1891 flag=none Canvas officially supports a fixed set of languages and locales. Unfortunately, not all browsers support all of those (the worst offender oddly enough is Google Chrome). Fortunately, polyfills for almost all of the Canvas supported languages are available via a polyfill package. This commit introduces a function that asynchronously loads the polyfill for a requested language. It does nothing if it sees there is already native support in the browser for that language. The function can be imported and run to dynamically switch in and out the polyfills as necessary, but since Canvas never changes ENV.LOCALE except at page load time, it should suffice to call it at front end initialization time; this was added to ui/index.js as a part of its "readiness" checks. The missing one (that NO browser supports) is Haitian Creole; we will have to probably build our own locale data file for that one. This takes care of polyfilling DateTimeFormat, NumberFormat, and RelativeTimeFormat. We can always add other Intl systems if the need arises. Test plan: * Be on Chrome (which does not support the Welsh language) * In the browser console, verify no native support for Welsh: Intl.DateTimeFormat.supportedLocalesOf(['cy']) ... should return an empty array * Go into your user settings on Canvas and change your language to Welsh (Cymraeg). Reload the page to make it take effect. Now your settings page should appear in Welsh. * In the browser console, verify that dates and times can be formatted correctly in Welsh (thanks to the polyfill): Intl.DateTimeFormat('cy', { dateStyle: 'long', timeStyle: 'long' }).format(new Date()) * That should display a date and time in Welsh (most prominently seen in the name of the month). Change-Id: I40632344ba1d8679aba1a976fcb55af97636be4b Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/267359 Reviewed-by: Ahmad Amireh <ahmad@instructure.com> Product-Review: Charley Kline <ckline@instructure.com> Product-Review: Ahmad Amireh <ahmad@instructure.com> QA-Review: Ahmad Amireh <ahmad@instructure.com> Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
2021-06-17 10:43:17 +08:00
['localePolyfills', false]
]
const advanceReadiness = target => {
const entry = readinessTargets.find(x => x[0] === target)
if (!entry) {
throw new Error(`Invalid readiness target -- "${target}"`)
Insert language polyfills at page load time Refs FOO-1891 flag=none Canvas officially supports a fixed set of languages and locales. Unfortunately, not all browsers support all of those (the worst offender oddly enough is Google Chrome). Fortunately, polyfills for almost all of the Canvas supported languages are available via a polyfill package. This commit introduces a function that asynchronously loads the polyfill for a requested language. It does nothing if it sees there is already native support in the browser for that language. The function can be imported and run to dynamically switch in and out the polyfills as necessary, but since Canvas never changes ENV.LOCALE except at page load time, it should suffice to call it at front end initialization time; this was added to ui/index.js as a part of its "readiness" checks. The missing one (that NO browser supports) is Haitian Creole; we will have to probably build our own locale data file for that one. This takes care of polyfilling DateTimeFormat, NumberFormat, and RelativeTimeFormat. We can always add other Intl systems if the need arises. Test plan: * Be on Chrome (which does not support the Welsh language) * In the browser console, verify no native support for Welsh: Intl.DateTimeFormat.supportedLocalesOf(['cy']) ... should return an empty array * Go into your user settings on Canvas and change your language to Welsh (Cymraeg). Reload the page to make it take effect. Now your settings page should appear in Welsh. * In the browser console, verify that dates and times can be formatted correctly in Welsh (thanks to the polyfill): Intl.DateTimeFormat('cy', { dateStyle: 'long', timeStyle: 'long' }).format(new Date()) * That should display a date and time in Welsh (most prominently seen in the name of the month). Change-Id: I40632344ba1d8679aba1a976fcb55af97636be4b Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/267359 Reviewed-by: Ahmad Amireh <ahmad@instructure.com> Product-Review: Charley Kline <ckline@instructure.com> Product-Review: Ahmad Amireh <ahmad@instructure.com> QA-Review: Ahmad Amireh <ahmad@instructure.com> Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
2021-06-17 10:43:17 +08:00
} else if (entry[1]) {
throw new Error(`Target already marked ready -- "${target}"`)
}
entry[1] = true
window.dispatchEvent(new CustomEvent('canvasReadyStateChange', { detail: target }))
if (readinessTargets.every(x => x[1])) {
window.canvasReadyState = 'complete'
window.dispatchEvent(new CustomEvent('canvasReadyStateChange'))
}
}
Redo the locale polyfiller using new features from @formatjs Fixes FOO-2330 flag=none Canvas supports locales that not all browsers support, so we have to check for those cases and pull in a polyfilled version of the Intl functions that we use (DateTimeFormat, NumberFormat, and RelativeTimeFormat) when a locale is called for that the browser does not support. The first time the locale polyfiller was implemented, a lot of tests had to be done to see if there was an available polyfill for the given locale; this somehow broke Chrome after Version 92 so it was disabled for Chrome. However, latest versions of the @formatjs polyfillers are much smarter and can perform those checks and fallbacks themselves, which makes the Canvas polyfiller code way simpler and more stable. An additional issue was uncovered: when the locale is being polyfilled, NONE of the native locales can be accessed any more, so code relying on being able to get at, say, 'en-US' to do date arithmetic was failing. So when a polyfill loads, we save the browser's version as Native* (so Intl.DateTimeFormat --> Intl.NativeDateTimeFormat) so it can be accessed if needed (shouldn't be anywhere except in the ui/shared datetime support code). Another issue uncovered is that when a polyfill is necessary, it seems to take a long time... it can be SECONDS before it is fully loaded and its Promises resolve, at least in dev. Unfortunately a lot of front-end code can start up and begin to use Intl functions during that time, possibly with unpredictable results. The only real answer is to make the execution of immediate bundles, and the call to ready() to finish front-end initialization, wait pending the resolution of the Promise indicating that the locales have loaded. This is a bit unfortunate as it delays the execution of front-end code, but will only be noticeable in locales that need polyfilling because if a native locale is detected, the bundle loading and call to ready() will happen immediately as before. This commit does the following: - changes the Rails js_env to include LOCALES instead of LOCALE. LOCALES is a full list of locale strings in fallback order, so that if `sv-SE-x-k12` isn't found, it will try `sv-SE` and `sv-x-k12` and `sv` before finally falling back to `en`. The front-end startup code backfills ENV.LOCALE to ENV.LOCALES[0] for backward compatibility. - up-revs @formatjs to a more recent version that implements the check if a polyfill is available and leverages the LOCALES list to find an available polyfill. - Rewrites intl-polyfills to be smarter about detecting when a polyfill is necessary and whether it is possible. - Makes it easier to add new Intl subsystems to the polyfill code should they start getting used in the Canvas code somewhere. - Fixes up the helpers that relied upon the 'en-US' locale specifically. They now specifically check for the Native version of an Intl subsystem first. - Fixes up the changeTimezone helpers in ui/shared/datetime because they relied on the `en-US` locale always being available, which is not true when the locale has been polyfilled. That was kind of sketchy anyway because it relied on new Date() parsing a fairly free-form English date and time string; it now constructs an ISO8601 string which is much more supported as an argument to new Date(). Test plan: * Try some different locale scenarios and observe the behavior of Canvas in that language in general, and also specifically how it formats dates and times (this may be faster to do in console). * Pay particular attention to places where datepickers are used, specifically, create a new assignment and fiddle with the due dates down near the bottom. * Locale scenarios to try: a native locale like de or es -should just work a native locale with an extension like sv-x-k12 -should just work a polyfillable locale like cy or nn -should work with a console message saying it is polyfilled the one non-polyfillable locale: Kreyòl Ayisyen -should work via a fallback all the way to 'en' on console Change-Id: I93a1f2c3f0b3002747f564aba24c93d77244383e Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/284509 Reviewed-by: Ahmad Amireh <ahmad@instructure.com> QA-Review: Charley Kline <ckline@instructure.com> Product-Review: Charley Kline <ckline@instructure.com> Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
2022-02-05 08:03:25 +08:00
function afterDocumentReady() {
Insert language polyfills at page load time Refs FOO-1891 flag=none Canvas officially supports a fixed set of languages and locales. Unfortunately, not all browsers support all of those (the worst offender oddly enough is Google Chrome). Fortunately, polyfills for almost all of the Canvas supported languages are available via a polyfill package. This commit introduces a function that asynchronously loads the polyfill for a requested language. It does nothing if it sees there is already native support in the browser for that language. The function can be imported and run to dynamically switch in and out the polyfills as necessary, but since Canvas never changes ENV.LOCALE except at page load time, it should suffice to call it at front end initialization time; this was added to ui/index.js as a part of its "readiness" checks. The missing one (that NO browser supports) is Haitian Creole; we will have to probably build our own locale data file for that one. This takes care of polyfilling DateTimeFormat, NumberFormat, and RelativeTimeFormat. We can always add other Intl systems if the need arises. Test plan: * Be on Chrome (which does not support the Welsh language) * In the browser console, verify no native support for Welsh: Intl.DateTimeFormat.supportedLocalesOf(['cy']) ... should return an empty array * Go into your user settings on Canvas and change your language to Welsh (Cymraeg). Reload the page to make it take effect. Now your settings page should appear in Welsh. * In the browser console, verify that dates and times can be formatted correctly in Welsh (thanks to the polyfill): Intl.DateTimeFormat('cy', { dateStyle: 'long', timeStyle: 'long' }).format(new Date()) * That should display a date and time in Welsh (most prominently seen in the name of the month). Change-Id: I40632344ba1d8679aba1a976fcb55af97636be4b Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/267359 Reviewed-by: Ahmad Amireh <ahmad@instructure.com> Product-Review: Charley Kline <ckline@instructure.com> Product-Review: Ahmad Amireh <ahmad@instructure.com> QA-Review: Ahmad Amireh <ahmad@instructure.com> Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
2021-06-17 10:43:17 +08:00
// eslint-disable-next-line promise/catch-or-return
Redo the locale polyfiller using new features from @formatjs Fixes FOO-2330 flag=none Canvas supports locales that not all browsers support, so we have to check for those cases and pull in a polyfilled version of the Intl functions that we use (DateTimeFormat, NumberFormat, and RelativeTimeFormat) when a locale is called for that the browser does not support. The first time the locale polyfiller was implemented, a lot of tests had to be done to see if there was an available polyfill for the given locale; this somehow broke Chrome after Version 92 so it was disabled for Chrome. However, latest versions of the @formatjs polyfillers are much smarter and can perform those checks and fallbacks themselves, which makes the Canvas polyfiller code way simpler and more stable. An additional issue was uncovered: when the locale is being polyfilled, NONE of the native locales can be accessed any more, so code relying on being able to get at, say, 'en-US' to do date arithmetic was failing. So when a polyfill loads, we save the browser's version as Native* (so Intl.DateTimeFormat --> Intl.NativeDateTimeFormat) so it can be accessed if needed (shouldn't be anywhere except in the ui/shared datetime support code). Another issue uncovered is that when a polyfill is necessary, it seems to take a long time... it can be SECONDS before it is fully loaded and its Promises resolve, at least in dev. Unfortunately a lot of front-end code can start up and begin to use Intl functions during that time, possibly with unpredictable results. The only real answer is to make the execution of immediate bundles, and the call to ready() to finish front-end initialization, wait pending the resolution of the Promise indicating that the locales have loaded. This is a bit unfortunate as it delays the execution of front-end code, but will only be noticeable in locales that need polyfilling because if a native locale is detected, the bundle loading and call to ready() will happen immediately as before. This commit does the following: - changes the Rails js_env to include LOCALES instead of LOCALE. LOCALES is a full list of locale strings in fallback order, so that if `sv-SE-x-k12` isn't found, it will try `sv-SE` and `sv-x-k12` and `sv` before finally falling back to `en`. The front-end startup code backfills ENV.LOCALE to ENV.LOCALES[0] for backward compatibility. - up-revs @formatjs to a more recent version that implements the check if a polyfill is available and leverages the LOCALES list to find an available polyfill. - Rewrites intl-polyfills to be smarter about detecting when a polyfill is necessary and whether it is possible. - Makes it easier to add new Intl subsystems to the polyfill code should they start getting used in the Canvas code somewhere. - Fixes up the helpers that relied upon the 'en-US' locale specifically. They now specifically check for the Native version of an Intl subsystem first. - Fixes up the changeTimezone helpers in ui/shared/datetime because they relied on the `en-US` locale always being available, which is not true when the locale has been polyfilled. That was kind of sketchy anyway because it relied on new Date() parsing a fairly free-form English date and time string; it now constructs an ISO8601 string which is much more supported as an argument to new Date(). Test plan: * Try some different locale scenarios and observe the behavior of Canvas in that language in general, and also specifically how it formats dates and times (this may be faster to do in console). * Pay particular attention to places where datepickers are used, specifically, create a new assignment and fiddle with the due dates down near the bottom. * Locale scenarios to try: a native locale like de or es -should just work a native locale with an extension like sv-x-k12 -should just work a polyfillable locale like cy or nn -should work with a console message saying it is polyfilled the one non-polyfillable locale: Kreyòl Ayisyen -should work via a fallback all the way to 'en' on console Change-Id: I93a1f2c3f0b3002747f564aba24c93d77244383e Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/284509 Reviewed-by: Ahmad Amireh <ahmad@instructure.com> QA-Review: Charley Kline <ckline@instructure.com> Product-Review: Charley Kline <ckline@instructure.com> Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
2022-02-05 08:03:25 +08:00
Promise.all((window.deferredBundles || []).map(loadBundle)).then(() => {
Insert language polyfills at page load time Refs FOO-1891 flag=none Canvas officially supports a fixed set of languages and locales. Unfortunately, not all browsers support all of those (the worst offender oddly enough is Google Chrome). Fortunately, polyfills for almost all of the Canvas supported languages are available via a polyfill package. This commit introduces a function that asynchronously loads the polyfill for a requested language. It does nothing if it sees there is already native support in the browser for that language. The function can be imported and run to dynamically switch in and out the polyfills as necessary, but since Canvas never changes ENV.LOCALE except at page load time, it should suffice to call it at front end initialization time; this was added to ui/index.js as a part of its "readiness" checks. The missing one (that NO browser supports) is Haitian Creole; we will have to probably build our own locale data file for that one. This takes care of polyfilling DateTimeFormat, NumberFormat, and RelativeTimeFormat. We can always add other Intl systems if the need arises. Test plan: * Be on Chrome (which does not support the Welsh language) * In the browser console, verify no native support for Welsh: Intl.DateTimeFormat.supportedLocalesOf(['cy']) ... should return an empty array * Go into your user settings on Canvas and change your language to Welsh (Cymraeg). Reload the page to make it take effect. Now your settings page should appear in Welsh. * In the browser console, verify that dates and times can be formatted correctly in Welsh (thanks to the polyfill): Intl.DateTimeFormat('cy', { dateStyle: 'long', timeStyle: 'long' }).format(new Date()) * That should display a date and time in Welsh (most prominently seen in the name of the month). Change-Id: I40632344ba1d8679aba1a976fcb55af97636be4b Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/267359 Reviewed-by: Ahmad Amireh <ahmad@instructure.com> Product-Review: Charley Kline <ckline@instructure.com> Product-Review: Ahmad Amireh <ahmad@instructure.com> QA-Review: Ahmad Amireh <ahmad@instructure.com> Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
2021-06-17 10:43:17 +08:00
advanceReadiness('deferredBundles')
Redo the locale polyfiller using new features from @formatjs Fixes FOO-2330 flag=none Canvas supports locales that not all browsers support, so we have to check for those cases and pull in a polyfilled version of the Intl functions that we use (DateTimeFormat, NumberFormat, and RelativeTimeFormat) when a locale is called for that the browser does not support. The first time the locale polyfiller was implemented, a lot of tests had to be done to see if there was an available polyfill for the given locale; this somehow broke Chrome after Version 92 so it was disabled for Chrome. However, latest versions of the @formatjs polyfillers are much smarter and can perform those checks and fallbacks themselves, which makes the Canvas polyfiller code way simpler and more stable. An additional issue was uncovered: when the locale is being polyfilled, NONE of the native locales can be accessed any more, so code relying on being able to get at, say, 'en-US' to do date arithmetic was failing. So when a polyfill loads, we save the browser's version as Native* (so Intl.DateTimeFormat --> Intl.NativeDateTimeFormat) so it can be accessed if needed (shouldn't be anywhere except in the ui/shared datetime support code). Another issue uncovered is that when a polyfill is necessary, it seems to take a long time... it can be SECONDS before it is fully loaded and its Promises resolve, at least in dev. Unfortunately a lot of front-end code can start up and begin to use Intl functions during that time, possibly with unpredictable results. The only real answer is to make the execution of immediate bundles, and the call to ready() to finish front-end initialization, wait pending the resolution of the Promise indicating that the locales have loaded. This is a bit unfortunate as it delays the execution of front-end code, but will only be noticeable in locales that need polyfilling because if a native locale is detected, the bundle loading and call to ready() will happen immediately as before. This commit does the following: - changes the Rails js_env to include LOCALES instead of LOCALE. LOCALES is a full list of locale strings in fallback order, so that if `sv-SE-x-k12` isn't found, it will try `sv-SE` and `sv-x-k12` and `sv` before finally falling back to `en`. The front-end startup code backfills ENV.LOCALE to ENV.LOCALES[0] for backward compatibility. - up-revs @formatjs to a more recent version that implements the check if a polyfill is available and leverages the LOCALES list to find an available polyfill. - Rewrites intl-polyfills to be smarter about detecting when a polyfill is necessary and whether it is possible. - Makes it easier to add new Intl subsystems to the polyfill code should they start getting used in the Canvas code somewhere. - Fixes up the helpers that relied upon the 'en-US' locale specifically. They now specifically check for the Native version of an Intl subsystem first. - Fixes up the changeTimezone helpers in ui/shared/datetime because they relied on the `en-US` locale always being available, which is not true when the locale has been polyfilled. That was kind of sketchy anyway because it relied on new Date() parsing a fairly free-form English date and time string; it now constructs an ISO8601 string which is much more supported as an argument to new Date(). Test plan: * Try some different locale scenarios and observe the behavior of Canvas in that language in general, and also specifically how it formats dates and times (this may be faster to do in console). * Pay particular attention to places where datepickers are used, specifically, create a new assignment and fiddle with the due dates down near the bottom. * Locale scenarios to try: a native locale like de or es -should just work a native locale with an extension like sv-x-k12 -should just work a polyfillable locale like cy or nn -should work with a console message saying it is polyfilled the one non-polyfillable locale: Kreyòl Ayisyen -should work via a fallback all the way to 'en' on console Change-Id: I93a1f2c3f0b3002747f564aba24c93d77244383e Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/284509 Reviewed-by: Ahmad Amireh <ahmad@instructure.com> QA-Review: Charley Kline <ckline@instructure.com> Product-Review: Charley Kline <ckline@instructure.com> Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
2022-02-05 08:03:25 +08:00
})
// LS-1662: there are math equations on the page that
// we don't see, so remain invisible and aren't
// typeset my MathJax. Let's trick Canvas into knowing
// there's math on the page by putting some there.
if (!/quizzes\/\d*\/edit/.test(window.location.pathname)) {
if (document.querySelector('.math_equation_latex')) {
const elem = document.createElement('math')
elem.innerHTML = '&nbsp;'
document.body.appendChild(elem)
}
}
if (!ENV?.FEATURES?.new_math_equation_handling) {
// This is in a setTimeout to have it run on the next time through the event loop
// so that the code that actually renders the user_content runs first,
// because it has to be rendered before we can check if isMathMLOnPage
setTimeout(() => {
if (mathml.isMathOnPage()) mathml.loadMathJax(undefined)
}, 5)
return
}
// This is in a setTimeout to have it run on the next time through the event loop
// so that the code that actually renders the user_content runs first,
Load mathjax if we find any inline LaTex If the LaTex the user enters in the equation editor has errors, MathJax will typeset it, with the bad parts in red. Unfortunately the services canvas uses to generate the equation image simply fails. The equation editor now verifies the image can be created and if not will insert the raw LaTex into the RCE delimited by \(...\). Once the content is saved MathJax will typeset it (includeing the red, but hey, that's better than what used to happen) now also looks for $$ or \( starting delimiters mathjax uses to identify equations and looks for math on wiki pages, which was missing before (that is not behind the flag) had to skip some screenreader_gradebook specs that started failing with this change. The gradebook team is as baffled as I am. Will create a ticket for them to investigate. if MathJax finds LaTex errors (which you'll see as red in the preview area), the service that generates the equation image fails. This detects that and puts the raw LaTex back into the RCE's content. On saving, MathJax can process it, though it will still show the red. This is better than losing the equation because the image was missing. closes LS-1488 flag=inline_math_everywhere test plan - turn on SiteAdmin feature "Updated math equation handling" (flag=new_math_equation_handling) and the RootAccount feature "Support LaTex math equations almost everywhere" (flag=inline_math_everywhere) - in the RCE, enter \(your equation here\) - enter $$your equation here$$ - save > expect the first equation to be typeset and inline > expect the second equation to be typeset and a block - the equations can span over multiple lines too - edit an eq with the eq editor > expect it to be typeset too - in the RCE, click on the equation toolbar button - in the advanced pane of the equation editor, enter \var = 27 > expect the \var part to be red in the preview area (because it's undefined) - click Insert Equation > expect the raw LaTex to be in the RCE, surrounded by \(...\) - save > expect the equation to get typeset (and \var will still be red) - have an assignment with a student submission - grade the submission and include an equation in the comments for example: \(y = x^2\) - view the assignment as the student > expect the equation to be renered in the comment - put some math in an assignment's title > expect to see it in the assignments page - create a page with inline math in it > expect the math to be typeset - create a discussion with math - reply to the discussion with inline math in it - edit the inline math in the reply > expect the math to be typeset each time - have a student submit an assignemnt - as the teacher go to speedgrader > expect typeset math everywhere - add a comment with math > expect it to get typeset - goto /assignments/:id/submissions/:user_id > expect comments with math to be typeset - add a comment with math > epxect it go get typeset - old quizzes mostly work. While editing a question, inline math is not typeset, but will be when previewed or being taken - new module items can have math in their title, but if you edit the title, it's not typeset (this has baffled me, but it's got to be an extremely rare case) - load the calendar and flipping between Week, Month, Agenda views > expect entries with inline math in their title to be typeset - loading the calendar in different initial Views > expect events with math to be typeset - create a new event with math (e.g. "\(x^2\)"in the title > expect it to be typeset when saved - open an event in the calendar that has math in its body > expect it to be typeset Change-Id: Id5e1e822fad29a52bf21573e62976a4482afcf43 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/248246 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Charley Kline <ckline@instructure.com> QA-Review: Robin Kuss <rkuss@instructure.com> Product-Review: Peyton Craighill <pcraighill@instructure.com>
2020-09-23 06:13:35 +08:00
// because it has to be rendered before we can check if isMathOnPage
Make typeset math and math image match at least get them much closer. 1. typeset math using svg by default, which is how the image is generated 2. size the image so it matches the surrounding font-size Also, still typeset math from images even if the image fails to load. closes MAT-501 flag=new_math_equation_handling SIZING MATH REQUIRES A COMPANION CHANGE TO MATHMAN (the other stuff doesn't) - clone git clone ssh://<yourid>@gerrit.instructure.com:29418/mathman and follow the instructions for building. - checkout https://gerrit.instructure.com/c/mathman/+/277389 - build it (once built, you don't have to run in in docker) - in a canvas rails console: Setting.set( 'equation_image_url, 'http://localhost:8000/svg?tex=' ) http://localhost:8000 is where mathman is via `node app.js` it's at http://mathman.docker if in docker (at least that's what the README says, I don't really know) - test mathman by requesting `http://<mathman-url>/svg?tex=17` and expect an image of "17". now try with `request /svg?tex=17&scale=2` and your "17" shoul be twice as large. - restart your canvas server test plan: Updated typesetting: - have a question_bank quetsion with math and answers with math - include the question in a quiz > verify that the question looks the same in the question bank as it does when previewing/taking the quiz - if your math includes a "g", it should look the same - the size of the equation should be pretty close Sizing to match: - turn on scale_math_equations site admin feature - put an equation w/in a paragraph with a large font, or add an equation to the rce, select it, and change the font size - click on the equation, edit equation, click insert equation w/o changing anything > expect the equation to match the larger font. - extra credit: DO THIS WITH AND WITHOUT MATHMAN PLUGIN ENABLED (yes, there are 2 paths canvas takes to mathman) make sure to update dyanmic-settings.yml's math-man entry math-man: base_url: 'http://localhost:8000' use_for_svg: 'true' use_for_mml: 'false' - at /plugins, enable mathman plugin and ensure use_for_svg istrue Error handling: - change the URL to mathman to a dead end - load a page with math equation images > expect the math to be typeset by mathjax Change-Id: I354e98a0a0256740ce5b4937f5b4e3adc690fe51 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/277245 Reviewed-by: Weston Dransfield <wdransfield@instructure.com> Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> QA-Review: Weston Dransfield <wdransfield@instructure.com> Product-Review: David Lyons <lyons@instructure.com>
2021-11-02 20:52:12 +08:00
let processedBodyMath = false
setTimeout(() => {
Make typeset math and math image match at least get them much closer. 1. typeset math using svg by default, which is how the image is generated 2. size the image so it matches the surrounding font-size Also, still typeset math from images even if the image fails to load. closes MAT-501 flag=new_math_equation_handling SIZING MATH REQUIRES A COMPANION CHANGE TO MATHMAN (the other stuff doesn't) - clone git clone ssh://<yourid>@gerrit.instructure.com:29418/mathman and follow the instructions for building. - checkout https://gerrit.instructure.com/c/mathman/+/277389 - build it (once built, you don't have to run in in docker) - in a canvas rails console: Setting.set( 'equation_image_url, 'http://localhost:8000/svg?tex=' ) http://localhost:8000 is where mathman is via `node app.js` it's at http://mathman.docker if in docker (at least that's what the README says, I don't really know) - test mathman by requesting `http://<mathman-url>/svg?tex=17` and expect an image of "17". now try with `request /svg?tex=17&scale=2` and your "17" shoul be twice as large. - restart your canvas server test plan: Updated typesetting: - have a question_bank quetsion with math and answers with math - include the question in a quiz > verify that the question looks the same in the question bank as it does when previewing/taking the quiz - if your math includes a "g", it should look the same - the size of the equation should be pretty close Sizing to match: - turn on scale_math_equations site admin feature - put an equation w/in a paragraph with a large font, or add an equation to the rce, select it, and change the font size - click on the equation, edit equation, click insert equation w/o changing anything > expect the equation to match the larger font. - extra credit: DO THIS WITH AND WITHOUT MATHMAN PLUGIN ENABLED (yes, there are 2 paths canvas takes to mathman) make sure to update dyanmic-settings.yml's math-man entry math-man: base_url: 'http://localhost:8000' use_for_svg: 'true' use_for_mml: 'false' - at /plugins, enable mathman plugin and ensure use_for_svg istrue Error handling: - change the URL to mathman to a dead end - load a page with math equation images > expect the math to be typeset by mathjax Change-Id: I354e98a0a0256740ce5b4937f5b4e3adc690fe51 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/277245 Reviewed-by: Weston Dransfield <wdransfield@instructure.com> Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> QA-Review: Weston Dransfield <wdransfield@instructure.com> Product-Review: David Lyons <lyons@instructure.com>
2021-11-02 20:52:12 +08:00
processedBodyMath = true
window.dispatchEvent(
new CustomEvent(mathml.processNewMathEventName, {
detail: {target: document.body}
})
)
Load mathjax if we find any inline LaTex If the LaTex the user enters in the equation editor has errors, MathJax will typeset it, with the bad parts in red. Unfortunately the services canvas uses to generate the equation image simply fails. The equation editor now verifies the image can be created and if not will insert the raw LaTex into the RCE delimited by \(...\). Once the content is saved MathJax will typeset it (includeing the red, but hey, that's better than what used to happen) now also looks for $$ or \( starting delimiters mathjax uses to identify equations and looks for math on wiki pages, which was missing before (that is not behind the flag) had to skip some screenreader_gradebook specs that started failing with this change. The gradebook team is as baffled as I am. Will create a ticket for them to investigate. if MathJax finds LaTex errors (which you'll see as red in the preview area), the service that generates the equation image fails. This detects that and puts the raw LaTex back into the RCE's content. On saving, MathJax can process it, though it will still show the red. This is better than losing the equation because the image was missing. closes LS-1488 flag=inline_math_everywhere test plan - turn on SiteAdmin feature "Updated math equation handling" (flag=new_math_equation_handling) and the RootAccount feature "Support LaTex math equations almost everywhere" (flag=inline_math_everywhere) - in the RCE, enter \(your equation here\) - enter $$your equation here$$ - save > expect the first equation to be typeset and inline > expect the second equation to be typeset and a block - the equations can span over multiple lines too - edit an eq with the eq editor > expect it to be typeset too - in the RCE, click on the equation toolbar button - in the advanced pane of the equation editor, enter \var = 27 > expect the \var part to be red in the preview area (because it's undefined) - click Insert Equation > expect the raw LaTex to be in the RCE, surrounded by \(...\) - save > expect the equation to get typeset (and \var will still be red) - have an assignment with a student submission - grade the submission and include an equation in the comments for example: \(y = x^2\) - view the assignment as the student > expect the equation to be renered in the comment - put some math in an assignment's title > expect to see it in the assignments page - create a page with inline math in it > expect the math to be typeset - create a discussion with math - reply to the discussion with inline math in it - edit the inline math in the reply > expect the math to be typeset each time - have a student submit an assignemnt - as the teacher go to speedgrader > expect typeset math everywhere - add a comment with math > expect it to get typeset - goto /assignments/:id/submissions/:user_id > expect comments with math to be typeset - add a comment with math > epxect it go get typeset - old quizzes mostly work. While editing a question, inline math is not typeset, but will be when previewed or being taken - new module items can have math in their title, but if you edit the title, it's not typeset (this has baffled me, but it's got to be an extremely rare case) - load the calendar and flipping between Week, Month, Agenda views > expect entries with inline math in their title to be typeset - loading the calendar in different initial Views > expect events with math to be typeset - create a new event with math (e.g. "\(x^2\)"in the title > expect it to be typeset when saved - open an event in the calendar that has math in its body > expect it to be typeset Change-Id: Id5e1e822fad29a52bf21573e62976a4482afcf43 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/248246 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Charley Kline <ckline@instructure.com> QA-Review: Robin Kuss <rkuss@instructure.com> Product-Review: Peyton Craighill <pcraighill@instructure.com>
2020-09-23 06:13:35 +08:00
}, 0)
const observer = new MutationObserver((mutationList, _observer) => {
Make typeset math and math image match at least get them much closer. 1. typeset math using svg by default, which is how the image is generated 2. size the image so it matches the surrounding font-size Also, still typeset math from images even if the image fails to load. closes MAT-501 flag=new_math_equation_handling SIZING MATH REQUIRES A COMPANION CHANGE TO MATHMAN (the other stuff doesn't) - clone git clone ssh://<yourid>@gerrit.instructure.com:29418/mathman and follow the instructions for building. - checkout https://gerrit.instructure.com/c/mathman/+/277389 - build it (once built, you don't have to run in in docker) - in a canvas rails console: Setting.set( 'equation_image_url, 'http://localhost:8000/svg?tex=' ) http://localhost:8000 is where mathman is via `node app.js` it's at http://mathman.docker if in docker (at least that's what the README says, I don't really know) - test mathman by requesting `http://<mathman-url>/svg?tex=17` and expect an image of "17". now try with `request /svg?tex=17&scale=2` and your "17" shoul be twice as large. - restart your canvas server test plan: Updated typesetting: - have a question_bank quetsion with math and answers with math - include the question in a quiz > verify that the question looks the same in the question bank as it does when previewing/taking the quiz - if your math includes a "g", it should look the same - the size of the equation should be pretty close Sizing to match: - turn on scale_math_equations site admin feature - put an equation w/in a paragraph with a large font, or add an equation to the rce, select it, and change the font size - click on the equation, edit equation, click insert equation w/o changing anything > expect the equation to match the larger font. - extra credit: DO THIS WITH AND WITHOUT MATHMAN PLUGIN ENABLED (yes, there are 2 paths canvas takes to mathman) make sure to update dyanmic-settings.yml's math-man entry math-man: base_url: 'http://localhost:8000' use_for_svg: 'true' use_for_mml: 'false' - at /plugins, enable mathman plugin and ensure use_for_svg istrue Error handling: - change the URL to mathman to a dead end - load a page with math equation images > expect the math to be typeset by mathjax Change-Id: I354e98a0a0256740ce5b4937f5b4e3adc690fe51 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/277245 Reviewed-by: Weston Dransfield <wdransfield@instructure.com> Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> QA-Review: Weston Dransfield <wdransfield@instructure.com> Product-Review: David Lyons <lyons@instructure.com>
2021-11-02 20:52:12 +08:00
if (!processedBodyMath) return
New approach to MathJax-ifying equations closes LS-1601 flag=new_math_equation_handling The previous approach was to replace the equation image with the equation's LaTeX in canvas' backend, but not all user content sent to the browser passes through UserContent.escape. Discussions and legacy quiz questions included. The backend approach also suffered from the an ugly visual where the LaTeX is displayed onscreen until MathJax typesets it. In a previous commit, I caught Discussion replies in apiUserContent where the screenreader assistive mathml is injected into the DOM adjacent to the image. That worked but we now had 2 places where the replacement was taking place, and quiz questions are still being missed. A better approach is to handle it all in a central location, which is with the code that detects math is on the page. The new approach is to inject the LaTeX into the DOM adjacent to the image just before MathJax does its processing, then removes the image when it finished. This way the equation image is displayed to the user while MathJaX does its work, and since we look for new math in a MutationObserver watching the whole document, we never miss any equation images on the page. Because we are looking for mutations anywhere on the page, there may be nodes we want to ignore (e.g. the quiz timer). This is handled by adding to the ignore_list css selector in main.js test plan: - with the "Updated math equation handling" flag on (and optionally 'Support LaTex math equations almost everywhere") - double check that equations created with the rce equation editor are processed with mathjax all over canvas > expect equation images to be visible until replaced by MathJax typeset versions - Discussions: - reply to a discussion with an equation (inline and equation editor) > expect them to be typeset by mathjax - edit a reply and save > expect the the reply to have it's math processed by mathjax - Legacy Quizzes - create a quiz, set it so 1 question per page - add a couple questions with equations - preview the quiz, moving forward and back thru the questions > expect the questions go have their equations typeset by mathjax Change-Id: I9e2ec4fd53de06748156bbd4adadac7e2b1e205f Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/252222 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Jackson Howe <jackson.howe@instructure.com> QA-Review: Robin Kuss <rkuss@instructure.com> Product-Review: Peyton Craighill <pcraighill@instructure.com>
2020-11-07 22:41:14 +08:00
for (let m = 0; m < mutationList.length; ++m) {
Load mathjax if we find any inline LaTex If the LaTex the user enters in the equation editor has errors, MathJax will typeset it, with the bad parts in red. Unfortunately the services canvas uses to generate the equation image simply fails. The equation editor now verifies the image can be created and if not will insert the raw LaTex into the RCE delimited by \(...\). Once the content is saved MathJax will typeset it (includeing the red, but hey, that's better than what used to happen) now also looks for $$ or \( starting delimiters mathjax uses to identify equations and looks for math on wiki pages, which was missing before (that is not behind the flag) had to skip some screenreader_gradebook specs that started failing with this change. The gradebook team is as baffled as I am. Will create a ticket for them to investigate. if MathJax finds LaTex errors (which you'll see as red in the preview area), the service that generates the equation image fails. This detects that and puts the raw LaTex back into the RCE's content. On saving, MathJax can process it, though it will still show the red. This is better than losing the equation because the image was missing. closes LS-1488 flag=inline_math_everywhere test plan - turn on SiteAdmin feature "Updated math equation handling" (flag=new_math_equation_handling) and the RootAccount feature "Support LaTex math equations almost everywhere" (flag=inline_math_everywhere) - in the RCE, enter \(your equation here\) - enter $$your equation here$$ - save > expect the first equation to be typeset and inline > expect the second equation to be typeset and a block - the equations can span over multiple lines too - edit an eq with the eq editor > expect it to be typeset too - in the RCE, click on the equation toolbar button - in the advanced pane of the equation editor, enter \var = 27 > expect the \var part to be red in the preview area (because it's undefined) - click Insert Equation > expect the raw LaTex to be in the RCE, surrounded by \(...\) - save > expect the equation to get typeset (and \var will still be red) - have an assignment with a student submission - grade the submission and include an equation in the comments for example: \(y = x^2\) - view the assignment as the student > expect the equation to be renered in the comment - put some math in an assignment's title > expect to see it in the assignments page - create a page with inline math in it > expect the math to be typeset - create a discussion with math - reply to the discussion with inline math in it - edit the inline math in the reply > expect the math to be typeset each time - have a student submit an assignemnt - as the teacher go to speedgrader > expect typeset math everywhere - add a comment with math > expect it to get typeset - goto /assignments/:id/submissions/:user_id > expect comments with math to be typeset - add a comment with math > epxect it go get typeset - old quizzes mostly work. While editing a question, inline math is not typeset, but will be when previewed or being taken - new module items can have math in their title, but if you edit the title, it's not typeset (this has baffled me, but it's got to be an extremely rare case) - load the calendar and flipping between Week, Month, Agenda views > expect entries with inline math in their title to be typeset - loading the calendar in different initial Views > expect events with math to be typeset - create a new event with math (e.g. "\(x^2\)"in the title > expect it to be typeset when saved - open an event in the calendar that has math in its body > expect it to be typeset Change-Id: Id5e1e822fad29a52bf21573e62976a4482afcf43 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/248246 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Charley Kline <ckline@instructure.com> QA-Review: Robin Kuss <rkuss@instructure.com> Product-Review: Peyton Craighill <pcraighill@instructure.com>
2020-09-23 06:13:35 +08:00
if (mutationList[m]?.addedNodes?.length) {
New approach to MathJax-ifying equations closes LS-1601 flag=new_math_equation_handling The previous approach was to replace the equation image with the equation's LaTeX in canvas' backend, but not all user content sent to the browser passes through UserContent.escape. Discussions and legacy quiz questions included. The backend approach also suffered from the an ugly visual where the LaTeX is displayed onscreen until MathJax typesets it. In a previous commit, I caught Discussion replies in apiUserContent where the screenreader assistive mathml is injected into the DOM adjacent to the image. That worked but we now had 2 places where the replacement was taking place, and quiz questions are still being missed. A better approach is to handle it all in a central location, which is with the code that detects math is on the page. The new approach is to inject the LaTeX into the DOM adjacent to the image just before MathJax does its processing, then removes the image when it finished. This way the equation image is displayed to the user while MathJaX does its work, and since we look for new math in a MutationObserver watching the whole document, we never miss any equation images on the page. Because we are looking for mutations anywhere on the page, there may be nodes we want to ignore (e.g. the quiz timer). This is handled by adding to the ignore_list css selector in main.js test plan: - with the "Updated math equation handling" flag on (and optionally 'Support LaTex math equations almost everywhere") - double check that equations created with the rce equation editor are processed with mathjax all over canvas > expect equation images to be visible until replaced by MathJax typeset versions - Discussions: - reply to a discussion with an equation (inline and equation editor) > expect them to be typeset by mathjax - edit a reply and save > expect the the reply to have it's math processed by mathjax - Legacy Quizzes - create a quiz, set it so 1 question per page - add a couple questions with equations - preview the quiz, moving forward and back thru the questions > expect the questions go have their equations typeset by mathjax Change-Id: I9e2ec4fd53de06748156bbd4adadac7e2b1e205f Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/252222 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Jackson Howe <jackson.howe@instructure.com> QA-Review: Robin Kuss <rkuss@instructure.com> Product-Review: Peyton Craighill <pcraighill@instructure.com>
2020-11-07 22:41:14 +08:00
const addedNodes = mutationList[m].addedNodes
for (let n = 0; n < addedNodes.length; ++n) {
const node = addedNodes[n]
if (node.nodeType !== Node.ELEMENT_NODE) continue
const processNewMathEvent = new CustomEvent(mathml.processNewMathEventName, {
detail: {target: node}
})
window.dispatchEvent(processNewMathEvent)
New approach to MathJax-ifying equations closes LS-1601 flag=new_math_equation_handling The previous approach was to replace the equation image with the equation's LaTeX in canvas' backend, but not all user content sent to the browser passes through UserContent.escape. Discussions and legacy quiz questions included. The backend approach also suffered from the an ugly visual where the LaTeX is displayed onscreen until MathJax typesets it. In a previous commit, I caught Discussion replies in apiUserContent where the screenreader assistive mathml is injected into the DOM adjacent to the image. That worked but we now had 2 places where the replacement was taking place, and quiz questions are still being missed. A better approach is to handle it all in a central location, which is with the code that detects math is on the page. The new approach is to inject the LaTeX into the DOM adjacent to the image just before MathJax does its processing, then removes the image when it finished. This way the equation image is displayed to the user while MathJaX does its work, and since we look for new math in a MutationObserver watching the whole document, we never miss any equation images on the page. Because we are looking for mutations anywhere on the page, there may be nodes we want to ignore (e.g. the quiz timer). This is handled by adding to the ignore_list css selector in main.js test plan: - with the "Updated math equation handling" flag on (and optionally 'Support LaTex math equations almost everywhere") - double check that equations created with the rce equation editor are processed with mathjax all over canvas > expect equation images to be visible until replaced by MathJax typeset versions - Discussions: - reply to a discussion with an equation (inline and equation editor) > expect them to be typeset by mathjax - edit a reply and save > expect the the reply to have it's math processed by mathjax - Legacy Quizzes - create a quiz, set it so 1 question per page - add a couple questions with equations - preview the quiz, moving forward and back thru the questions > expect the questions go have their equations typeset by mathjax Change-Id: I9e2ec4fd53de06748156bbd4adadac7e2b1e205f Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/252222 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Jackson Howe <jackson.howe@instructure.com> QA-Review: Robin Kuss <rkuss@instructure.com> Product-Review: Peyton Craighill <pcraighill@instructure.com>
2020-11-07 22:41:14 +08:00
}
Load mathjax if we find any inline LaTex If the LaTex the user enters in the equation editor has errors, MathJax will typeset it, with the bad parts in red. Unfortunately the services canvas uses to generate the equation image simply fails. The equation editor now verifies the image can be created and if not will insert the raw LaTex into the RCE delimited by \(...\). Once the content is saved MathJax will typeset it (includeing the red, but hey, that's better than what used to happen) now also looks for $$ or \( starting delimiters mathjax uses to identify equations and looks for math on wiki pages, which was missing before (that is not behind the flag) had to skip some screenreader_gradebook specs that started failing with this change. The gradebook team is as baffled as I am. Will create a ticket for them to investigate. if MathJax finds LaTex errors (which you'll see as red in the preview area), the service that generates the equation image fails. This detects that and puts the raw LaTex back into the RCE's content. On saving, MathJax can process it, though it will still show the red. This is better than losing the equation because the image was missing. closes LS-1488 flag=inline_math_everywhere test plan - turn on SiteAdmin feature "Updated math equation handling" (flag=new_math_equation_handling) and the RootAccount feature "Support LaTex math equations almost everywhere" (flag=inline_math_everywhere) - in the RCE, enter \(your equation here\) - enter $$your equation here$$ - save > expect the first equation to be typeset and inline > expect the second equation to be typeset and a block - the equations can span over multiple lines too - edit an eq with the eq editor > expect it to be typeset too - in the RCE, click on the equation toolbar button - in the advanced pane of the equation editor, enter \var = 27 > expect the \var part to be red in the preview area (because it's undefined) - click Insert Equation > expect the raw LaTex to be in the RCE, surrounded by \(...\) - save > expect the equation to get typeset (and \var will still be red) - have an assignment with a student submission - grade the submission and include an equation in the comments for example: \(y = x^2\) - view the assignment as the student > expect the equation to be renered in the comment - put some math in an assignment's title > expect to see it in the assignments page - create a page with inline math in it > expect the math to be typeset - create a discussion with math - reply to the discussion with inline math in it - edit the inline math in the reply > expect the math to be typeset each time - have a student submit an assignemnt - as the teacher go to speedgrader > expect typeset math everywhere - add a comment with math > expect it to get typeset - goto /assignments/:id/submissions/:user_id > expect comments with math to be typeset - add a comment with math > epxect it go get typeset - old quizzes mostly work. While editing a question, inline math is not typeset, but will be when previewed or being taken - new module items can have math in their title, but if you edit the title, it's not typeset (this has baffled me, but it's got to be an extremely rare case) - load the calendar and flipping between Week, Month, Agenda views > expect entries with inline math in their title to be typeset - loading the calendar in different initial Views > expect events with math to be typeset - create a new event with math (e.g. "\(x^2\)"in the title > expect it to be typeset when saved - open an event in the calendar that has math in its body > expect it to be typeset Change-Id: Id5e1e822fad29a52bf21573e62976a4482afcf43 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/248246 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Charley Kline <ckline@instructure.com> QA-Review: Robin Kuss <rkuss@instructure.com> Product-Review: Peyton Craighill <pcraighill@instructure.com>
2020-09-23 06:13:35 +08:00
}
}
})
observer.observe(document.body, {
childList: true,
subtree: true
})
Redo the locale polyfiller using new features from @formatjs Fixes FOO-2330 flag=none Canvas supports locales that not all browsers support, so we have to check for those cases and pull in a polyfilled version of the Intl functions that we use (DateTimeFormat, NumberFormat, and RelativeTimeFormat) when a locale is called for that the browser does not support. The first time the locale polyfiller was implemented, a lot of tests had to be done to see if there was an available polyfill for the given locale; this somehow broke Chrome after Version 92 so it was disabled for Chrome. However, latest versions of the @formatjs polyfillers are much smarter and can perform those checks and fallbacks themselves, which makes the Canvas polyfiller code way simpler and more stable. An additional issue was uncovered: when the locale is being polyfilled, NONE of the native locales can be accessed any more, so code relying on being able to get at, say, 'en-US' to do date arithmetic was failing. So when a polyfill loads, we save the browser's version as Native* (so Intl.DateTimeFormat --> Intl.NativeDateTimeFormat) so it can be accessed if needed (shouldn't be anywhere except in the ui/shared datetime support code). Another issue uncovered is that when a polyfill is necessary, it seems to take a long time... it can be SECONDS before it is fully loaded and its Promises resolve, at least in dev. Unfortunately a lot of front-end code can start up and begin to use Intl functions during that time, possibly with unpredictable results. The only real answer is to make the execution of immediate bundles, and the call to ready() to finish front-end initialization, wait pending the resolution of the Promise indicating that the locales have loaded. This is a bit unfortunate as it delays the execution of front-end code, but will only be noticeable in locales that need polyfilling because if a native locale is detected, the bundle loading and call to ready() will happen immediately as before. This commit does the following: - changes the Rails js_env to include LOCALES instead of LOCALE. LOCALES is a full list of locale strings in fallback order, so that if `sv-SE-x-k12` isn't found, it will try `sv-SE` and `sv-x-k12` and `sv` before finally falling back to `en`. The front-end startup code backfills ENV.LOCALE to ENV.LOCALES[0] for backward compatibility. - up-revs @formatjs to a more recent version that implements the check if a polyfill is available and leverages the LOCALES list to find an available polyfill. - Rewrites intl-polyfills to be smarter about detecting when a polyfill is necessary and whether it is possible. - Makes it easier to add new Intl subsystems to the polyfill code should they start getting used in the Canvas code somewhere. - Fixes up the helpers that relied upon the 'en-US' locale specifically. They now specifically check for the Native version of an Intl subsystem first. - Fixes up the changeTimezone helpers in ui/shared/datetime because they relied on the `en-US` locale always being available, which is not true when the locale has been polyfilled. That was kind of sketchy anyway because it relied on new Date() parsing a fairly free-form English date and time string; it now constructs an ISO8601 string which is much more supported as an argument to new Date(). Test plan: * Try some different locale scenarios and observe the behavior of Canvas in that language in general, and also specifically how it formats dates and times (this may be faster to do in console). * Pay particular attention to places where datepickers are used, specifically, create a new assignment and fiddle with the due dates down near the bottom. * Locale scenarios to try: a native locale like de or es -should just work a native locale with an extension like sv-x-k12 -should just work a polyfillable locale like cy or nn -should work with a console message saying it is polyfilled the one non-polyfillable locale: Kreyòl Ayisyen -should work via a fallback all the way to 'en' on console Change-Id: I93a1f2c3f0b3002747f564aba24c93d77244383e Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/284509 Reviewed-by: Ahmad Amireh <ahmad@instructure.com> QA-Review: Charley Kline <ckline@instructure.com> Product-Review: Charley Kline <ckline@instructure.com> Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
2022-02-05 08:03:25 +08:00
}
// This is because most pages use this and by having it all in it's own chunk it makes webpack
// split out a ton of stuff (like @instructure/ui-view) into multiple chunks because its chunking
// algorithm decides that because that chunk would either be too small or it would cause more than
// our maxAsyncRequests it should concat it into mutlple parents.
require.include('./features/navigation_header')
if (!window.bundles) window.bundles = []
// If you add to this be sure there is support for it in the intl-polyfills package!
const intlSubsystemsInUse = ['DateTimeFormat', 'RelativeTimeFormat', 'NumberFormat']
// Do we have native support in the given Intl subsystem for one of the current
// locale fallbacks?
function noNativeSupport(sys) {
const locales = [...ENV.LOCALES]
// 'en' is the final fallback, don't settle for that unless it's the only
// available locale, in which case there is obviously native support.
if (locales.length < 1 || (locales.length === 1 && locales[0] === 'en')) return false
if (locales.slice(-1)[0] === 'en') locales.pop()
for (const locale of locales) {
const native = Intl[sys].supportedLocalesOf([locale])
if (native.length > 0) return false
}
return true
}
async function maybePolyfillLocaleThenGo() {
await import(`../public/javascripts/translations/${ENV.LOCALE}`)
advanceReadiness('localeFiles')
Redo the locale polyfiller using new features from @formatjs Fixes FOO-2330 flag=none Canvas supports locales that not all browsers support, so we have to check for those cases and pull in a polyfilled version of the Intl functions that we use (DateTimeFormat, NumberFormat, and RelativeTimeFormat) when a locale is called for that the browser does not support. The first time the locale polyfiller was implemented, a lot of tests had to be done to see if there was an available polyfill for the given locale; this somehow broke Chrome after Version 92 so it was disabled for Chrome. However, latest versions of the @formatjs polyfillers are much smarter and can perform those checks and fallbacks themselves, which makes the Canvas polyfiller code way simpler and more stable. An additional issue was uncovered: when the locale is being polyfilled, NONE of the native locales can be accessed any more, so code relying on being able to get at, say, 'en-US' to do date arithmetic was failing. So when a polyfill loads, we save the browser's version as Native* (so Intl.DateTimeFormat --> Intl.NativeDateTimeFormat) so it can be accessed if needed (shouldn't be anywhere except in the ui/shared datetime support code). Another issue uncovered is that when a polyfill is necessary, it seems to take a long time... it can be SECONDS before it is fully loaded and its Promises resolve, at least in dev. Unfortunately a lot of front-end code can start up and begin to use Intl functions during that time, possibly with unpredictable results. The only real answer is to make the execution of immediate bundles, and the call to ready() to finish front-end initialization, wait pending the resolution of the Promise indicating that the locales have loaded. This is a bit unfortunate as it delays the execution of front-end code, but will only be noticeable in locales that need polyfilling because if a native locale is detected, the bundle loading and call to ready() will happen immediately as before. This commit does the following: - changes the Rails js_env to include LOCALES instead of LOCALE. LOCALES is a full list of locale strings in fallback order, so that if `sv-SE-x-k12` isn't found, it will try `sv-SE` and `sv-x-k12` and `sv` before finally falling back to `en`. The front-end startup code backfills ENV.LOCALE to ENV.LOCALES[0] for backward compatibility. - up-revs @formatjs to a more recent version that implements the check if a polyfill is available and leverages the LOCALES list to find an available polyfill. - Rewrites intl-polyfills to be smarter about detecting when a polyfill is necessary and whether it is possible. - Makes it easier to add new Intl subsystems to the polyfill code should they start getting used in the Canvas code somewhere. - Fixes up the helpers that relied upon the 'en-US' locale specifically. They now specifically check for the Native version of an Intl subsystem first. - Fixes up the changeTimezone helpers in ui/shared/datetime because they relied on the `en-US` locale always being available, which is not true when the locale has been polyfilled. That was kind of sketchy anyway because it relied on new Date() parsing a fairly free-form English date and time string; it now constructs an ISO8601 string which is much more supported as an argument to new Date(). Test plan: * Try some different locale scenarios and observe the behavior of Canvas in that language in general, and also specifically how it formats dates and times (this may be faster to do in console). * Pay particular attention to places where datepickers are used, specifically, create a new assignment and fiddle with the due dates down near the bottom. * Locale scenarios to try: a native locale like de or es -should just work a native locale with an extension like sv-x-k12 -should just work a polyfillable locale like cy or nn -should work with a console message saying it is polyfilled the one non-polyfillable locale: Kreyòl Ayisyen -should work via a fallback all the way to 'en' on console Change-Id: I93a1f2c3f0b3002747f564aba24c93d77244383e Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/284509 Reviewed-by: Ahmad Amireh <ahmad@instructure.com> QA-Review: Charley Kline <ckline@instructure.com> Product-Review: Charley Kline <ckline@instructure.com> Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
2022-02-05 08:03:25 +08:00
// If any Intl subsystem has no native support for the current locale, start
// trying to polyfill that locale from @formatjs. Note that this (possibly slow)
// process only executes at all if polyfilling was detected to be necessary.
if (intlSubsystemsInUse.some(noNativeSupport)) {
/* eslint-disable no-console */
try {
const im = await import('intl-polyfills')
const result = await im.loadAllLocalePolyfills(ENV.LOCALES, intlSubsystemsInUse)
result.forEach(r => {
if (r.error)
console.error(`${r.subsys} polyfill for locale "${r.locale}" failed: ${r.error}`)
if (r.source === 'polyfill')
console.info(`${r.subsys} polyfilled "${r.loaded}" for locale "${r.locale}"`)
})
} catch (e) {
console.error(`Locale polyfill load failed: ${e.message}`)
}
/* eslint-enable no-console */
}
Redo the locale polyfiller using new features from @formatjs Fixes FOO-2330 flag=none Canvas supports locales that not all browsers support, so we have to check for those cases and pull in a polyfilled version of the Intl functions that we use (DateTimeFormat, NumberFormat, and RelativeTimeFormat) when a locale is called for that the browser does not support. The first time the locale polyfiller was implemented, a lot of tests had to be done to see if there was an available polyfill for the given locale; this somehow broke Chrome after Version 92 so it was disabled for Chrome. However, latest versions of the @formatjs polyfillers are much smarter and can perform those checks and fallbacks themselves, which makes the Canvas polyfiller code way simpler and more stable. An additional issue was uncovered: when the locale is being polyfilled, NONE of the native locales can be accessed any more, so code relying on being able to get at, say, 'en-US' to do date arithmetic was failing. So when a polyfill loads, we save the browser's version as Native* (so Intl.DateTimeFormat --> Intl.NativeDateTimeFormat) so it can be accessed if needed (shouldn't be anywhere except in the ui/shared datetime support code). Another issue uncovered is that when a polyfill is necessary, it seems to take a long time... it can be SECONDS before it is fully loaded and its Promises resolve, at least in dev. Unfortunately a lot of front-end code can start up and begin to use Intl functions during that time, possibly with unpredictable results. The only real answer is to make the execution of immediate bundles, and the call to ready() to finish front-end initialization, wait pending the resolution of the Promise indicating that the locales have loaded. This is a bit unfortunate as it delays the execution of front-end code, but will only be noticeable in locales that need polyfilling because if a native locale is detected, the bundle loading and call to ready() will happen immediately as before. This commit does the following: - changes the Rails js_env to include LOCALES instead of LOCALE. LOCALES is a full list of locale strings in fallback order, so that if `sv-SE-x-k12` isn't found, it will try `sv-SE` and `sv-x-k12` and `sv` before finally falling back to `en`. The front-end startup code backfills ENV.LOCALE to ENV.LOCALES[0] for backward compatibility. - up-revs @formatjs to a more recent version that implements the check if a polyfill is available and leverages the LOCALES list to find an available polyfill. - Rewrites intl-polyfills to be smarter about detecting when a polyfill is necessary and whether it is possible. - Makes it easier to add new Intl subsystems to the polyfill code should they start getting used in the Canvas code somewhere. - Fixes up the helpers that relied upon the 'en-US' locale specifically. They now specifically check for the Native version of an Intl subsystem first. - Fixes up the changeTimezone helpers in ui/shared/datetime because they relied on the `en-US` locale always being available, which is not true when the locale has been polyfilled. That was kind of sketchy anyway because it relied on new Date() parsing a fairly free-form English date and time string; it now constructs an ISO8601 string which is much more supported as an argument to new Date(). Test plan: * Try some different locale scenarios and observe the behavior of Canvas in that language in general, and also specifically how it formats dates and times (this may be faster to do in console). * Pay particular attention to places where datepickers are used, specifically, create a new assignment and fiddle with the due dates down near the bottom. * Locale scenarios to try: a native locale like de or es -should just work a native locale with an extension like sv-x-k12 -should just work a polyfillable locale like cy or nn -should work with a console message saying it is polyfilled the one non-polyfillable locale: Kreyòl Ayisyen -should work via a fallback all the way to 'en' on console Change-Id: I93a1f2c3f0b3002747f564aba24c93d77244383e Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/284509 Reviewed-by: Ahmad Amireh <ahmad@instructure.com> QA-Review: Charley Kline <ckline@instructure.com> Product-Review: Charley Kline <ckline@instructure.com> Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
2022-02-05 08:03:25 +08:00
// After possible polyfilling has completed, now we can start evaluating any
// queueud JS bundles, arrange for tasks to run after the document is fully ready,
// and advance the readiness state.
advanceReadiness('localePolyfills')
window.bundles.push = loadBundle
Redo the locale polyfiller using new features from @formatjs Fixes FOO-2330 flag=none Canvas supports locales that not all browsers support, so we have to check for those cases and pull in a polyfilled version of the Intl functions that we use (DateTimeFormat, NumberFormat, and RelativeTimeFormat) when a locale is called for that the browser does not support. The first time the locale polyfiller was implemented, a lot of tests had to be done to see if there was an available polyfill for the given locale; this somehow broke Chrome after Version 92 so it was disabled for Chrome. However, latest versions of the @formatjs polyfillers are much smarter and can perform those checks and fallbacks themselves, which makes the Canvas polyfiller code way simpler and more stable. An additional issue was uncovered: when the locale is being polyfilled, NONE of the native locales can be accessed any more, so code relying on being able to get at, say, 'en-US' to do date arithmetic was failing. So when a polyfill loads, we save the browser's version as Native* (so Intl.DateTimeFormat --> Intl.NativeDateTimeFormat) so it can be accessed if needed (shouldn't be anywhere except in the ui/shared datetime support code). Another issue uncovered is that when a polyfill is necessary, it seems to take a long time... it can be SECONDS before it is fully loaded and its Promises resolve, at least in dev. Unfortunately a lot of front-end code can start up and begin to use Intl functions during that time, possibly with unpredictable results. The only real answer is to make the execution of immediate bundles, and the call to ready() to finish front-end initialization, wait pending the resolution of the Promise indicating that the locales have loaded. This is a bit unfortunate as it delays the execution of front-end code, but will only be noticeable in locales that need polyfilling because if a native locale is detected, the bundle loading and call to ready() will happen immediately as before. This commit does the following: - changes the Rails js_env to include LOCALES instead of LOCALE. LOCALES is a full list of locale strings in fallback order, so that if `sv-SE-x-k12` isn't found, it will try `sv-SE` and `sv-x-k12` and `sv` before finally falling back to `en`. The front-end startup code backfills ENV.LOCALE to ENV.LOCALES[0] for backward compatibility. - up-revs @formatjs to a more recent version that implements the check if a polyfill is available and leverages the LOCALES list to find an available polyfill. - Rewrites intl-polyfills to be smarter about detecting when a polyfill is necessary and whether it is possible. - Makes it easier to add new Intl subsystems to the polyfill code should they start getting used in the Canvas code somewhere. - Fixes up the helpers that relied upon the 'en-US' locale specifically. They now specifically check for the Native version of an Intl subsystem first. - Fixes up the changeTimezone helpers in ui/shared/datetime because they relied on the `en-US` locale always being available, which is not true when the locale has been polyfilled. That was kind of sketchy anyway because it relied on new Date() parsing a fairly free-form English date and time string; it now constructs an ISO8601 string which is much more supported as an argument to new Date(). Test plan: * Try some different locale scenarios and observe the behavior of Canvas in that language in general, and also specifically how it formats dates and times (this may be faster to do in console). * Pay particular attention to places where datepickers are used, specifically, create a new assignment and fiddle with the due dates down near the bottom. * Locale scenarios to try: a native locale like de or es -should just work a native locale with an extension like sv-x-k12 -should just work a polyfillable locale like cy or nn -should work with a console message saying it is polyfilled the one non-polyfillable locale: Kreyòl Ayisyen -should work via a fallback all the way to 'en' on console Change-Id: I93a1f2c3f0b3002747f564aba24c93d77244383e Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/284509 Reviewed-by: Ahmad Amireh <ahmad@instructure.com> QA-Review: Charley Kline <ckline@instructure.com> Product-Review: Charley Kline <ckline@instructure.com> Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
2022-02-05 08:03:25 +08:00
window.bundles.forEach(loadBundle)
ready(afterDocumentReady)
}
maybePolyfillLocaleThenGo().catch(e =>
// eslint-disable-next-line no-console
console.error(`Front-end bundles did not successfully start! (${e.message})`)
)
if (ENV.csp)
// eslint-disable-next-line promise/catch-or-return
import('./boot/initializers/setupCSP').then(({default: setupCSP}) => setupCSP(window.document))
if (ENV.INCOMPLETE_REGISTRATION) import('./boot/initializers/warnOnIncompleteRegistration')
if (ENV.badge_counts) import('./boot/initializers/showBadgeCounts')
$('html').removeClass('scripts-not-loaded')
$('.help_dialog_trigger').click(event => {
event.preventDefault()
// eslint-disable-next-line promise/catch-or-return
import('./boot/initializers/enableHelpDialog').then(({default: helpDialog}) => helpDialog.open())
})
// Backbone routes
$('body').on(
'click',
'[data-pushstate]',
preventDefault(function () {
Backbone.history.navigate($(this).attr('href'), true)
})
)
if (
window.ENV.NEW_USER_TUTORIALS &&
window.ENV.NEW_USER_TUTORIALS.is_enabled &&
window.ENV.context_asset_string &&
splitAssetString(window.ENV.context_asset_string)[0] === 'courses'
) {
// eslint-disable-next-line promise/catch-or-return
import('./features/new_user_tutorial/index').then(({default: initializeNewUserTutorials}) => {
initializeNewUserTutorials()
})
}
;(window.requestIdleCallback || window.setTimeout)(() => {
// eslint-disable-next-line promise/catch-or-return
import('./boot/initializers/runOnEveryPageButDontBlockAnythingElse').then(() =>
advanceReadiness('asyncInitializers')
)
})