Skip to content
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

Saving playground code state #1917

Merged
merged 17 commits into from
Mar 22, 2024
Merged
Show file tree
Hide file tree
Changes from 16 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
7 changes: 6 additions & 1 deletion book.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,12 @@ urlcolor = "red"

[output.html]
curly-quotes = true
additional-js = ["theme/speaker-notes.js", "theme/redbox.js"]
additional-js = [
"theme/speaker-notes.js",
"theme/redbox.js",
"theme/save-playgrounds.js",
"theme/instructor-menu.js",
]
additional-css = [
"theme/css/svgbob.css",
"theme/css/redbox.css",
Expand Down
4 changes: 4 additions & 0 deletions theme/css/redbox.css
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,7 @@ div#aspect-ratio-helper div {
of vertical space to borders. */
aspect-ratio: 16/8.5;
}

#instructor-menu-list {
margin-left: 55px;
}
74 changes: 74 additions & 0 deletions theme/instructor-menu.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
(function handleInstructor() {
function handleInstructorMenu() {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Did you discuss simply adding this to the theme instead? Since this will be a permanent thing on all pages, it should go into index.hbs or head.hbs.

That would simplify the code a lot since you can just write out the HTML directly.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Why was this not done for the red box, you might ask? Because that was not supposed to be rendered for people looking at the course in the published version.

let leftButtons = document.getElementsByClassName("left-buttons")[0];
let instructorMenu = document.createElement("button");
let instructorMenuList = document.createElement("ul");
let redBoxItem = document.createElement("li");
let redBoxButton = document.createElement("button");
let playgroundStateItem = document.createElement("li");
let playgroundStateButton = document.createElement("button");

leftButtons.insertBefore(instructorMenu, leftButtons.lastChild);
leftButtons.insertBefore(instructorMenuList, leftButtons.lastChild);
instructorMenuList.insertBefore(redBoxItem, instructorMenuList.lastChild);
instructorMenuList.insertBefore(
playgroundStateItem,
instructorMenuList.lastChild
);
redBoxItem.insertBefore(redBoxButton, redBoxItem.lastChild);
playgroundStateItem.insertBefore(
playgroundStateButton,
playgroundStateItem.lastChild
);

instructorMenu.title = "Utilities for course instructors";
instructorMenu.innerHTML =
'<i class="fa fa-ellipsis-v" aria-hidden="true"></i>';
redBoxButton.innerHTML = "aspect-ratio box";
redBoxButton.title =
"Outline the area that fits on one screen while teaching the course.";
playgroundStateButton.innerHTML = "reset all playgrounds";
playgroundStateButton.title =
"Reset code in all playgrounds to its original value.";

instructorMenu.className = "icon-button";
instructorMenuList.className = "theme-popup";
redBoxButton.className = "theme";
playgroundStateButton.className = "theme";
instructorMenuList.style.display = "none";

instructorMenuList.role = "menu";
redBoxItem.role = "none";
playgroundStateItem.role = "none";
redBoxButton.role = "menuitem";
playgroundStateButton.role = "menuitem";

redBoxButton.id = "redbox";
instructorMenuList.id = "instructor-menu-list";
playgroundStateButton.id = "playground-state";

instructorMenu.addEventListener("click", () => {
if (instructorMenuList.style.display === "none") {
instructorMenuList.style.display = "block";
} else {
instructorMenuList.style.display = "none";
}
});

document.addEventListener("click", (e) => {
if (
!instructorMenu.contains(e.target) &&
!instructorMenuList.contains(e.target)
) {
instructorMenuList.style.display = "none";
}
});
}
handleInstructorMenu();
var redBoxButton = document.getElementById("redbox");
var playgroundStateButton = document.getElementById("playground-state");
redBoxButton.addEventListener("click", () => window.redboxButtonClicked());
playgroundStateButton.addEventListener("click", () =>
window.resetPlaygroundsClicked()
);
})();
35 changes: 13 additions & 22 deletions theme/redbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,19 @@
var parentElement = document.body; // Change this to your desired parent element
// Append the new div to the parent element
parentElement.insertBefore(newDiv, parentElement.firstChild);
// Create the button element
var hideShowButton = document.createElement("button");
hideShowButton.innerHTML = '<i class="fa fa-square-o"></i>';
hideShowButton.className = "icon-button";
hideShowButton.type = "button";
hideShowButton.title =
"Outline the area that fits on one screen while teaching the course.";
hideShowButton.id = "Dev";
var navbarButtons = document.getElementsByClassName("left-buttons");
navbarButtons[0].insertBefore(hideShowButton, navbarButtons.firstChild);
//Default hiding the redbox
document.getElementById("aspect-ratio-helper").style.display = "none";
//Add Event listener to button to perform on click action.
hideShowButton.addEventListener("click", function () {
if (
document.getElementById("aspect-ratio-helper").style.display === "none"
) {
document.getElementById("aspect-ratio-helper").style.display = "block";
hideShowButton.innerHTML = '<i class="fa fa-square"></i>';
} else {
document.getElementById("aspect-ratio-helper").style.display = "none";
hideShowButton.innerHTML = '<i class="fa fa-square-o"></i>';
}
});
})();

