Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
1c644fc
deleted old tinymce
devdob Feb 13, 2014
dda5866
new tinymce
devdob Feb 13, 2014
2ae2ec9
Include all the controls on the toolbar that we previously had.
Feb 20, 2014
0ddc3a6
Changes to support Bulk e-mail usage.
Feb 21, 2014
9bc0638
adding new studio skin for TinyMCE4
Mar 6, 2014
0d0ace4
Get handling of static image links working again.
Mar 13, 2014
1ece49c
Delete old Studio skin.
Mar 13, 2014
a14574e
Version 1.3 of CodeMirror plugin.
Mar 14, 2014
f6acab9
Modify paths for location of CodeMirror files.
Mar 17, 2014
9ac94fc
Fire events when CodeMirror Editor is open and closed.
Mar 17, 2014
9ec3a2d
Remove CodeMirror tabbed editor.
Mar 17, 2014
1e06fd3
fixed tinymce visual editor css
Mar 17, 2014
f71e333
Change how we detect that an image has been inserted.
Mar 17, 2014
b1b0d16
made the codemirror look more studio-like
Mar 18, 2014
7ac1e7b
reordered the tinymce buttons
Mar 18, 2014
28dc8e0
Update unit tests.
Mar 18, 2014
f31f936
Update acceptance test for image plugin.
Mar 18, 2014
d73f65c
Make sure to strip out temporary caret.
Mar 19, 2014
b1f4d28
Test for style block being maintained.
Mar 19, 2014
cc2fec2
Allow TinyMCE to create p's, else formatting doesn't work.
Mar 19, 2014
07d54be
Add tests for toolbar buttons and converting links.
Mar 19, 2014
09643c8
Add test for code format toolbar button.
Mar 20, 2014
9797354
Remove unnecessary code.
Mar 20, 2014
6c1d369
Remove unused testing templates and unused tabs.
Mar 20, 2014
ffbba2b
Update tinymce paths.
Mar 20, 2014
e1908b5
Fire an event with the link plugin closes so we can rewrite links.
Mar 20, 2014
fb6afc7
pep8
Mar 20, 2014
d623a4e
Updates from code review.
Mar 20, 2014
677f39d
Change the name of the button to "Edit HTML".
Mar 20, 2014
7ce576d
Changed name of "code" toolbar button to "Code block".
Mar 20, 2014
d89ebed
Upgrade version of TinyMCE to 4.0.16.
Mar 20, 2014
d3828f9
Fire events before and after the image dialog is shown.
Mar 21, 2014
b0c3598
Change the event handling for image plugin.
Mar 21, 2014
bb0a58a
Code review feedback.
Mar 21, 2014
a6b18de
Fire events before and after the link dialog is shown.
Mar 21, 2014
a9b9184
Remove unnecessary helper method.
Mar 21, 2014
9054c62
keeping the component editor inside the component window
Mar 21, 2014
8f6980b
Use compressed CodeMirror file.
Mar 21, 2014
ed51a66
replaced code icon in TinyMCE editor; simplified UI on TMCE toolbar
Mar 24, 2014
0953583
Change code editor icon to say HTML.
Mar 24, 2014
1cd6e1d
Move code style block button.
Mar 24, 2014
7b24172
Update tests for minor UI changes.
Mar 24, 2014
c8eaa53
Fix typos.
Mar 24, 2014
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 4 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ the top. Include a label indicating the component affected.
Blades: Fixed bug when image mapped input's Show Answer multiplies rectangles on
many inputtypes. BLD-810.

Studio and LMS: Upgrade version of TinyMCE to 4.0.16. Switch from tabbed Visual/HTML
Editor for HTML modules to showing the code editor as a plugin within TinyMCE (triggered
from toolbar). STUD-1422

LMS: Enabled screen reader feedback of problem responses.
LMS-2158

Expand Down
18 changes: 11 additions & 7 deletions cms/djangoapps/contentstore/features/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -318,19 +318,23 @@ def i_am_shown_a_notification(step):
assert world.is_css_present('.wrapper-prompt')


def type_in_codemirror(index, text):
def type_in_codemirror(index, text, find_prefix="$"):
script = """
var cm = $('div.CodeMirror:eq({})').get(0).CodeMirror;
var cm = {find_prefix}('div.CodeMirror:eq({index})').get(0).CodeMirror;
cm.getInputField().focus();
cm.setValue(arguments[0]);
cm.getInputField().blur();""".format(index)
cm.getInputField().blur();""".format(index=index, find_prefix=find_prefix)
world.browser.driver.execute_script(script, str(text))
world.wait_for_ajax_complete()

def get_codemirror_value(index=0):
return world.browser.driver.execute_script("""
return $('div.CodeMirror:eq({})').get(0).CodeMirror.getValue();
""".format(index))

def get_codemirror_value(index=0, find_prefix="$"):
return world.browser.driver.execute_script(
"""
return {find_prefix}('div.CodeMirror:eq({index})').get(0).CodeMirror.getValue();
""".format(index=index, find_prefix=find_prefix)
)

Copy link
Contributor

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.


def upload_file(filename):
path = os.path.join(TEST_ROOT, filename)
Expand Down
50 changes: 47 additions & 3 deletions cms/djangoapps/contentstore/features/html-editor.feature
Original file line number Diff line number Diff line change
Expand Up @@ -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>
"""

Copy link
Contributor

Choose a reason for hiding this comment

The 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 "&nbsp" or decides to put something else instead.

Copy link
Author

Choose a reason for hiding this comment

The 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.

Copy link
Author

Choose a reason for hiding this comment

The 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>
"""
180 changes: 155 additions & 25 deletions cms/djangoapps/contentstore/features/html-editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -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$')
Expand Down Expand Up @@ -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)

Copy link
Contributor

Choose a reason for hiding this comment

The 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")
1 change: 1 addition & 0 deletions cms/static/sass/views/_unit.scss
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,7 @@ body.course.unit,.view-unit {

.row {
margin-bottom: 0px;
overflow: hidden;
}

// Module Actions, also used for Static Pages
Expand Down
4 changes: 2 additions & 2 deletions cms/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@
"backbone": "js/vendor/backbone-min",
"backbone.associations": "js/vendor/backbone-associations-min",
"backbone.paginator": "js/vendor/backbone.paginator.min",
"tinymce": "js/vendor/tiny_mce/tiny_mce",
"jquery.tinymce": "js/vendor/tiny_mce/jquery.tinymce",
"tinymce": "js/vendor/tiny_mce/tinymce.min",
"jquery.tinymce": "js/vendor/tiny_mce/jquery.tinymce.min",
"xmodule": "/xmodule/xmodule",
"xblock": "coffee/src/xblock",
"utility": "js/src/utility",
Expand Down
6 changes: 0 additions & 6 deletions cms/templates/widgets/html-edit.html
Original file line number Diff line number Diff line change
Expand Up @@ -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">
Copy link
Author

Choose a reason for hiding this comment

The 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)?

Copy link
Contributor

Choose a reason for hiding this comment

The 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>
Expand Down
2 changes: 1 addition & 1 deletion common/lib/xmodule/xmodule/css/html/edit.scss
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
}

.editor-tabs {
top: 11px !important;
top: 0 !important;
right: 10px;
z-index: 99;
}
Expand Down

This file was deleted.

This file was deleted.

11 changes: 2 additions & 9 deletions common/lib/xmodule/xmodule/js/fixtures/html-edit.html
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>
Loading