Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions cms/static/coffee/fixtures/tabs-edit.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<div class="base_wrapper">
<section class="editor-with-tabs">
<div class="wrapper-comp-editor" id="editor-tab-id" data-html_id='test_id'>
<div class="edit-header">
<ul class="editor-tabs">
<li class="inner_tab_wrap"><a href="#tab-0" class="tab">Tab 0 Editor</a></li>
<li class="inner_tab_wrap"><a href="#tab-1" class="tab">Tab 1 Transcripts</a></li>
<li class="inner_tab_wrap" id="settings"><a href="#tab-2" class="tab">Tab 2 Settings</a></li>
</ul>
</div>
<div class="tabs-wrapper">
<div class="component-tab" id="tab-0">
<textarea name="" class="edit-box">XML Editor Text</textarea>
</div>
<div class="component-tab" id="tab-1">
Transcripts
</div>
<div class="component-tab" id="tab-2">
Subtitles
</div>
</div>
<div class="wrapper-comp-settings">
<ul>
<li id="editor-mode"><a>Editor</a></li>
<li id="settings-mode"><a>Settings</a></li>
</ul>
</div>
</div>
</section>

<div class="component-edit-header" style="display: block"/>
</div>

95 changes: 95 additions & 0 deletions cms/static/coffee/spec/tabs/edit.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
describe "TabsEditingDescriptor", ->
beforeEach ->
@isInactiveClass = "is-inactive"
@isCurrent = "current"
loadFixtures 'tabs-edit.html'
@descriptor = new TabsEditingDescriptor($('.base_wrapper'))
@html_id = 'test_id'
@tab_0_switch = jasmine.createSpy('tab_0_switch');
@tab_0_modelUpdate = jasmine.createSpy('tab_0_modelUpdate');
@tab_1_switch = jasmine.createSpy('tab_1_switch');
@tab_1_modelUpdate = jasmine.createSpy('tab_1_modelUpdate');
TabsEditingDescriptor.Model.addModelUpdate(@html_id, 'Tab 0 Editor', @tab_0_modelUpdate)
TabsEditingDescriptor.Model.addOnSwitch(@html_id, 'Tab 0 Editor', @tab_0_switch)
TabsEditingDescriptor.Model.addModelUpdate(@html_id, 'Tab 1 Transcripts', @tab_1_modelUpdate)
TabsEditingDescriptor.Model.addOnSwitch(@html_id, 'Tab 1 Transcripts', @tab_1_switch)

spyOn($.fn, 'hide').andCallThrough()
spyOn($.fn, 'show').andCallThrough()
spyOn(TabsEditingDescriptor.Model, 'initialize')
spyOn(TabsEditingDescriptor.Model, 'updateValue')

afterEach ->
TabsEditingDescriptor.Model.modules= {}

describe "constructor", ->
it "first tab should be visible", ->
expect(@descriptor.$tabs.first()).toHaveClass(@isCurrent)
expect(@descriptor.$content.first()).not.toHaveClass(@isInactiveClass)

describe "onSwitchEditor", ->
it "switching tabs changes styles", ->
@descriptor.$tabs.eq(1).trigger("click")
expect(@descriptor.$tabs.eq(0)).not.toHaveClass(@isCurrent)
expect(@descriptor.$content.eq(0)).toHaveClass(@isInactiveClass)
expect(@descriptor.$tabs.eq(1)).toHaveClass(@isCurrent)
expect(@descriptor.$content.eq(1)).not.toHaveClass(@isInactiveClass)
expect(@tab_1_switch).toHaveBeenCalled()

it "if click on current tab, nothing should happen", ->
spyOn($.fn, 'trigger').andCallThrough()
currentTab = @descriptor.$tabs.filter('.' + @isCurrent)
@descriptor.$tabs.eq(0).trigger("click")
expect(@descriptor.$tabs.filter('.' + @isCurrent)).toEqual(currentTab)
expect($.fn.trigger.calls.length).toEqual(1)