//Create a function to button to perform on click action.
function redboxButtonClicked() {
var hideShowButton = document.getElementById("redbox");
if (document.getElementById("aspect-ratio-helper").style.display === "none") {
document.getElementById("aspect-ratio-helper").style.display = "block";
hideShowButton.innerHTML = "aspect-ratio box";
} else {
document.getElementById("aspect-ratio-helper").style.display = "none";
hideShowButton.innerHTML = "aspect-ratio box";
}
}
window.redboxButtonClicked = redboxButtonClicked;
46 changes: 46 additions & 0 deletions theme/save-playgrounds.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
(function savePlaygrounds() {
function setCodeToPlayground() {
var codes = JSON.parse(
localStorage.getItem(`${window.location.href}₹code`)
djmitche marked this conversation as resolved.
Show resolved Hide resolved
);
if (codes) {
var i = 0;
Array.from(document.querySelectorAll(".playground")).forEach(function (
pre_block
) {
let code_block = pre_block.querySelector("code");
let editor = window.ace.edit(code_block);
editor.setValue(codes[i]);
editor.clearSelection();
i += 1;
});
}
}
function getCodeFromPlayground() {
var codes = [];
Array.from(document.querySelectorAll(".playground")).forEach(function (
pre_block
) {
let code_block = pre_block.querySelector("code");
let editor = window.ace.edit(code_block);
let code = editor.getValue();
codes.push(code);
});
localStorage.setItem(`${window.location.href}₹code`, JSON.stringify(codes));
Copy link
Collaborator

Choose a reason for hiding this comment

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

Has it already been discussed what the character is doing here? It looks a bit strange to me 😄

Have you considered using just the pathname instead of the full URL? Since local storage is different for different hosts, I don't think we need the full URL here.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Oh, if the is necessary somehow, then I would suggest creating a new function to construct the key. You can then document the use there — and also call it from both places that need this key.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh, if the is necessary somehow, then I would suggest creating a new function to construct the key. You can then document the use there — and also call it from both places that need this key.

Sorry, I didn't understand creating of "another function for key creating".

Copy link
Collaborator

Choose a reason for hiding this comment

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

Hey @mani-chand, I'm suggesting creating a one-line function which returns the correct key for the current page. Something like

function localStorageKey() {
  // The '₹' here is used for ...
  return `${window.location.href}₹code`
}

You should then explain what does here 🙂

}
setCodeToPlayground();
addEventListener("pagehide", getCodeFromPlayground);
})();

function resetPlaygroundsClicked() {
let keys = [];
for (var i = 0, len = localStorage.length; i < len; i++) {
if (localStorage.key(i).includes("₹code")) {
keys.push(localStorage.key(i));
}
}
for (let j = 0; j < keys.length; j++) {
localStorage.removeItem(keys[j]);
}
}
window.resetPlaygroundsClicked = resetPlaygroundsClicked;