-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Upgrade TinyMCE and switch to CodeMirror plugin #2657
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
1c644fc
dda5866
2ae2ec9
0ddc3a6
9bc0638
0d0ace4
1ece49c
a14574e
f6acab9
9ac94fc
9ec3a2d
1e06fd3
f71e333
b1b0d16
7ac1e7b
28dc8e0
f31f936
d73f65c
b1f4d28
cc2fec2
07d54be
09643c8
9797354
6c1d369
ffbba2b
e1908b5
fb6afc7
d623a4e
677f39d
7ce576d
d89ebed
d3828f9
b0c3598
bb0a58a
a6b18de
a9b9184
9054c62
8f6980b
ed51a66
0953583
1cd6e1d
7b24172
c8eaa53
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,6 +22,50 @@ Feature: CMS.HTML Editor | |
|
|
||
| Scenario: TinyMCE image plugin sets urls correctly | ||
| Given I have created a Blank HTML Page | ||
| When I edit the page and select the Visual Editor | ||
| And I add an image with a static link via the Image Plugin Icon | ||
| Then the image static link is rewritten to translate the path | ||
| When I edit the page | ||
| And I add an image with static link "/static/image.jpg" via the Image Plugin Icon | ||
| Then the src link is rewritten to "c4x/MITx/999/asset/image.jpg" | ||
| And the link is shown as "/static/image.jpg" in the Image Plugin | ||
|
|
||
| Scenario: TinyMCE link plugin sets urls correctly | ||
| Given I have created a Blank HTML Page | ||
| When I edit the page | ||
| And I add a link with static link "/static/image.jpg" via the Link Plugin Icon | ||
| Then the href link is rewritten to "c4x/MITx/999/asset/image.jpg" | ||
| And the link is shown as "/static/image.jpg" in the Link Plugin | ||
|
|
||
| Scenario: TinyMCE and CodeMirror preserve style tags | ||
| Given I have created a Blank HTML Page | ||
| When I edit the page | ||
| And type "<p class='title'>pages</p><style><!-- .title { color: red; } --></style>" in the code editor and press OK | ||
| And I save the page | ||
| Then the page text contains: | ||
| """ | ||
| <p class="title">pages</p> | ||
| <style><!-- | ||
| .title { color: red; } | ||
| --></style> | ||
| """ | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. were you planning to change this test to be "Then the page text contains" rather than "Then the page text is"? This would allow you to be more flexible. For example, if we replace the TinyMCE version with another that doesn't put it in the " " or decides to put something else instead.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, I didn't wish to do the "contains" approach. I'd rather check what the text actually is.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I went ahead and changed this to the "contains" approach. |
||
| Scenario: TinyMCE toolbar buttons are as expected | ||
| Given I have created a Blank HTML Page | ||
| When I edit the page | ||
| Then the expected toolbar buttons are displayed | ||
|
|
||
| Scenario: Static links are converted when switching between code editor and WYSIWYG views | ||
| Given I have created a Blank HTML Page | ||
| When I edit the page | ||
| And type "<img src="/static/image.jpg">" in the code editor and press OK | ||
| Then the src link is rewritten to "c4x/MITx/999/asset/image.jpg" | ||
| And the code editor displays "<p><img src="/static/image.jpg" alt="" /></p>" | ||
|
|
||
| Scenario: Code format toolbar button wraps text with code tags | ||
| Given I have created a Blank HTML Page | ||
| When I edit the page | ||
| And I set the text to "display as code" and I select the text | ||
| And I select the code toolbar button | ||
| And I save the page | ||
| Then the page text contains: | ||
| """ | ||
| <p><code>display as code</code></p> | ||
| """ | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,7 +2,10 @@ | |
| # pylint: disable=C0111 | ||
|
|
||
| from lettuce import world, step | ||
| from nose.tools import assert_in # pylint: disable=no-name-in-module | ||
| from nose.tools import assert_in, assert_equal # pylint: disable=no-name-in-module | ||
| from common import type_in_codemirror, get_codemirror_value | ||
|
|
||
| CODEMIRROR_SELECTOR_PREFIX = "$('iframe').contents().find" | ||
|
|
||
|
|
||
| @step('I have created a Blank HTML Page$') | ||
|
|
@@ -31,41 +34,168 @@ def i_created_etext_in_latex(step): | |
| ) | ||
|
|
||
|
|
||
| @step('I edit the page and select the Visual Editor') | ||
| @step('I edit the page$') | ||
| def i_click_on_edit_icon(step): | ||
| world.edit_component() | ||
| world.wait_for(lambda _driver: world.css_visible('a.visual-tab')) | ||
| world.css_click('a.visual-tab') | ||
|
|
||
|
|
||
| @step('I add an image with a static link via the Image Plugin Icon') | ||
| def i_click_on_image_plugin_icon(step): | ||
| # Click on image plugin button | ||
| world.wait_for(lambda _driver: world.css_visible('a.mce_image')) | ||
| world.css_click('a.mce_image') | ||
| @step('I add an image with static link "(.*)" via the Image Plugin Icon$') | ||
| def i_click_on_image_plugin_icon(step, path): | ||
| use_plugin( | ||
| '.mce-i-image', | ||
| lambda: world.css_fill('.mce-textbox', path, 0) | ||
| ) | ||
|
|
||
|
|
||
| @step('the link is shown as "(.*)" in the Image Plugin$') | ||
| def check_link_in_image_plugin(step, path): | ||
| use_plugin( | ||
| '.mce-i-image', | ||
| lambda: assert_equal(path, world.css_find('.mce-textbox')[0].value) | ||
| ) | ||
|
|
||
|
|
||
| @step('I add a link with static link "(.*)" via the Link Plugin Icon$') | ||
| def i_click_on_link_plugin_icon(step, path): | ||
| def fill_in_link_fields(): | ||
| world.css_fill('.mce-textbox', path, 0) | ||
| world.css_fill('.mce-textbox', 'picture', 1) | ||
|
|
||
| use_plugin('.mce-i-link', fill_in_link_fields) | ||
|
|
||
| # Change to the non-modal TinyMCE Image window | ||
| # keeping parent window so we can go back to it. | ||
| parent_window = world.browser.current_window | ||
| for window in world.browser.windows: | ||
|
|
||
| world.browser.switch_to_window(window) # Switch to a different window | ||
| if world.browser.title == 'Insert/Edit Image': | ||
| @step('the link is shown as "(.*)" in the Link Plugin$') | ||
| def check_link_in_link_plugin(step, path): | ||
| # Ensure caret position is within the link just created. | ||
| script = """ | ||
| var editor = tinyMCE.activeEditor; | ||
| editor.selection.select(editor.dom.select('a')[0]);""" | ||
| world.browser.driver.execute_script(script) | ||
| world.wait_for_ajax_complete() | ||
|
|
||
| use_plugin( | ||
| '.mce-i-link', | ||
| lambda: assert_equal(path, world.css_find('.mce-textbox')[0].value) | ||
| ) | ||
|
|
||
|
|
||
| @step('type "(.*)" in the code editor and press OK$') | ||
| def type_in_codemirror_plugin(step, text): | ||
| use_code_editor( | ||
| lambda: type_in_codemirror(0, text, CODEMIRROR_SELECTOR_PREFIX) | ||
| ) | ||
|
|
||
|
|
||
| @step('and the code editor displays "(.*)"$') | ||
| def verify_code_editor_text(step, text): | ||
| use_code_editor( | ||
| lambda: assert_equal(text, get_codemirror_value(0, CODEMIRROR_SELECTOR_PREFIX)) | ||
| ) | ||
|
|
||
| # This is the Image window so find the url text box, | ||
| # enter text in it then hit Insert button. | ||
| url_elem = world.browser.find_by_id("src") | ||
| url_elem.fill('/static/image.jpg') | ||
| world.browser.find_by_id('insert').click() | ||
|
|
||
| world.browser.switch_to_window(parent_window) # Switch back to the main window | ||
| def use_plugin(button_class, action): | ||
| # Click on plugin button | ||
| world.css_click(button_class) | ||
| perform_action_in_plugin(action) | ||
|
|
||
|
|
||
| @step('the image static link is rewritten to translate the path') | ||
| def image_static_link_is_rewritten(step): | ||
| def use_code_editor(action): | ||
| # Click on plugin button | ||
| buttons = world.css_find('div.mce-widget>button') | ||
|
|
||
| code_editor = [button for button in buttons if button.text == 'HTML'] | ||
| assert_equal(1, len(code_editor)) | ||
| code_editor[0].click() | ||
|
|
||
| perform_action_in_plugin(action) | ||
|
|
||
|
|
||
| def perform_action_in_plugin(action): | ||
| # Wait for the plugin window to open. | ||
| world.wait_for_visible('.mce-window') | ||
|
|
||
| # Trigger the action | ||
| action() | ||
|
|
||
| # Click OK | ||
| world.css_click('.mce-primary') | ||
|
|
||
|
|
||
| @step('I save the page$') | ||
| def i_click_on_save(step): | ||
| world.save_component(step) | ||
|
|
||
|
|
||
| @step('the page text contains:') | ||
| def check_page_text(step): | ||
| assert_in(step.multiline, world.css_find('.xmodule_HtmlModule').html) | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you can use assert_in here, per my previous comment of checking whether the expected text is contained within the block, rather than equal to. |
||
|
|
||
| @step('the src link is rewritten to "(.*)"$') | ||
| def image_static_link_is_rewritten(step, path): | ||
| # Find the TinyMCE iframe within the main window | ||
| with world.browser.get_iframe('mce_0_ifr') as tinymce: | ||
| image = tinymce.find_by_tag('img').first | ||
| assert_in(path, image['src']) | ||
|
|
||
| # Test onExecCommandHandler set the url to absolute. | ||
| assert_in('c4x/MITx/999/asset/image.jpg', image['src']) | ||
|
|
||
| @step('the href link is rewritten to "(.*)"$') | ||
| def link_static_link_is_rewritten(step, path): | ||
| # Find the TinyMCE iframe within the main window | ||
| with world.browser.get_iframe('mce_0_ifr') as tinymce: | ||
| link = tinymce.find_by_tag('a').first | ||
| assert_in(path, link['href']) | ||
|
|
||
|
|
||
| @step('the expected toolbar buttons are displayed$') | ||
| def check_toolbar_buttons(step): | ||
| dropdowns = world.css_find('.mce-listbox') | ||
| assert_equal(2, len(dropdowns)) | ||
|
|
||
| # Format dropdown | ||
| assert_equal('Paragraph', dropdowns[0].text) | ||
| # Font dropdown | ||
| assert_equal('Font Family', dropdowns[1].text) | ||
|
|
||
| buttons = world.css_find('.mce-ico') | ||
|
|
||
| # Note that the code editor icon is not present because we are now showing text instead of an icon. | ||
| # However, other test points user the code editor, so we have already verified its presence. | ||
| expected_buttons = [ | ||
| 'bold', | ||
| 'italic', | ||
| 'underline', | ||
| 'forecolor', | ||
| # This is our custom "code style" button, which uses an image instead of a class. | ||
| 'none', | ||
| 'bullist', | ||
| 'numlist', | ||
| 'outdent', | ||
| 'indent', | ||
| 'blockquote', | ||
| 'link', | ||
| 'unlink', | ||
| 'image' | ||
| ] | ||
|
|
||
| assert_equal(len(expected_buttons), len(buttons)) | ||
|
|
||
| for index, button in enumerate(expected_buttons): | ||
| class_names = buttons[index]._element.get_attribute('class') | ||
| assert_equal("mce-ico mce-i-" + button, class_names) | ||
|
|
||
|
|
||
| @step('I set the text to "(.*)" and I select the text$') | ||
| def set_text_and_select(step, text): | ||
| script = """ | ||
| var editor = tinyMCE.activeEditor; | ||
| editor.setContent(arguments[0]); | ||
| editor.selection.select(editor.dom.select('p')[0]);""" | ||
| world.browser.driver.execute_script(script, str(text)) | ||
| world.wait_for_ajax_complete() | ||
|
|
||
|
|
||
| @step('I select the code toolbar button$') | ||
| def select_code_button(step): | ||
| # This is our custom "code style" button. It uses an image instead of a class. | ||
| world.css_click(".mce-i-none") | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,14 +2,8 @@ | |
|
|
||
| <div class="wrapper-comp-editor" id="editor-tab" data-base-asset-url="${base_asset_url}"> | ||
| <section class="html-editor editor"> | ||
| <ul class="editor-tabs"> | ||
| <li><a href="#" class="visual-tab tab current" data-tab="visual">${_("Visual")}</a></li> | ||
| <li><a href="#" class="html-tab tab" data-tab="advanced">${_("HTML")}</a></li> | ||
| </ul> | ||
|
|
||
| <div class="row"> | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @frrrances Should we get rid of this div (also in LMS template at the end)?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since TinyMCE inserts a bunch of stuff after the textarea below, I would like to keep this wrapper div in case we want to contain all of it. Thanks for asking though! |
||
| <textarea class="tiny-mce">${data | h}</textarea> | ||
| <textarea name="" class="edit-box">${data | h}</textarea> | ||
| </div> | ||
| </section> | ||
| </div> | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,7 +19,7 @@ | |
| } | ||
|
|
||
| .editor-tabs { | ||
| top: 11px !important; | ||
| top: 0 !important; | ||
| right: 10px; | ||
| z-index: 99; | ||
| } | ||
|
|
||
This file was deleted.
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,10 +1,3 @@ | ||
| <section class="html-edit"> | ||
| <ul class="editor-tabs"> | ||
| <li><a href="#" class="visual-tab tab current" data-tab="visual">Visual</a></li> | ||
| <li><a href="#" class="html-tab tab" data-tab="advanced">HTML</a></li> | ||
| </ul> | ||
| <div class="row"> | ||
| <textarea class="tiny-mce">dummy text</textarea> | ||
| <textarea name="" class="edit-box">Advanced Editor Text</textarea> | ||
| </div> | ||
| </section> | ||
| <textarea class="tiny-mce">dummy text</textarea> | ||
| </section> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we correct the close paren and put it on the following line? It would also make it clearer that the return and format statements are part of the execute_script call.