it "onSwitch function call", ->
@descriptor.$tabs.eq(1).trigger("click")
expect(TabsEditingDescriptor.Model.updateValue).toHaveBeenCalled()
expect(@tab_1_switch).toHaveBeenCalled()

describe "save", ->
it "function for current tab should be called", ->
@descriptor.$tabs.eq(1).trigger("click")
data = @descriptor.save().data
expect(@tab_1_modelUpdate).toHaveBeenCalled()

it "detach click event", ->
spyOn($.fn, "off")
@descriptor.save()
expect($.fn.off).toHaveBeenCalledWith(
'click',
'.editor-tabs .tab',
@descriptor.onSwitchEditor
)

describe "editor/settings header", ->
it "is hidden", ->
expect(@descriptor.element.find(".component-edit-header").css('display')).toEqual('none')

describe "TabsEditingDescriptor special save cases", ->
beforeEach ->
@isInactiveClass = "is-inactive"
@isCurrent = "current"
loadFixtures 'tabs-edit.html'
@descriptor = new window.TabsEditingDescriptor($('.base_wrapper'))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the only place I can see where you reference this from window. Am I missing something?

@html_id = 'test_id'

describe "save", ->
it "case: no init", ->
data = @descriptor.save().data
expect(data).toEqual(null)

it "case: no function in model update", ->
TabsEditingDescriptor.Model.initialize(@html_id)
data = @descriptor.save().data
expect(data).toEqual(null)

it "case: no function in model update, but value presented", ->
@tab_0_modelUpdate = jasmine.createSpy('tab_0_modelUpdate').andReturn(1)
TabsEditingDescriptor.Model.addModelUpdate(@html_id, 'Tab 0 Editor', @tab_0_modelUpdate)
@descriptor.$tabs.eq(1).trigger("click")
expect(@tab_0_modelUpdate).toHaveBeenCalled()
data = @descriptor.save().data
expect(data).toEqual(1)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also a test point for the model update function existing (making sure it takes precedence over stored value)?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test is in previous describe, line 51.

21 changes: 21 additions & 0 deletions cms/templates/widgets/tabs-aggregator.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<%! from django.utils.translation import ugettext as _ %>
<div class="wrapper-comp-editor" id="editor-tab-${html_id}" data-html_id="${html_id}">
<section class="editor-with-tabs">
<div class="edit-header">
<span class="component-name"></span>
<ul class="${'editor-tabs' if (len(tabs) != 1) else 'editor-single-tab-name' }">
% for tab in tabs:
<li class="inner_tab_wrap"><a href="#tab-${html_id}-${loop.index}" class="tab ${'current' if tab.get('current', False) else ''}">${_(tab['name'])}</a></li>
% endfor
</ul>
</div>
<div class="${'tabs-wrapper' if (len(tabs) != 1) else 'editor-single-tab' }">
% for tab in tabs:
<div class="component-tab ${'is-inactive' if not tab.get('current', False) else ''}" id="tab-${html_id}-${loop.index}" >
<%include file="${tab['template']}" args="tabName=tab['name']"/>
</div>
% endfor
</div>
</section>
</div>

24 changes: 24 additions & 0 deletions cms/templates/widgets/tabs/metadata-edit-tab.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<%namespace name='static' file='../../static_content.html'/>
<%
import json
%>

## js templates
<script id="metadata-editor-tpl" type="text/template">
<%static:include path="js/metadata-editor.underscore" />
</script>

<script id="metadata-number-entry" type="text/template">
<%static:include path="js/metadata-number-entry.underscore" />
</script>

<script id="metadata-string-entry" type="text/template">
<%static:include path="js/metadata-string-entry.underscore" />
</script>

<script id="metadata-option-entry" type="text/template">
<%static:include path="js/metadata-option-entry.underscore" />
</script>

<div class="wrapper-comp-settings metadata_edit" id="settings-tab" data-metadata='${json.dumps(editable_metadata_fields) | h}'/>

