How to reload page without losing any data - javascript

I am pretty new to web development and I am making this little project that consists in a little site that allows a user to add and remove their goals(kinda like a to do list)
I want to implement a last feature that allows the browser to save the content of the page, so that if the user reloads the page, he/she does not lose track of their goals. I tried using local storage but it's not working.
Any suggestion/tips on how to tackle such problem?
Thank you very much and I apologise, in advance for the code smell.
var i = 0
var j =0
var parentElement = document.getElementById('new-goals')
function addGoal(){
var userGoal = window.prompt('Enter goal: ')
var divTag = document.createElement('div')
divTag.className = 'goalsSection'
divTag.id = 'goal- ' + i
i++
var goal = document.createElement('p')
goal.innerHTML = userGoal
goal.className= 'usergoal'
goal.id = 'UserGoal'+j
var del = document.createElement('button')
del.className = 'deleteButton'
del.innerHTML = 'Delete Goal'
del.id = j
var com = document.createElement('button')
com.className = 'completedButton'
com.innerHTML = 'Not Completed'
com.id = j
j++
com.onclick = function(e){
if (com.innerHTML == 'Not Completed' ){
var dec = window.prompt('Are you sure? this action can not be undo type y/n')
if (dec == 'y'){
com.innerHTML = 'Completed'
var ele = e.target.id
var fin = 'UserGoal'+ele
document.getElementById(fin).style.textDecoration='line-through'
}
}
}
divTag.appendChild(goal)
divTag.appendChild(del)
divTag.appendChild(com)
parentElement.appendChild(divTag)
del.onclick = function(e){
var id_toDelete = e.target.id
var id_section = 'goal- ' + id_toDelete
alert(id_section)
parentElement.removeChild(divTag)
}
}
body{
background-color: #003f5c;
}
h1{
display: flex;
justify-content: center;
font-size: 60px;
font-family: 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif;
}
.btnConatiner{
display: flex;
justify-content: center;
align-items: center;
margin-bottom: 40px;
}
#newGoalBtn{
display: flex;
justify-content: center;
align-items: center;
width: 200px;
height: 50px;
font-size: 30px;
border-radius: 15px;
border: solid 5px black;
cursor: pointer;
}
.goalsSection{
border: solid 6px white;
width: 200px;
height: 100px;
border-radius: 20px;
background-color: white;
margin: 10px;
float: left;
}
.usergoal{
text-align: center;
font-size:20px;
}
.deleteButton{
cursor: pointer;
}
.completedButton{
cursor: pointer;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
<title>Goal Tracker</title>
</head>
<body>
<h1>Goal Tracker</h1>
<div class="btnConatiner">
<button id="newGoalBtn" onclick="addGoal()">New Goal</button>
</div>
<section class="add-goals">
<div id="new-goals">
</div>
</section>
<script src="app.js"></script>
</body>
</html>

Inside the function addGoal, you can get all the goals that are already on the localstorage, and then push a new goal into the array and store.
// const goals = localStorage.getItem("goals") || []; // you can declare here too.
function addGoal() {
const goals = localStorage.getItem("goals") || [];
const userGoal = window.prompt("Enter goal:")
goals.push(userGoal)
localStorage.setItem('goals', JSON.stringify(goals)) // you need to transform into string
...
And then you can create a function to render the goals that are on the localstorage, like:
function renderGoals() {
const goals = JSON.parse(localStorage.getItem("goals")); // parsing back
// Then you can iterate on these goals (forEach for example) to render.
...
}

You can use localStorage, but not to store all the HTML you're creating, rather to store the essential data. And from that data, you can easily rebuild your html.
First keep track of your data, and set up your addGoal function to accept an argument for the rebuilding (after page refresh)
let userGoals = [] // leave this empty for the moment
function addGoal(userGoal){
if (!userGoal) { // this is a new one, so we'll store it in the array and localStorage
userGoal = window.prompt('Enter goal: ')
userGoals.push(userGoal);
localStorage.setItem('userGoals', JSON.stringify(userGoals)); // localStorage stores everything as strings so we stringify it
}
//... the rest of this function
Then at the bottom of your script, create a window.onload function that runs once, when the page first loads. If there is data in localStorage, this will create your User Goals list
window.onload = function() { // this runs after the page has loaded
if (localStorage.getItem('userGoals') ) { // if we have localStorage values waiting for us, parse them and iterate through them
JSON.parse(localStorage.getItem('userGoals')).forEach(goal => {
userGoals.push(goal)
addGoal(goal)
});
}
}
...

Related

How to use my API data I gathered through a GET request into a separate function

I am tasked with fetching data from an API and storing that data on a card for the game jeopardy I am creating. I am able to successfully fetch my data question from my api but am having a hard time of implementing it into my card. I am trying to access the variable 'res' in my addGenre() function so that I can assign the cards the questions.
const game = document.querySelector("#game");
const scoreDisplay = document.getElementById("score");
// ("https://opentdb.com/api.php?amount=10&category=11&difficulty=easy&type=boolean");
const film = 11;
const levels = ["easy", "medium", "hard"];
function addGenre() {
const column = document.createElement("div");
column.classList.add("genre-column");
column.innerText = "This is a genre";
game.append(column);
levels.forEach((lev) => {
const card = document.createElement("div");
card.classList.add("card");
column.append(card);
getEasy();
});
}
const getEasy = async function (level) {
const res = await axios.get(
`https://opentdb.com/api.php?amount=10&category=11&difficulty=${level}`
);
console.log(res);
return res;
};
addGenre();
body{
margin: 0;
padding: 0;
background-color: dodgerblue;
color: white;
font-family: Arial, Helvetica, sans-serif;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.genre-column{
display: flex;
flex-direction: column;
text-align: center;
}
.card{
width: 200px;
height: 120px;
border-radius: 20px;
background-color: blue;
text-align: center;
padding: 5px;
margin: 10px;
border: 3px solid yellow;
}
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Jeopardy</title>
<link href="https://fonts.googleapis.com/css?family=Copse&display=swap"
rel="stylesheet">
<link rel="stylesheet" href="app.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/all.min.css">
</head>
<body>
<h1>Let's Play!</h1>
<div id="game">
</div>
<h2>Score : <span id="score">0</span></h2>
<script src="https://unpkg.com/jquery"></script>
<script src="https://unpkg.com/axios/dist/axios.js"></script>
<script src="https://unpkg.com/lodash"></script>
<script src="app.js"></script>
</body>
</html>
You can invoke the getEasy method from inside the addGenre method. If you want to preserve the order you can do the following:
async function addGenre() {
// other code removed for brevity
// Make a request for every level and save it in the "requests" array
const requests = levels.map((lev) => getEasy(lev));
// Wait for all of the requests to finish. We will have a list of "responses" from the API
const responses = await Promise.all(requests);
// For each response, create a card an append it to the DOM
responses.forEach((res) => {
const card = document.createElement("div");
card.classList.add("card");
column.append(card);
// add whatever else you want to the card here
});
}
function addGenre() {
const column = document.createElement("div");
column.classList.add("genre-column");
column.innerText = "This is a genre";
game.append(column);
levels.forEach((lev) => {
const card = document.createElement("div");
card.classList.add("card");
column.append(card);
getEasy(lev).then((value) => {
card.innerText = value;
});
});
}

How to add bg image to API weather project?

Hello lately i've been working with APIs to get the hang of them through the usual weather app project BUT i'm pretty much still a beginner in javascript and i was wondering how to add a background image that matches the weather report of the city selected by the user.
I wanted to create many classes in css, each called like the weather (ex: .clear, .clouds,.rain etc...) and then use a classList.add() method to change it each time depending on the openWeatherMap data. I tried adding something like document.getElementsByTagName("body")[0].classList.add(weatherValue); inside the .then promise but it doesn't work. Can somebody help me? If there's a much simpler way i'd like to hear about it too :) Thank you so much
var button = document.querySelector(".button");
var inputValue = document.querySelector(".inputValue");
var cityName = document.querySelector(".name");
var weather = document.querySelector(".weather");
var desc = document.querySelector(".desc");
var temp = document.querySelector(".temp");
var humi = document.querySelector(".humi");
button.addEventListener("click", function() {
fetch("https://api.openweathermap.org/data/2.5/weather?q="+inputValue.value+"&appid={myapikey}")
.then(response => response.json())
.then(data => {
var nameValue = data['name'];
var weatherValue = data['weather'][0]['main'];
var tempValue = data['main']['temp'];
var descValue = data['weather'][0]['description'];
var humiValue = data['main']['humidity'];
cityName.innerHTML = nameValue;
weather.innerHTML = weatherValue; // this gives "clear" "clouds" etc to <p> element
desc.innerHTML = descValue;
temp.innerHTML = "Temperature: " + tempValue;
humi.innerHTML = "Humidity: " + humiValue;
})
.catch(err => alert("Wrong city name!"))
})
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: "Nunito", sans-serif;
background-repeat: no-repeat;
background-size: cover;
}
.input {
text-align: center;
margin: 100px 0;
}
input[type="text"] {
height: 50px;
width: 600px;
background: #e7e7e7;
font-family: "Nunito", sans-serif;
font-weight: bold;
font-size: 20px;
border: none;
border-radius: 2px;
padding: 10px 10px;
}
input[type="submit"] {
height: 50px;
width: 100px;
background: #e7e7e7;
font-family: "Nunito", sans-serif;
font-weight: bold;
font-size: 20px;
border: none;
border-radius: 2px;
}
.display {
text-align: center;
}
.clear {
/* background image here */
}
.clouds {
/* another background image here */
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="weather_app.css">
</head>
<body>
<div class="input">
<input type="text" class="inputValue" placeholder="Enter a city">
<input type="submit" value="Submit" class="button">
</div>
<div class="display">
<h1 class="name"></h1>
<p class="weather"></p>
<p class="desc"></p>
<p class="temp"></p>
<p class="humi"></p>
</div>
<script src= "weather_app.js"></script>
</body>
</html>
I did a project like this not long ago, https://github.com/Kroplewski-M/Weather-App , I used the openWeater API. I did this:
function setBackground(weather) {
if (weather == "Rain") {
background.src = "./resources/rainy-weather.jpg";
} else if (weather == "Snow") {
background.src = "./resources/snowy-weather.jpg";
} else if (weather == "Clear") {
background.src = "./resources/sunny-weather.jpg";
} else if (weather == "Clouds") {
background.src = "./resources/cloudy-weather.jpg";
}
}
The openWeather API returns what condition the weather is so you can just if statement on what the condition is and set the background accordingly

looking for why list does not display when adding task to the to do

Good day folks,
I am creating a to-do app, and so far when I enter the task in via the input the console shows my object firing but does not display it on the screen. Please look at my code and help me point out the issue, I have been debugging this for some time today.
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="css/to-doStylesheet.css">
<title>To-Do App</title>
</head>
<body>
<div class=container>
<div class= base>
<div class = screen>
<img src="images/WarGreymon_Render.png" alt="Wargreymon">
<div id ="speach-bubble"> What is on your
agenda for today?
</div>
<div class = "dateTime">
</div>
</div>
<div class = "nameInput" id = "inputContainer">
<form class ="form">
<input type="text" class ="userInput" placeholder="Add Agenda and press enter">
<input type="submit" value ="Add">
</form>
</div>
</div>
<ul class="list"></ul>
<script src="js/add-task.js"></script>
</body>
</html>
CSS
.form
{
margin-left: 400px;
}
.userInput
{
width: 394px;
height: 30px;
background-color: #B62626;
font-family: Digimon Basic;
color: #33D61A;
margin-left: -359px;
}
.userInput ::placeholder
{
color: #33D61A;
font-family: Digimon Basic;
}
.list:empty
{
display: none;
}
.list
{
list-style: none;
margin-bottom: 20px;
}
.input[type="checkbox"] {
display: none;
}
.tick {
width: 30px;
height: 30px;
border: 3px solid #333;
border-radius: 50%;
display: inline-flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
.todo-item {
margin-bottom: 10px;
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
}
.todo-item span {
flex-grow: 1;
margin-left: 10px;
margin-right: 10px;
font-size: 22px;
}
JS
let tasks = [];
const currentdt = new Date()
function todo(text) {
const todo = {
text,
checked: false,
id: Date.now(),
timestamp: currentdt
};
tasks.push(todo);
console.log(tasks);
}
// Select the form element
const form = document.querySelector('.form');
// Add a submit event listener
form.addEventListener('submit', event => {
// prevent page refresh on form submission
event.preventDefault();
// select the text input
const input = document.querySelector('.userInput');
// Get the value of the input and remove whitespace
const text = input.value.trim();
if (text !== '') {
todo(text);
input.value = '';
input.focus();
}
});
//This function is to display new to do on the screen
function displaytasks(todo)
{
const list = document.querySelector('list');
const isChecked = todo.checked ? 'done': '';
const addedList = document.createElement("li");
addedList.setAttribute('class', `todo-item ${isChecked}`);
addedList.setAttribute('data-key', todo.timestamp);
addedList.innerHTML = `<input id="${todo.timestamp}" type="checkbox"/>
<label for="${todo.timestamp}" class="tick js-tick"></label>
<span>${todo.text}</span>
<button class="delete-todo js-delete-todo">
<img class = "delete" src="images/delete.png" alt="delete icon">
</button>`;
list.append(addedList);
}
So I am busy with the js file at the moment, I think it has to do something with the innerHTML, but I am not sure what exactly is wrong there, because when I look in the console on the HTML side I do not see the <ul class="list"></ul> firing at all to bring the new HTML elements.
Your help will be much appreciated
It looks like the code to display the todos is not being called, so I would recommend you add in a function call after reading in a new todo.
...
const text = input.value.trim();
if (text !== '') {
todo(text);
input.value = '';
input.focus();
displaytasks(tasks); // Show tasks after submission
}
});
//This function is to display new to do on the screen
function displaytasks(todo)
{
const list = document.querySelector('.list');
...

Javascript Copy function handle not working

I am writing copy button for code-blocks, but the button can not handle "copy" event.
The buttons are created with createElement method, and event added to the buttons with addEventListener to the buttons, before appending to the blocks, through foreach loop.
JSFiddle Link of the blocks
Create Button code:
const textspan = document.createElement("SPAN");
const bgbutton = document.createElement("BUTTON");
bgbutton.classList.add("btnCopy", "badge");
bgbutton.innerText = "copy";
bgbutton.addEventListener('click', copytextHandle);
textspan.appendChild(bgbutton);
const codeSyn = document.querySelectorAll("pre");
codeSyn.forEach(function(el) {
el.insertAdjacentElement('afterbegin', textspan);
})
In my text, I have three blocks, but only one button is visible(last), first two blocks has no button.
Also, the click event, and functionality can not implemented with click hook. The problem is straight about, click event, please mention which causing the error.
window.addEventListener('load', function() {
var y = document.querySelectorAll("pre code");
for(var i = 0; i < y.length; i++) {
y[i].innerHTML = y[i].innerHTML.replace(/^\r?\n/, "");
}
const textspan = document.createElement("SPAN");
const bgbutton = document.createElement("BUTTON");
bgbutton.classList.add("btnCopy", "badge");
bgbutton.innerText = "copy";
bgbutton.addEventListener('click', copytextHandle);
textspan.appendChild(bgbutton);
const codeSyn = document.querySelectorAll("pre");
codeSyn.forEach(function(el) {
el.insertAdjacentElement('afterbegin', textspan);
})
})
const copytextHandle = (e) => {
const codeBlock = document.querySelectorAll(".hljs-ln")[e.target.dataset.idx];
const text = codeBlock
.innerText
.trim()
.replace(/\s+/g, " ")
.replace(/}/g, "}\n")
.replace(/{ /g, "{\n ")
.replace(/;/g, ";\n ")
copySuccess.classList.remove('hide');
navigator.clipboard.writeText(text).then(() => setTimeout(() => bgbutton.innerHTML("Copied"),200),
(e) => {
console.log('Error writing to the clipboard', e.message);
copySuccess.classList.add('hide');
}
);
};
span > button.btnCopy {
position: absolute;
right: 0;
margin-top: 0.6rem;
}
pre {
position: relative;
}
.btnCopy{border:none; background-color: #e8e8e8;}
/*background-color:a5a5a5, 9c9c9c*/
.btnCopy:hover{background-color: #585858}
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Testing HighlightJS</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap#5.0.0-beta2/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.6.0/styles/routeros.min.css">
</head>
<body>
<h3>Testing HighlightJS Multiple blocks</h3>
<h4>First Code block</h4>
<pre><code class="language-css">
.class{
font-size: 0.85rem;
font-weight: 600;
font-family: monospace;
}
h1 .header{
font-size: 1.5rem;;
font-family: Arial;
}
</code></pre>
<h4>Second Code block</h4>
<pre><code class="language-css">
.class{
font-size: 0.85rem;
font-weight: 600;
font-family: monospace;
}
h1 .header{
font-size: 1.5rem;;
font-family: Arial;
}
</code></pre>
<h4>Third Code block</h4>
<pre><code class="language-css">
.class{
font-size: 0.85rem;
font-weight: 600;
font-family: monospace;
}
h1 .header{
font-size: 1.5rem;;
font-family: Arial;
}
</code></pre>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.0.0-beta2/dist/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.6.0/highlight.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.6.0/languages/css.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlightjs-line-numbers.js/2.6.0/highlightjs-line-numbers.min.js"></script>
<script>hljs.highlightAll(); hljs.initLineNumbersOnLoad();</script>
</body>
</html>
After clicking the button copy you can get to a <table> element which is inside one of your <code> elements with this code:
const codeBlock = e.target.parentNode.nextSibling.children[0];
Once that is applied, the text within <code> gets copied to the variable text which we can see by running the code below and checking the console output.
The copy buttons now appear on all <code> blocks. I've added the code to create the button and span inside the codeSyn.forEach(function(el) { ... }, so that new elements are created for every <pre> that you are iterating through.
Another problem that arises is:
Uncaught ReferenceError: copySuccess is not defined
To resolve this error you should assign an HTML element that has class hide to the variable copySuccess so that this works:
copySuccess.classList.remove('hide');
Check the below code:
window.addEventListener('load', function() {
var copySuccess = document.getElementById("copySuccess");
var y = document.querySelectorAll("pre code");
for(var i = 0; i < y.length; i++) {
y[i].innerHTML = y[i].innerHTML.replace(/^\r?\n/, "");
}
const codeSyn = document.querySelectorAll("pre");
codeSyn.forEach(function(el) {
const textspan = document.createElement("SPAN");
const bgbutton = document.createElement("BUTTON");
bgbutton.classList.add("btnCopy", "badge");
bgbutton.innerText = "copy";
bgbutton.addEventListener('click', copytextHandle);
textspan.appendChild(bgbutton);
el.insertAdjacentElement('afterbegin', textspan);
})
})
const copytextHandle = (e) => {
const codeBlock = e.target.parentNode.nextSibling.children[0];
const text = codeBlock
.innerText
.trim()
.replace(/\s+/g, " ")
.replace(/}/g, "}\n")
.replace(/{ /g, "{\n ")
.replace(/;/g, ";\n ");
navigator.clipboard.writeText(text).then(() => setTimeout(() => e.target.innerHTML = "copied",2000),
(e) => {
console.log('Error writing to the clipboard', e.message);
}
);
};
span > button.btnCopy {
position: absolute;
right: 0;
margin-top: 0.6rem;
}
pre {
position: relative;
}
.hide {
display: none;
}
.btnCopy{border:none; background-color: #e8e8e8;}
/*background-color:a5a5a5, 9c9c9c*/
.btnCopy:hover{background-color: #585858}
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Testing HighlightJS</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap#5.0.0-beta2/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.6.0/styles/routeros.min.css">
</head>
<body>
<h3>Testing HighlightJS Multiple blocks <span id="copySuccess" class="hide">Copied...</span></h3>
<h4>First Code block</h4>
<pre><code class="language-css">
.class{
font-size: 0.85rem;
font-weight: 600;
font-family: monospace;
}
h1 .header{
font-size: 1.5rem;
font-family: Arial;
}
</code></pre>
<h4>Second Code block</h4>
<pre><code class="language-css">
.class{
font-size: 0.85rem;
font-weight: 600;
font-family: monospace;
}
h1 .header{
font-size: 1.5rem;
font-family: Arial;
}
</code></pre>
<h4>Third Code block</h4>
<pre><code class="language-css">
.class{
font-size: 0.85rem;
font-weight: 600;
font-family: monospace;
}
h1 .header{
font-size: 1.5rem;
font-family: Arial;
}
</code></pre>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.0.0-beta2/dist/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.6.0/highlight.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.6.0/languages/css.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlightjs-line-numbers.js/2.6.0/highlightjs-line-numbers.min.js"></script>
<script>hljs.highlightAll(); hljs.initLineNumbersOnLoad();</script>
</body>
</html>
What is happeninig is you're moving the same button in a loop all the way to last pre. Use eg. cloneNode to make a new button per pre element.
simple move scenario (https://jsfiddle.net/jtg6fczd/)
document.querySelector("div").append(button) // adds button to div
document.body.append(button) // moves button out of div

Save contentEditable into html file with javascript

How can I save contenteditable element with javascript(no PHP) into actual HTML code? So I can edit content whenever even in offline mode.
Like when you click "save button" it replace old file with new one(text with changes).
If there is a way to make this work in offline mode with any other programming lang please suggest.
I found a few examples but they were all made with PHP.
Also, I will post code. In this code, you are able to edit the file with javascript and save it. But problem is that it does not save into actual HTML code.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title of the document</title>
</head>
<style type="text/css">
body{
font-family: "Dosis";
font-size: 1.3em;
line-height: 1.6em;
}
.headline{
font-size: 2em;
text-align: center;
}
#wrapper {
width: 600px;
background: #FFF;
padding: 1em;
margin: 1em auto;
box-shadow: 0 2px 5px rgba(0,0,0,0.3);
border-radius: 3px;
}
button {
border: none;
padding: 0.8em;
background: #F96;
border-radius: 3px;
color: white;
font-weight: bold;
margin: 0 0 1em;
}
button:hover, button:focus {
cursor: pointer;
outline: none;
}
#editor {
padding: 1em;
background: #E6E6E6;
border-radius: 3px;
}
</style>
<body>
<div id="wrapper">
<section>
<h1 class="headline">contentEditable Demonstration</h1>
<button id="editBtn" type="button">Edit Document</button>
<div id="editDocument">
<h1 id="title">A Nice Heading.</h1>
<p>Last Edited by <span id="author">Monty Shokeen</span>
</p>
<p id="content">You can change the heading, author name and this content itself. Click on Edit Document to start editing. At this point, you can edit this document and the changes will be saved in localStorage. However, once you reload the page your changes will be gone. To fix it we will have to retrieve the contents from localSotrage when the page reloads.</p>
</div>
</section>
</div>
<script>
var editBtn = document.getElementById('editBtn');
var editables = document.querySelectorAll('#title, #author, #content');
if (typeof(Storage) !== "undefined") {
if (localStorage.getItem('title') !== null) {
editables[0].innerHTML = localStorage.getItem('title');
}
if (localStorage.getItem('author') !== null) {
editables[1].innerHTML = localStorage.getItem('author');
}
if (localStorage.getItem('content') !== null) {
editables[2].innerHTML = localStorage.getItem('content');
}
}
editBtn.addEventListener('click', function(e) {
if (!editables[0].isContentEditable) {
editables[0].contentEditable = 'true';
editables[1].contentEditable = 'true';
editables[2].contentEditable = 'true';
editBtn.innerHTML = 'Save Changes';
editBtn.style.backgroundColor = '#6F9';
} else {
// Disable Editing
editables[0].contentEditable = 'false';
editables[1].contentEditable = 'false';
editables[2].contentEditable = 'false';
// Change Button Text and Color
editBtn.innerHTML = 'Enable Editing';
editBtn.style.backgroundColor = '#F96';
// Save the data in localStorage
for (var i = 0; i < editables.length; i++) {
localStorage.setItem(editables[i].getAttribute('id'), editables[i].innerHTML);
}
}
});
</script>
</body>
</html>
You'll want to use something like the downloadInnerHtml function as described here. Ideally you'll probably also want to strip out the script tag and content editable attribute before exporting because you won't want the final html page to be editable

Categories

Resources