Skip to content

Commit 42e23f1

Browse files
authored
Merge pull request #1224 from ascholerChemeketa/restore-tabbed-stuff
Restore tabbedstuff to interactives
2 parents 5b7d316 + cdd290d commit 42e23f1

4 files changed

Lines changed: 206 additions & 0 deletions

File tree

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<h2>Tabbed Stuff</h2>
2+
3+
```html
4+
<div data-component="tabbedStuff" id="tabbedstuff1">
5+
<div data-component="tab" data-tabname="Tab 1">
6+
Stuff in tab 1.
7+
</div>
8+
<div data-component="tab" data-tabname="Tab 2">
9+
Stuff in tab 2.
10+
</div>
11+
<div data-component="tab" data-inactive data-tabname="Tab 3">
12+
Stuff in tab 3.
13+
</div>
14+
</div>
15+
```
16+
17+
Here the <code>div</code> tag represents the entire Tabbed Stuff component to be rendered.
18+
Each Tabbed Stuff component contains a series of Tab components, which are also <code>div</code> elements.
19+
Each Tab component can contain anything from text to other working components such as Multiple Choice, Activecode, etc.
20+
By default, the first tab is opened on page load, but this can be changed by the presence of <code>data-inactive</code> in the Tabbed Stuff tag or <code>data-active</code> in one of the tabs.
21+
22+
Option spec:
23+
24+
<ul>
25+
<li><code>data-component="tabbedStuff"</code> Identifies this as a Tabbed Stuff component</li>
26+
<li><code>id</code> Must be unique in the document</li>
27+
<li><code>data-inactive</code> Ensures that no tabs are open by default on page load--this overrides any data-active attribute in a tab tag.</li>
28+
</ul>
29+
30+
Option spec for each tab:
31+
32+
<ul>
33+
<li><code>data-component="tab"</code> Identifies this as a Tab component</li>
34+
<li><code>data-tabname</code> This is the text that appears on the top of the tab that users can click to open the tab.</li>
35+
<li><code>data-active</code> Specifies this tab to be opened on page load--only one per Tabbed Stuff component, and is overridden by the presence of <code>data-inactive</code> in the Tabbed Stuff tag. The default tab to be opened on page load is the first tab.</li>
36+
</ul>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
.tab-pane {
2+
padding: 20px 15px 10px 15px;
3+
}
4+
5+
.nav.nav-tabs {
6+
padding-top: 6px;
7+
background-color: var(--componentBgColor);
8+
border-color: var(--componentBorderColor);
9+
}
10+
11+
.nav.nav-tabs > li {
12+
margin-right: 1px;
13+
margin-left: 6px;
14+
}
15+
16+
.nav.nav-tabs > li > a {
17+
border: 1px solid var(--componentBorderColor);
18+
border-radius: 4px 4px 0 0;
19+
color: var(--bodyFont, #555);
20+
}
21+
22+
.nav.nav-tabs > li.active > a,
23+
.nav.nav-tabs > li > a:is(:hover, :focus),
24+
.nav.nav-tabs > li.active > a:is(:hover, :focus) {
25+
background-color: #156ba4;
26+
color: white;
27+
}
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
/*==========================================
2+
======= Master tabbedstuff.js ========
3+
============================================
4+
=== This file contains the JS for ===
5+
=== the Runestone tabbedStuff component. ===
6+
============================================
7+
=== Created by ===
8+
=== Isaiah Mayerchak ===
9+
=== 06/15/15 ===
10+
=== Brad Miller ===
11+
=== 06/15/15 ===
12+
==========================================*/
13+
"use strict";
14+
15+
var TSList = {}; // Dictionary that contains all instances of TabbedStuff objects
16+
17+
import RunestoneBase from "../../common/js/runestonebase";
18+
import "../css/tabbedstuff.css";
19+
20+
// Define TabbedStuff object
21+
class TabbedStuff extends RunestoneBase {
22+
constructor(opts) {
23+
super(opts);
24+
var orig = opts.orig;
25+
this.origElem = orig; // entire original <div> element that will be replaced by new HTML
26+
this.divid = orig.id;
27+
this.inactive = false;
28+
if ($(this.origElem).is("[data-inactive]")) {
29+
this.inactive = true;
30+
}
31+
this.togglesList = []; // For use in Codemirror/Disqus
32+
this.childTabs = [];
33+
this.populateChildTabs();
34+
this.activeTab = 0; // default value--activeTab is the index of the tab that starts open
35+
this.findActiveTab();
36+
this.createTabContainer();
37+
this.indicate_component_ready();
38+
}
39+
/*===========================================
40+
== Update attributes of instance variables ==
41+
== variables according to specifications ==
42+
===========================================*/
43+
populateChildTabs() {
44+
for (var i = 0; i < this.origElem.childNodes.length; i++) {
45+
if ($(this.origElem.childNodes[i]).data("component") === "tab") {
46+
this.childTabs.push(this.origElem.childNodes[i]);
47+
}
48+
}
49+
}
50+
findActiveTab() {
51+
for (var i = 0; i < this.childTabs.length; i++) {
52+
if ($(this.childTabs[i]).is("[data-active]")) {
53+
this.activeTab = i;
54+
}
55+
}
56+
}
57+
/*==========================================
58+
== Creating/appending final HTML elements ==
59+
==========================================*/
60+
createTabContainer() {
61+
this.containerDiv = document.createElement("div");
62+
this.containerDiv.id = this.divid;
63+
$(this.containerDiv).addClass(this.origElem.getAttribute("class"));
64+
$(this.containerDiv).attr({ role: "tabpanel" });
65+
this.tabsUL = document.createElement("ul");
66+
this.tabsUL.id = this.divid + "_tab";
67+
$(this.tabsUL).addClass("nav nav-tabs");
68+
$(this.tabsUL).attr({ role: "tablist" });
69+
this.tabContentDiv = document.createElement("div"); // Create tab content container that holds tab panes w/content
70+
$(this.tabContentDiv).addClass("tab-content");
71+
this.createTabs(); // create and append tabs to the <ul>
72+
this.containerDiv.appendChild(this.tabsUL);
73+
this.containerDiv.appendChild(this.tabContentDiv);
74+
this.addCMD(); // Adds fuctionality for Codemirror/Disqus
75+
$(this.origElem).replaceWith(this.containerDiv);
76+
}
77+
createTabs() {
78+
// Create tabs in format <li><a><span></span></a></li> to be appended to the <ul>
79+
for (var i = 0; i < this.childTabs.length; i++) {
80+
// First create tabname and tabfriendly name that has no spaces to be used for the id
81+
var tabListElement = document.createElement("li");
82+
$(tabListElement).attr({
83+
role: "presentation",
84+
"aria-controls": this.divid + "-" + i
85+
});
86+
// Using bootstrap tabs functionality
87+
var tabElement = document.createElement("a");
88+
$(tabElement).attr({
89+
"data-toggle": "tab",
90+
href: "#" + this.divid + "-" + i,
91+
role: "tab"
92+
});
93+
var tabTitle = document.createElement("span"); // Title of tab--what the user will see
94+
tabTitle.textContent = $(this.childTabs[i]).data("tabname");
95+
tabElement.appendChild(tabTitle);
96+
tabListElement.appendChild(tabElement);
97+
this.tabsUL.appendChild(tabListElement);
98+
// tabPane is what holds the contents of the tab
99+
var tabPaneDiv = document.createElement("div");
100+
tabPaneDiv.id = this.divid + "-" + i;
101+
$(tabPaneDiv).addClass("tab-pane");
102+
$(tabPaneDiv).attr({
103+
role: "tabpanel"
104+
});
105+
//var tabHTML = $(this.childTabs[i]).html();
106+
//$(tabPaneDiv).html(tabHTML);
107+
tabPaneDiv.appendChild(this.childTabs[i]);
108+
if (!this.inactive) {
109+
if (this.activeTab === i) {
110+
$(tabListElement).addClass("active");
111+
$(tabPaneDiv).addClass("active");
112+
}
113+
}
114+
this.togglesList.push(tabElement);
115+
this.tabContentDiv.appendChild(tabPaneDiv);
116+
}
117+
}
118+
/*===================================
119+
== Codemirror/Disqus functionality ==
120+
===================================*/
121+
addCMD() {
122+
$(this.togglesList).on("shown.bs.tab", function(e) {
123+
var content_div = $(e.target.attributes.href.value);
124+
content_div.find(".disqus_thread_link").each(function() {
125+
$(this).click();
126+
});
127+
content_div.find(".CodeMirror").each(function(i, el) {
128+
el.CodeMirror.refresh();
129+
});
130+
});
131+
}
132+
}
133+
134+
/*=================================
135+
== Find the custom HTML tags and ==
136+
== execute our code on them ==
137+
=================================*/
138+
$("load", function() {
139+
$("[data-component=tabbedStuff]").each(function(index) {
140+
TSList[this.id] = new TabbedStuff({ orig: this });
141+
});
142+
});

bases/rsptx/interactives/webpack.index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ const module_map = {
7474
shortanswer: () =>
7575
import("./runestone/shortanswer/js/timed_shortanswer.js"),
7676
showeval: () => import("./runestone/showeval/js/showEval.js"),
77+
tabbedStuff: () => import("./runestone/tabbedStuff/js/tabbedstuff.js"),
7778
timedAssessment: () => import("./runestone/timed/js/timed.js"),
7879
// TODO: since this isn't in a ``data-component``, need to trigger an import of this code manually.
7980
webwork: () => import("./runestone/webwork/js/webwork.js"),

0 commit comments

Comments
 (0)