33 changes: 33 additions & 0 deletions cms/templates/widgets/videoalpha/codemirror-edit.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<%! from django.utils.translation import ugettext as _ %>
<%page args="tabName"/>
<div>
<textarea id="xml-${html_id}" class="edit-box">${data | h}</textarea>
</div>

<script type='text/javascript'>
$(document).ready(function(){
## Init CodeMirror editor
var el = $("#xml-${html_id}"),
xml_editor = CodeMirror.fromTextArea(el.get(0), {
mode: "application/xml",
lineNumbers: true,
lineWrapping: true
});

TabsEditingDescriptor.Model.addModelUpdate(
'${html_id}',
'${tabName}',
function() { return xml_editor.getValue(); })

TabsEditingDescriptor.Model.addOnSwitch(
'${html_id}',
'${tabName}',
function(){
## CodeMirror should get focus when tab is active
xml_editor.refresh();
xml_editor.focus();
}
)
});
</script>

Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.supertestclass{
color: red;
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.supertestclass{
color: red;
}

19 changes: 19 additions & 0 deletions common/lib/xmodule/xmodule/css/tabs/codemirror.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
.editor{
@include clearfix();

.CodeMirror {
@include box-sizing(border-box);
width: 100%;
position: relative;
height: 379px;
border: 1px solid #3c3c3c;
border-top: 1px solid #8891a1;
background: $white;
color: #3c3c3c;
}

.CodeMirror-scroll {
height: 100%;
}
}

137 changes: 137 additions & 0 deletions common/lib/xmodule/xmodule/css/tabs/tabs.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
// styles duped from _unit.scss - Edit Header (Component Name, Mode-Editor, Mode-Settings)


.tabs-wrapper{
padding-top: 0;
position: relative;

.wrapper-comp-settings {
// set visibility to metadata editor
display: block;
}
}

.editor-single-tab-name {
display: none;
}


.editor-with-tabs {
@include clearfix();
position: relative;


.edit-header {
@include box-sizing(border-box);
padding: 18px 0 18px $baseline;
top: 0 !important; // ugly override for second level tab override
right: 0;
background-color: $blue;
border-bottom: 1px solid $blue-d2;
color: $white;

//Component Name
.component-name {
@extend .t-copy-sub1;
position: relative;
top: 0;
left: 0;
width: 50%;
color: $white;
font-weight: 600;



em {
display: inline-block;
margin-right: ($baseline/4);
font-weight: 400;
color: $white;
}
}

//Nav-Edit Modes
.editor-tabs {
list-style: none;
right: 0;
top: ($baseline/4);
position: absolute;
padding: 12px ($baseline*0.75);

.inner_tab_wrap {
display: inline-block;
margin-left: 8px;

a.tab {
@include font-size(14);
@include linear-gradient(top, rgba(255, 255, 255, .3), rgba(255, 255, 255, 0));
border: 1px solid $blue-d1;
border-radius: 3px;
padding: ($baseline/4) ($baseline);
background-color: $blue;
font-weight: bold;
color: $white;

&.current {
@include linear-gradient($blue, $blue);
color: $blue-d1;
box-shadow: inset 0 1px 2px 1px $shadow-l1;
background-color: $blue-d4;
cursor: default;
}

&:hover {
box-shadow: inset 0 1px 2px 1px $shadow;
background-image: linear-gradient(#009FE6, #009FE6) !important;
}
}
}
}
}

.is-inactive {
display: none;
}

.comp-subtitles-entry {
text-align: center;

.file-upload {
display: none;
}

.comp-subtitles-import-list {
> li {
display: block;
margin: $baseline/2 0px $baseline/2 0;
}

.blue-button {
font-size: 1em;
display: block;
width: 70%;
margin: 0 auto;
text-align: center;
}
}
}


}

.component-tab {
background: $white;
position: relative;
border-top: 1px solid #8891a1;

&#advanced {
padding: 0;
border: none;
}

.blue-button {
@include blue-button;
}
}


Empty file.
Loading