Remove rce_pretty_html_editor feature flag

fixes MAT-133

flag=none

test plan:
- Verify that there is no rce_pretty_html_editor
feature flag (site admin).
- Navigate to an RCE instance.
- Verify that pretty html editor is enabled by default.

Change-Id: Ibe76738577d0716e30f06815c9a072f41ca48103
Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/275197
Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
Reviewed-by: Weston Dransfield <wdransfield@instructure.com>
QA-Review: Weston Dransfield <wdransfield@instructure.com>
Product-Review: Juan Chavez <juan.chavez@instructure.com>
This commit is contained in:
Juan Chavez 2021-10-01 00:09:04 -04:00
parent 00d660ede5
commit b55dad68da
18 changed files with 115 additions and 143 deletions

View File

@ -8,7 +8,6 @@ import '@instructure/canvas-theme'
window.ENV = window.ENV || {
FEATURES: {
rce_pretty_html_editor: true,
rce_auto_save: true
},
// the RCE won't load w/o these yet

View File

@ -234,7 +234,7 @@ class ApplicationController < ActionController::Base
# put feature checks on Account.site_admin and @domain_root_account that we're loading for every page in here
# so altogether we can get them faster the vast majority of the time
JS_ENV_SITE_ADMIN_FEATURES = [
:cc_in_rce_video_tray, :featured_help_links, :rce_pretty_html_editor,
:cc_in_rce_video_tray, :featured_help_links,
:strip_origin_from_quiz_answer_file_references, :rce_buttons_and_icons, :important_dates, :feature_flag_filters, :k5_parent_support,
:conferencing_in_planner, :remember_settings_tab, :word_count_in_speed_grader, :observer_picker
].freeze

View File

@ -11,8 +11,3 @@ cc_in_rce_video_tray:
display_name: RCE Edit Closed Captions
description: Edit closed captions/subtitles to videos from the video options tray in the RCE
applies_to: SiteAdmin
rce_pretty_html_editor:
state: hidden
display_name: RCE Pretty HTML Editor
description: A much better HTML code editor for the RCE, though it suffers from being inaccessible to screenreader users.
applies_to: SiteAdmin

View File

@ -55,7 +55,6 @@ const RCE = forwardRef(function RCE(props, rceRef) {
textareaId,
textareaClassName,
rcsProps,
use_rce_pretty_html_editor,
use_rce_buttons_and_icons,
use_rce_a11y_checker_notifications,
onFocus,
@ -97,7 +96,6 @@ const RCE = forwardRef(function RCE(props, rceRef) {
textareaId,
textareaClassName,
trayProps: rcsProps,
use_rce_pretty_html_editor,
use_rce_buttons_and_icons,
use_rce_a11y_checker_notifications,
editorOptions: Object.assign(editorOptions, editorOptions, {
@ -192,8 +190,6 @@ RCE.propTypes = {
// properties necessary for the RCE to us the RCS
// if missing, RCE features that require the RCS are omitted
rcsProps: trayPropTypes,
// enable the pretty html editor (temporary until the feature is forced on)
use_rce_pretty_html_editor: bool,
// enable the custom buttons feature (temporary until the feature is forced on)
use_rce_buttons_and_icons: bool,
// enable the a11y checker notifications (temporary until the feature is forced on)
@ -217,7 +213,6 @@ RCE.defaultProps = {
maxInitRenderedRCEs: -1,
mirroredAttrs: {},
readOnly: false,
use_rce_pretty_html_editor: true,
use_rce_buttons_and_icons: true,
use_rce_a11y_checker_notifications: true,
onFocus: () => {},

View File

@ -273,8 +273,6 @@ class RCEWrapper extends React.Component {
instRecordDisabled: PropTypes.bool,
highContrastCSS: PropTypes.arrayOf(PropTypes.string),
maxInitRenderedRCEs: PropTypes.number,
// feature flag related props
use_rce_pretty_html_editor: PropTypes.bool,
use_rce_buttons_and_icons: PropTypes.bool,
use_rce_a11y_checker_notifications: PropTypes.bool
}
@ -681,11 +679,7 @@ class RCEWrapper extends React.Component {
let newState
switch (this.state.editorView) {
case WYSIWYG_VIEW:
if (this.props.use_rce_pretty_html_editor) {
newState = {editorView: newView || PRETTY_HTML_EDITOR_VIEW}
} else {
newState = {editorView: RAW_HTML_EDITOR_VIEW}
}
newState = {editorView: newView || PRETTY_HTML_EDITOR_VIEW}
break
case PRETTY_HTML_EDITOR_VIEW:
newState = {editorView: newView || WYSIWYG_VIEW}
@ -1708,8 +1702,6 @@ class RCEWrapper extends React.Component {
}
renderHtmlEditor() {
if (!this.props.use_rce_pretty_html_editor) return null
// the div keeps the editor from collapsing while the code editor is downloaded
return (
<Suspense
@ -1811,7 +1803,6 @@ class RCEWrapper extends React.Component {
onKBShortcutModalOpen={this.openKBShortcutModal}
onA11yChecker={this.onA11yChecker}
onFullscreen={this.handleClickFullscreen}
use_rce_pretty_html_editor={this.props.use_rce_pretty_html_editor}
use_rce_a11y_checker_notifications={this.props.use_rce_a11y_checker_notifications}
a11yBadgeColor={this.theme.canvasBadgeBackgroundColor}
a11yErrorsCount={this.state.a11yErrorsCount}

View File

@ -53,7 +53,6 @@ StatusBar.propTypes = {
onKBShortcutModalOpen: func.isRequired,
onA11yChecker: func.isRequired,
onFullscreen: func.isRequired,
use_rce_pretty_html_editor: bool,
use_rce_a11y_checker_notifications: bool,
preferredHtmlEditor: oneOf([PRETTY_HTML_EDITOR_VIEW, RAW_HTML_EDITOR_VIEW]),
readOnly: bool,
@ -122,7 +121,7 @@ export default function StatusBar(props) {
// adding a delay before including the HTML Editor description to wait the focus moves to the RCE
// and prevent JAWS from reading the aria-describedby element when switching back to RCE view
const timerid = setTimeout(() => {
setIncludeEdtrDesc(props.use_rce_pretty_html_editor && !isHtmlView())
setIncludeEdtrDesc(!isHtmlView())
}, 100)
return () => clearTimeout(timerid)
@ -130,11 +129,10 @@ export default function StatusBar(props) {
function preferredHtmlEditor() {
if (props.preferredHtmlEditor) return props.preferredHtmlEditor
return props.use_rce_pretty_html_editor ? PRETTY_HTML_EDITOR_VIEW : RAW_HTML_EDITOR_VIEW
return PRETTY_HTML_EDITOR_VIEW
}
function getHtmlEditorView(event) {
if (!props.use_rce_pretty_html_editor) return RAW_HTML_EDITOR_VIEW
if (!event.shiftKey) return preferredHtmlEditor()
return preferredHtmlEditor() === RAW_HTML_EDITOR_VIEW
? PRETTY_HTML_EDITOR_VIEW
@ -207,8 +205,6 @@ export default function StatusBar(props) {
}
function renderHtmlEditorMessage() {
if (!props.use_rce_pretty_html_editor) return null
const message =
props.editorView === PRETTY_HTML_EDITOR_VIEW
? formatMessage(
@ -297,9 +293,7 @@ export default function StatusBar(props) {
function renderToggleHtml() {
const toggleToHtml = formatMessage('Switch to the html editor')
const toggleToRich = formatMessage('Switch to the rich text editor')
const toggleToHtmlTip = props.use_rce_pretty_html_editor
? formatMessage('Click or shift-click for the html editor.')
: toggleToHtml
const toggleToHtmlTip = formatMessage('Click or shift-click for the html editor.')
const descText = isHtmlView() ? toggleToRich : toggleToHtml
const titleText = isHtmlView() ? toggleToRich : toggleToHtmlTip
@ -314,7 +308,6 @@ export default function StatusBar(props) {
}}
onKeyUp={event => {
if (
props.use_rce_pretty_html_editor &&
props.editorView === WYSIWYG_VIEW &&
event.shiftKey &&
event.keyCode === 79

View File

@ -95,7 +95,6 @@ describe('RCE StatusBar', () => {
it('defaults to pretty html editor', async () => {
const onChangeView = jest.fn()
const {container, getByText} = renderStatusBar({
use_rce_pretty_html_editor: true,
onChangeView
})
@ -112,7 +111,6 @@ describe('RCE StatusBar', () => {
it('prefers raw html editor if specified', async () => {
const onChangeView = jest.fn()
const {container, getByText} = renderStatusBar({
use_rce_pretty_html_editor: true,
preferredHtmlEditor: RAW_HTML_EDITOR_VIEW,
onChangeView
})
@ -179,7 +177,7 @@ describe('RCE StatusBar', () => {
const {container, getByTestId} = renderStatusBar({editorView: RAW_HTML_EDITOR_VIEW})
const statusbar = getByTestId('RCEStatusBar')
const buttons = container.querySelectorAll('[tabindex]')
expect(buttons.length).toEqual(2)
expect(buttons.length).toEqual(3)
buttons[0].focus()
expect(document.activeElement).toBe(buttons[0])
@ -195,7 +193,7 @@ describe('RCE StatusBar', () => {
const {container, getByTestId} = renderStatusBar({editorView: RAW_HTML_EDITOR_VIEW})
const statusbar = getByTestId('RCEStatusBar')
const buttons = container.querySelectorAll('[tabindex]')
expect(buttons.length).toEqual(2)
expect(buttons.length).toEqual(3)
buttons[buttons.length - 1].focus()
expect(document.activeElement).toBe(buttons[buttons.length - 1])
@ -213,8 +211,7 @@ describe('RCE StatusBar', () => {
describe('in pretty HTML mode', () => {
it('cycles focus with right arrow keys', () => {
const {container, getByTestId} = renderStatusBar({
editorView: PRETTY_HTML_EDITOR_VIEW,
use_rce_pretty_html_editor: true
editorView: PRETTY_HTML_EDITOR_VIEW
})
const statusbar = getByTestId('RCEStatusBar')
const buttons = container.querySelectorAll('[tabindex]')
@ -232,8 +229,7 @@ describe('RCE StatusBar', () => {
it('cycles focus with left arrow keys', async () => {
const {container, getByTestId} = renderStatusBar({
editorView: PRETTY_HTML_EDITOR_VIEW,
use_rce_pretty_html_editor: true
editorView: PRETTY_HTML_EDITOR_VIEW
})
const statusbar = getByTestId('RCEStatusBar')
const buttons = container.querySelectorAll('[tabindex]')

View File

@ -30,12 +30,7 @@ tinymce.create('tinymce.plugins.InstructureHtmlView', {
icon: 'htmlview',
onAction: () => ed.execCommand('instructureHtmlView'),
onSetup(api) {
// safari won't fullscreen the textarea that's the raw html editor
const disable =
!('requestFullscreen' in document.body) &&
!ed.rceWrapper.props.use_rce_pretty_html_editor &&
ed.rceWrapper.state.fullscreenState.isTinyFullscreen
api.setDisabled(disable)
api.setDisabled(false)
}
})
}

View File

@ -286,6 +286,7 @@ describe "submissions" do
f('.submit_assignment_link').click
body_html = '<span style="width: 18rem; height: 1rem; vertical-align: middle;" aria-label="Loading" data-placeholder-for="filename"> </span>'
switch_editor_views # switch to html editor
switch_to_raw_html_editor
tinymce = f("#submission_body")
tinymce.click
tinymce.send_keys(body_html)

View File

@ -47,6 +47,10 @@ describe "threaded discussions" do
f('#discussion_topic').find_element(:css, '.discussion-reply-action').click
wait_for_ajaximations
f('[data-btn-id="rce-edit-btn"]').click
editor_switch_button = f('[data-btn-id="rce-editormessage-btn"]')
if editor_switch_button.text == 'Raw HTML Editor'
editor_switch_button.click
end
wait_for_ajaximations
f("textarea[data-rich_text='true']").send_keys entry_text
fj("button:contains('Post Reply')").click
@ -256,6 +260,10 @@ describe "threaded discussions" do
f("button[data-testid='discussion-topic-reply']").click
wait_for_ajaximations
f('[data-btn-id="rce-edit-btn"]').click
editor_switch_button = f('[data-btn-id="rce-editormessage-btn"]')
if editor_switch_button.text == 'Raw HTML Editor'
editor_switch_button.click
end
wait_for_ajaximations
f("textarea[data-rich_text='true']").send_keys entry_text
fj("button:contains('Reply')").click

View File

@ -335,6 +335,10 @@ module WikiAndTinyCommon
if html
# Switch to HTML
f("button[data-btn-id='rce-edit-btn']").click
button = f('button[data-btn-id="rce-editormessage-btn"]')
if button.text == 'Raw HTML Editor'
button.click
end
in_frame tiny_rce_ifr_id do
tinyrce_element = f('body')
tinyrce_element.send_keys(text)

View File

@ -972,6 +972,13 @@ module RCENextPage
click_editor_view_button
end
def switch_to_raw_html_editor
button = f('button[data-btn-id="rce-editormessage-btn"]')
if button.text == 'Raw HTML Editor'
button.click
end
end
def switch_to_editor_view
click_editor_view_button
end

View File

@ -71,6 +71,7 @@ describe 'RCE Next autosave feature', ignore_js_errors: true do
it 'autosaves htmlview entered content' do
create_and_edit_announcement
switch_to_html_view
switch_to_raw_html_editor
f('textarea#discussion-topic-message10').send_keys('html text')
f("#discussion-title").send_keys("New Discussion Title")
driver.navigate.refresh
@ -192,6 +193,7 @@ describe 'RCE Next autosave feature', ignore_js_errors: true do
# simulate a placeholder image
switch_to_html_view
switch_to_raw_html_editor
f('textarea#discussion-topic-message10').send_keys(
"<div data-placeholder-for='someimage.jpg' style='width: 200px; height: 50px;'>svg spinner here</div>"
)

View File

@ -190,6 +190,7 @@ describe 'RCE next tests', ignore_js_errors: true do
visit_front_page_edit(@course)
switch_to_html_view
switch_to_raw_html_editor
html_view = f('textarea#wiki_page_body')
html_view.send_keys('<a href="http://example.com">edit me</a>')
switch_to_editor_view
@ -198,6 +199,7 @@ describe 'RCE next tests', ignore_js_errors: true do
click_link_for_options
click_link_options_button
wait_for_ajaximations
expect(link_options_tray).to be_displayed
link_text_textbox = f('input[type="text"][value="edit me"]')
@ -946,6 +948,7 @@ describe 'RCE next tests', ignore_js_errors: true do
visit_front_page_edit(@course)
switch_to_html_view
switch_to_raw_html_editor
html_view = f('textarea#wiki_page_body')
html_view.send_keys('<img src="image.jpg" alt="image.jpg" />')
switch_to_editor_view
@ -973,6 +976,7 @@ describe 'RCE next tests', ignore_js_errors: true do
visit_front_page_edit(@course)
switch_to_html_view
switch_to_raw_html_editor
html_view = f('textarea#wiki_page_body')
html_view.send_keys('<img src="image.jpg" alt="image.jpg" />')
switch_to_editor_view
@ -1463,117 +1467,93 @@ describe 'RCE next tests', ignore_js_errors: true do
driver.execute_script('if (document.fullscreenElement) document.exitFullscreen()')
end
describe 'with the use_rce_pretty_html_editor flag off' do
before(:each) { Account.site_admin.disable_feature! :rce_pretty_html_editor }
it 'switches between wysiwyg and pretty html view' do
skip('Cannot get this to pass flakey spec catcher in jenkins, though is fine locally MAT-29')
rce_wysiwyg_state_setup(@course)
expect(f('[aria-label="Rich Content Editor"]')).to be_displayed
it 'switches between wysiwyg and raw html view' do
rce_wysiwyg_state_setup(@course)
expect(f('[aria-label="Rich Content Editor"]')).to be_displayed
# click edit button -> fancy editor
click_editor_view_button
click_editor_view_button
expect(f('textarea#wiki_page_body')).to be_displayed
# it's lazy loaded
expect(f('.RceHtmlEditor')).to be_displayed
click_editor_view_button
expect(f('[aria-label="Rich Content Editor"]')).to be_displayed
end
# click edit button -> back to the rce
click_editor_view_button
expect(f('[aria-label="Rich Content Editor"]')).to be_displayed
it 'displays the editor in fullscreen' do
rce_wysiwyg_state_setup(@course)
# shift-o edit button -> raw editor
shift_O_combination('[data-btn-id="rce-edit-btn"]')
expect(f('textarea#wiki_page_body')).to be_displayed
click_editor_view_button
expect(f('textarea#wiki_page_body')).to be_displayed
click_full_screen_button
expect(fullscreen_element).to eq(f('textarea#wiki_page_body'))
end
# click "Pretty HTML Editor" status bar button -> fancy editor
fj('button:contains("Pretty HTML Editor")').click
expect(f('.RceHtmlEditor')).to be_displayed
end
describe 'with the use_rce_pretty_html_editor flag on' do
before(:each) { Account.site_admin.enable_feature! :rce_pretty_html_editor }
it 'displays the editor in fullscreen' do
skip('Cannot get this to pass flakey spec catcher in jenkins, though is fine locally MAT-29')
rce_wysiwyg_state_setup(@course)
it 'switches between wysiwyg and pretty html view' do
skip('Cannot get this to pass flakey spec catcher in jenkins, though is fine locally')
rce_wysiwyg_state_setup(@course)
expect(f('[aria-label="Rich Content Editor"]')).to be_displayed
click_editor_view_button
expect(f('.RceHtmlEditor')).to be_displayed
# click edit button -> fancy editor
click_editor_view_button
click_full_screen_button
expect(fullscreen_element).to eq(f('.RceHtmlEditor'))
end
# it's lazy loaded
expect(f('.RceHtmlEditor')).to be_displayed
it 'gets default html editor from the rce.htmleditor cookie' do
get '/'
driver.manage.add_cookie(name: 'rce.htmleditor', value: 'RAW', path: '/')
# click edit button -> back to the rce
click_editor_view_button
expect(f('[aria-label="Rich Content Editor"]')).to be_displayed
rce_wysiwyg_state_setup(@course)
# shift-o edit button -> raw editor
shift_O_combination('[data-btn-id="rce-edit-btn"]')
expect(f('textarea#wiki_page_body')).to be_displayed
# clicking opens raw editor
click_editor_view_button
expect(f('textarea#wiki_page_body')).to be_displayed
ensure
driver.manage.delete_cookie('rce.htmleditor')
end
# click "Pretty HTML Editor" status bar button -> fancy editor
fj('button:contains("Pretty HTML Editor")').click
expect(f('.RceHtmlEditor')).to be_displayed
end
it 'saves pretty HTML editor text on submit' do
skip(
'Cannot get this to pass flakey spec catcher in jenkins, though is fine locally MAT-35'
)
quiz_content = '<p>test</p>'
@quiz = @course.quizzes.create!
open_quiz_edit_form
click_questions_tab
click_new_question_button
create_essay_question
expect_new_page_load { f('.save_quiz_button').click }
open_quiz_show_page
expect_new_page_load { f('#preview_quiz_button').click }
switch_to_html_view
expect(f('.RceHtmlEditor')).to be_displayed
f('.RceHtmlEditor .CodeMirror textarea').send_keys(quiz_content)
expect_new_page_load { submit_quiz }
expect(f("#questions .essay_question .quiz_response_text").attribute("innerHTML")).to eq(
quiz_content
)
end
it 'displays the editor in fullscreen' do
skip('Cannot get this to pass flakey spec catcher in jenkins, though is fine locally')
rce_wysiwyg_state_setup(@course)
it 'sanitizes the HTML set in the HTML editor' do
skip 'still flakey. Needs to be addressed in MAT-386'
get '/'
click_editor_view_button
expect(f('.RceHtmlEditor')).to be_displayed
html = <<~HTML
<img src="/" id="test-image" onerror="alert('hello')" />
HTML
click_full_screen_button
expect(fullscreen_element).to eq(f('.RceHtmlEditor'))
end
rce_wysiwyg_state_setup(
@course,
html,
html: true,
new_rce: true
)
it 'gets default html editor from the rce.htmleditor cookie' do
get '/'
driver.manage.add_cookie(name: 'rce.htmleditor', value: 'RAW', path: '/')
rce_wysiwyg_state_setup(@course)
# clicking opens raw editor
click_editor_view_button
expect(f('textarea#wiki_page_body')).to be_displayed
ensure
driver.manage.delete_cookie('rce.htmleditor')
end
it 'saves pretty HTML editor text on submit' do
skip(
'Cannot get this to pass flakey spec catcher in jenkins, though is fine locally MAT-35'
)
quiz_content = '<p>test</p>'
@quiz = @course.quizzes.create!
open_quiz_edit_form
click_questions_tab
click_new_question_button
create_essay_question
expect_new_page_load { f('.save_quiz_button').click }
open_quiz_show_page
expect_new_page_load { f('#preview_quiz_button').click }
switch_to_html_view
expect(f('.RceHtmlEditor')).to be_displayed
f('.RceHtmlEditor .CodeMirror textarea').send_keys(quiz_content)
expect_new_page_load { submit_quiz }
expect(f('#questions .essay_question .quiz_response_text').attribute('innerHTML')).to eq(
quiz_content
)
end
it 'sanitizes the HTML set in the HTML editor' do
skip 'still flakey. Needs to be addressed in MAT-386'
get '/'
html = <<~HTML
<img src="/" id="test-image" onerror="alert('hello')" />
HTML
rce_wysiwyg_state_setup(@course, html, html: true, new_rce: true)
in_frame rce_page_body_ifr_id do
expect(f('#test-image').attribute('onerror')).to be_nil
end
in_frame rce_page_body_ifr_id do
expect(f('#test-image').attribute('onerror')).to be_nil
end
end
end

View File

@ -329,6 +329,13 @@ module CustomSeleniumActions
edit_btn.click
end
def switch_to_raw_html_editor
button = f('button[data-btn-id="rce-editormessage-btn"]')
if button.text == 'Raw HTML Editor'
button.click
end
end
def clear_tiny(tiny_controlling_element, iframe_id = nil)
if iframe_id
in_frame iframe_id do

View File

@ -308,8 +308,8 @@ describe "Wiki Pages" do
it "embeds vimeo video in the page", priority: "1", test_id: 126835 do
get "/courses/#{@course.id}/pages/Page1/edit"
element = f("#wiki_page_body")
switch_editor_views
switch_to_raw_html_editor
html_contents = %q(
<p>
<iframe style="width: 640px; height: 480px;"
@ -323,6 +323,7 @@ describe "Wiki Pages" do
</iframe>
</p>
)
element = f('#wiki_page_body')
element.send_keys(html_contents)
wait_for_new_page_load { f(".btn-primary").click }
expect(f("iframe")).to be_present

View File

@ -130,7 +130,6 @@ const CanvasRce = forwardRef(function CanvasRce(props, rceRef) {
onBlur={onBlur}
onContentChange={onContentChange}
onInit={onInit}
use_rce_pretty_html_editor={!!window.ENV?.FEATURES?.rce_pretty_html_editor}
use_rce_buttons_and_icons={!!window.ENV?.FEATURES?.rce_buttons_and_icons}
use_rce_a11y_checker_notifications={!!window.ENV?.use_rce_a11y_checker_notifications}
{...rest}

View File

@ -191,7 +191,6 @@ const RCELoader = {
instRecordDisabled: ENV.RICH_CONTENT_INST_RECORD_TAB_DISABLED,
maxInitRenderedRCEs: tinyMCEInitOptions.maxInitRenderedRCEs,
highContrastCSS: window.ENV?.url_for_high_contrast_tinymce_editor_css,
use_rce_pretty_html_editor: !!window.ENV?.FEATURES?.rce_pretty_html_editor,
use_rce_buttons_and_icons: !!window.ENV?.FEATURES?.rce_buttons_and_icons,
use_rce_a11y_checker_notifications: !!window.ENV?.use_rce_a11y_checker_notifications
}