Autosaving (localStorage) textfield from iFrame doesn't work - javascript

I am building a rich text editor and want to autosave the text in the iframe.
I have multiple code parts and snippets which – taken by itself – are working perfectly but I am failing to assemble them correctly. LIVEDEMO
Here is a graphic of what I want to achieve:
I have an editable iFrame which is my text editor. The innerHTML of this iFrame should be loaded into a textarea hidden under the iframe and the content of the textarea should be saved in the localStorage regularly.
The iFrame code works.
<script>
function iFrameOn() {
richTextField.document.designMode = 'On';
}
function iBold() {
richTextField.document.execCommand('bold', false, null);
}
function iUnderline() {
richTextField.document.execCommand('underline', false, null);
}
function iItalic() {
richTextField.document.execCommand('italic', false, null);
}
function iFontSize() {
var size = prompt('Enter a size 1-7', '')
richTextField.document.execCommand('FontSize', false, size);
}
function iForeColor() {
var color = prompt('Define a basic color or apply a hexadecimal color code for advanced colors:', '')
richTextField.document.execCommand('ForeColor', false, color);
}
function iHorizontalRule() {
richTextField.document.execCommand('InsertHorizontalRule', false, null);
}
function iUnorderedList() {
richTextField.document.execCommand('InsertUnorderedList', false, "newUL");
}
function iOrderedList() {
richTextField.document.execCommand('InsertOrderedList', false, "newOL");
}
function iLink() {
var linkURL = prompt('Enter the URL for this link:', 'http://')
richTextField.document.execCommand('CreateLink', false, linkURL);
}
function iUnLink() {
richTextField.document.execCommand('UnLink', false, null);
}
function iImage() {
var imgSrc = prompt('Enter image location:', '');
if(imgSrc != null){
richTextField.document.execCommand('insertimage', false, imgSrc);
}
}
</script>
<body onLoad="iFrameOn();">
<h2>Text Editor</h2>
<form action="my_parse_file.php" name="myform" id="myform" method="post" onLoad="autosave_form();">
<fieldset>
<p>Entry Title: <input name="title" id="title" type="text" size="80" maxlength="80" /></p>
<p>Entry Body:<br />
<div id="wysiwyg_cp" style="padding: 8px; width: 700px;">
<input type="button" onClick="iBold()" value="B" />
<input type="button" onClick="iUnderline()" value="U" />
<input type="button" onClick="iItalic()" value="I" />
<input type="button" onClick="iFontSize()" value="Text Size" />
<input type="button" onClick="iForeColor()" value="Text Color" />
<input type="button" onClick="iHorizontalRule()" value="HR" />
<input type="button" onClick="iUnorderedList()" value="UL" />
<input type="button" onClick="iOrderedList()" value="OL" />
<input type="button" onClick="iLink()" value="Link" />
<input type="button" onClick="iUnLink()" value="UnLink" />
<input type="button" onClick="iImage()" value="Image" />
</div>
<textarea style="display: none;" name="myTextArea" id="myTextArea" cols="100" rows="14"></textarea>
<iframe name="richTextField" id="richTextField" style="border: #000000 1px solid; width: 700px; height: 300px"></iframe>
</p><br />
<input name="myBtn" type="button" value="Submit Data" onClick="javascript:submit_form();"/>
</fieldset>
</form>
</body>
The autosaver also works – but only with the textarea and not the iFrame.
// get the state of the form
function getFormState() {
var fields = document.getElementsByTagName('form')[0].elements;
if (fields.length == 0){return};
for (var i = 1; i <= fields.length-1; i++) {
var name = fields[i].getAttribute('name');
if (name in localStorage && localStorage[name] !== null) {
fields[i].value = localStorage[name];
}
}
}
// save the state of the form
function saveFormState() {
var fields = document.getElementsByTagName('form')[0].elements;
if (fields.length == 0){return};
var populated = false;
for (var i = 1; i <= fields.length-1; i++) {
var name = fields[i].getAttribute('name');
if (fields[i].value != '' && fields[i].getAttribute('type') != 'submit') {
localStorage[name] = fields[i].value;
populated = true;
}
}
// display the time form data was saved (optional)
if (populated) {
var date = new Date();
var hours = date.getHours();
var mins = date.getMinutes();
var secs = date.getSeconds();
hours = (hours < 10) ? '0' + hours : hours;
mins = (mins < 10) ? '0' + mins : mins;
secs = (secs < 10) ? '0' + secs : secs;
var msg = '[Form data was saved at ' + hours + ':' + mins + ':' + secs + ']';
var timecont = document.getElementById('time_container');
if (timecont !== null) {
timecont.innerHTML = msg;
}
else {
timecont = document.createElement('span');
timecont.setAttribute('id', 'time_container');
timecont.appendChild(document.createTextNode(msg));
document.getElementsByTagName('fieldset')[0].appendChild(timecont);
}
}
}
// run the above functions when the web page is loaded
window.onload = function () {
// check if HTML5 localStorage is supported by the browser
if ('localStorage' in window && window['localStorage'] !== null) {
// get the form state
getFormState();
// save the state of the form each 15 seconds (customizable)
setInterval('saveFormState()', 15 * 1000);
}
}
And now I need some binding code which loads the innerHTML of the iFrame routinely into the textarea.
function autosave_form() {
var theForm = document.getElementbyID('myform');
theForm.elements["myTextArea"].value = window.frames['richTextField'].document.body.innerHTML;
setTimeout(yourFunction, 5000);
}
So where are my fellacies? Or what did I overlook? Please help.
LIVEDEMO

You're not using the interface on the iframe object correctly. To get the content of an iframe on the same domain, you need to go through the contentWindow field. For example:
function read_iframe() {
return window.frames['richTextField'].contentWindow.document.body.innerHTML;
}
Remember that you cannot read the content of an iframe on another domain.
You can find complete docs on the HTMLIFrameElement's methods and fields at https://developer.mozilla.org/en/docs/Web/API/HTMLIFrameElement

Edited!
It seems like iframe is the common way of creating html editors.
I am sure that the explanations here will assist you.
~~~
I am not sure you can access the iframe's innerHTML since it would be cross-site scripting, which is prohibited for security reasons. Access the iframe content using javascript might result in access denied errors.

Related

Implement shopping cart JavaScript

here what I am trying to do is when a user clicks the + button function should get called, it looks for the cookie shopping_cart. Then it tries to find the JSON with key 'item_qty', which is key-value pair of all the items in the cart. But the cart is not updating, moreover when clicked on + button is showing Unexpected token N in JSON at position 0
In browser console I am getting it as
"csrftoken=some_value; shopping_cart=None"
var updateCart = function (count) {
$('#cart-info').val($('#cart-info').val() + count);
};
var item_add = function (item_slug) {
var shopping_cart = JSON.parse($.cookie("shopping_cart"));
var item_slug = item_slug;
if(shopping_cart.hasOwnProperty('item_qty')){
item_qty_dict = shopping_cart['item_qty'];
if(item_qty_dict.hasOwnProperty(item_slug)){
var count_pre = item_qty_dict[item_slug];
item_qty_dict[item_slug] = count_pre + 1;
}
else {
item_qty_dict[item_slug] = 1;
shopping_cart['item_qty'] = item_qty_dict;
}
}
else {
shopping_cart = {}
shopping_cart['item_qty'] = {item_slug: 1};
}
$.cookie("shopping_cart", JSON.stringify(shopping_cart));
var temp= $.cookie('shopping_cart')
console.log(JSON.parse(temp));
};
var buttonPlus = $(".cart-qty-plus");
var incrementPlus = buttonPlus.click(function () {
var $n = $(this)
.parent(".qnty_chngr")
.find(".qty");
$n.val(Number($n.val()) + 1);
var product_slug = $(this).parent(".qnty_chngr").siblings('.product-slug').val();
console.log(product_slug);
updateCart(1);
item_add(product_slug);
});
HTML:
<div class="qnty_chngr">
<button class="cart-qty-plus" type="button" value="+">+</button>
<input type="text" name="qty" maxlength="12" value="1" class="input-text qty"/>
<button class="cart-qty-minus" type="button" value="-" title="Add less quantity">-</button>
</div>
<input type="hidden" class="product-slug" name="product_slug" value="{{ medicine.slug }}">
<div class="add_to_cart">
<button class="add_to_cart_txt" value="10"><span class="AddInfoBtn">Add </span></button>
</div>,
Seems in your cookie there is no valid JSON. None is not valid, it should be "None" (with quotes). Remove the cookie before testing.
Also if possible try using this library which works the way you expected.
https://github.com/js-cookie/js-cookie

Fill textbox from url query and call function

<input type="text" id="tnum" maxlength="50" placeholder="Enter Your Tracking ID" />
<input class="btn" type="button" value="TRACK" onclick="doTrack()" />
<div id="YQContainer"></div>
So basically, I have a page that can track packages for my customers. I want to be able to send them a link in their email that will automatically track their package from the link. ( they don't have to type in their tracking id and click track when they go to my tracking page )
example.com/track?tnum=3298439857
This is what i'm using to track packages.
https://www.17track.net/en/externalcall/single
The basic idea is as follows:
Wait for page to load
Parse the URL and extract needed query parameter
Set the value of the form element
Call the doTrack() function
// Handy function to parse the URL and get a map of the query parameters
function parseQueryParameters(url) {
var qp = {};
if (!url) {
return qp;
}
var queryString = url.split('?')[1];
if (!queryString) {
return qp;
}
return queryString.split('&')
.reduce(function(m, d) {
var splits = d.split('=');
var key = splits[0];
var value = splits[1];
if (key && value) {
m[key] = value;
}
return m;
}, qp);
}
//Wait for page to load
window.onload = function() {
//Extract tnum query parameter
var qp = parseQueryParameters(window.location.href);
//If no parameter is provided, do nothing
if (!qp.tnum) return;
//Set the value of the form element
document.getElementById("tnum").value = qp.tnum;
// Call doTrack
doTrack();
}
//Temporary doTrack function - remove when integrating ;)
function doTrack() {
console.log(document.getElementById("tnum").value)
}
<input type="text" id="tnum" maxlength="50" placeholder="Enter Your Tracking ID" />
<input class="btn" type="button" value="TRACK" onclick="doTrack()" />
<div id="YQContainer"></div>
<html>
<head>
<script>
function setURL(){
var dt_value = document.getElementById("tnum").value;
//just test here ..what is coming..
alert(dt_value );
var sjdurl = "example.com/track?tnum="+dt_value;
popup = window.open(sjdurl,"popup"," menubar =0,toolbar =0,location=0, height=900, width=1000");
popup.window.moveTo(950,150);
}
</script>
</head>
<body>
<input type="Text" id="tnum" maxlength="25" size="25"/>
<input type='button' onclick='setURL()' value='SUBMIT'>
</body>
</html>
function doTrack(tnum) {
var trackNumber = tnum;
window.open("example.com/track?tnum="+trackNumber);
}
$(".btn").on('click',function(e) {
e.preventDefault();
var tnum = $('#tnum').val();
if (tnum!="") {
doTrack(tnum);
} else {
return false;
}
});

Separating HTML and JS

I am trying to separate some JS code that is embedded in to a HTML file. I do not own this code, it is for a remote support landing page but I'm not sure how to separate them out.
I have tried copying the JS code in to a different .js file and then adding the script tags to link but no luck.
<script type="text/javascript" src="https://www.islonline.net/webapi/api.js?
libs=join"></script>
<div class="isl-connect-form">
<form id="isl-connect-form" action="#" method="get" onsubmit="return
isl_connect();">
<fieldset>
<legend>Enter your session code and click Connect</legend>
<div>
<label for="isl-code-field">Session code</label>
<input type="text" name="code" id="isl-code-field" value="" />
</div>
<input type="submit" name="submit" value="Connect" />
</fieldset>
</form>
<div id="isl-feedback"></div>
</div>
<script type="text/javascript">
function isl_connect() {
var doc = document,
f = doc.getElementById('isl-connect-form'),
r = doc.getElementById('isl-feedback'),
is_msie = navigator.userAgent.indexOf('MSIE') >= 0,
b = null;
ISLOnline.Join.getSessionInfoByCode(
f.code.value,
function (info) {
r.className = 'isl-success';
r.innerHTML = 'Connecting to session ' +
info.getAttribute('sessionCode');
if (is_msie) {
r.innerHTML += ', please click the button below:<br />';
r.appendChild(doc.createElement('br'));
var b = doc.createElement('input');
b.type = 'button';
b.name = 'join';
b.value = 'Start';
b.onclick = function () {
info.join();
};
r.appendChild(b);
} else {
info.join();
}
},
function (error) {
r.className = 'isl-error';
r.innerHTML = 'Invalid session code!';
/* comment the line above and uncomment the line below if you
wish to
display the error that is sent by the server */
//r.innerHTML += error.getDescription();
}
);
return false;
}
Create a new JS file and put the original full javascript within it then load it after the islonline.net API call. I have shown an example.
<script type="text/javascript" src="https://www.islonline.net/webapi/api.js?libs=join"></script>
<div class="isl-connect-form">
<form id="isl-connect-form">
<fieldset>
<legend>Enter your session code and click Connect</legend>
<div>
<label for="isl-code-field">Session code</label>
<input type="text" name="code" id="isl-code-field" value="" />
</div>
<input type="submit" name="submit" value="Connect" />
</fieldset>
</form>
<div id="isl-feedback"></div>
</div>
<!-- your new external JS file -->
<script type="text/javascript" src="https://www.example.com/path/to/your/file.js"></script>
Your new Javascript file will contain the original JS code, with a slight modification to help separate HTML and JavaScript by using addEventListener instead of onsubmit:
document.getElementById('isl-connect-form').addEventListener('submit', function isl_connect(event) {
if (typeof event.preventDefault == 'function') event.preventDefault();
var doc = document,
f = this,
r = doc.getElementById('isl-feedback'),
is_msie = navigator.userAgent.indexOf('MSIE') >= 0,
b = null;
ISLOnline.Join.getSessionInfoByCode(
f.code.value,
function (info) {
r.className = 'isl-success';
r.innerHTML = 'Connecting to session ' +
info.getAttribute('sessionCode');
if (is_msie) {
r.innerHTML += ', please click the button below:<br />';
r.appendChild(doc.createElement('br'));
var b = doc.createElement('input');
b.type = 'button';
b.name = 'join';
b.value = 'Start';
b.onclick = function () {
info.join();
};
r.appendChild(b);
} else {
info.join();
}
},
function (error) {
r.className = 'isl-error';
r.innerHTML = 'Invalid session code!';
/* comment the line above and uncomment the line below if you wish to
* display the error that is sent by the server
*/
//r.innerHTML += error.getDescription();
}
);
return false;
});

Trying to create a form with 2 "quantity" selectors using html, javascript

I am trying to create a quantity selector like what you would find in a grocery store website or in most e-commerce sites. (One with +1 and -1 buttons) I can make the first selector work but can't seem to get the second one to.
Here's the code and HTML I have so far:
function addNum1() {
var newValue = Number(ordernow.firstvalue.value);
newValue +=1;
ordernow.firstvalue.value = newValue;
}
function minusNum1() {
var subNum = Number(ordernow.firstvalue.value);
if (subNum > 0) {
subNum -= 1;
ordernow.firstvalue.value = subNum;
}
}
function addNum2() {
var newValue = Number(ordernow.firstvalue2.value);
newValue2 +=1;
ordernow.firstvalue2.value = newValue2;
}
function minusNum2() {
var subNum2 = Number(ordernow.firstvalue2.value);
if (subNum2 > 0) {
subNum2 -= 1;
ordernow.firstvalue2.value = subNum2;
}
};
<body>
<div class=container>
<form name="orderup" id="ordernow">
<p> Chicken &nbsp &nbsp $4.57</p>
Quantity<input type="button" id="firstminus" value="- 1" onclick="minusNum1()"/>
<input type="text" id="firstvalue" value="0"/>
<input type="button" id="firstadd" value="+1" onclick="addNum1()"/>
<p> Beef &nbsp &nbsp $3.32</p>
Quantity<input type="button" id="firstminus2" value="- 1" onclick="minusNum2()"/>
<input type="text" id="firstvalue2" value="0"/>
<input type="button" id="firstadd2" value="+1" onclick="addNum2()"/>
</form>
</div>
</body>
If you open your browser's development tools the console should show an error message. On Chrome I get:
Uncaught ReferenceError: newValue2 is not defined
This is because addNum2() declares newValue but then uses newValue2 on the next line.
function addNum2() {
var newValue = Number(ordernow.firstvalue2.value);
newValue2 +=1;
ordernow.firstvalue2.value = newValue2;
}
var newValue = Number(ordernow.firstvalue2.value);
newValue2 +=1;
You can use the same var name because you are in a different function scope.
Fix:
function addNum2() {
var newValue = Number(ordernow.firstvalue2.value);
newValue +=1;
ordernow.firstvalue2.value = newValue;
}
Always check for error messages in the console and run your javascript in the debugger when something is "mysteriously" not working.

SetInterval in for Loop executing only last time

I have a little problem with SetInterval in javascript. I have a component which load content from url to div. The problem lies in the undefined number of these components.
Each have individual url and reload time.
and the PROBLEM is that my setinterval will execute only the last of components in the for loop.
I NEED to each component reloading on it self. :
component n1 = reload time 5s
component n2= reload time 60sec.
$(document).ready(function() {
var pocet = $('[id^=komponenta]').length;
var i;
for (i = 0, text = ""; i < pocet; i++) {
var nazev = 'komponenta' + i;
var cil = 'target' + i;
var adresa = document.getElementById(nazev).adresa.value;
var cas = document.getElementById(nazev).reload.value;
setInterval(function() {
$('#' + cil).load(adresa);
}, cas);
}
});
<div id="target0"></div>
<div id="target1"></div>
<div id="target2"></div>
<form class="pure-form pure-form-stacked" method="POST" id="komponenta0">
<fieldset>
<label for="email">Komponenta:</label>
<label for="remember" class="pure-checkbox">
</label>
<input type="hidden" name="adresa" id="adresa" type="text" placeholder="Vložte prosím URL" value="text.html">
<input type="hidden" name="reload" value="10000">
</fieldset>
</form>
<form class="pure-form pure-form-stacked" method="POST" id="komponenta1">
<fieldset>
<label for="email">Komponenta:</label>
<label for="remember" class="pure-checkbox">
</label>
<input type="hidden" name="adresa" id="adresa" type="text" placeholder="Vložte prosím URL" value="text2.html">
<input type="hidden" name="reload" value="2000">
</fieldset>
</form>
try this
(function(CIL, ADRESA, CAS) {
setInterval(function() {
$('#' + CIL).load(ADRESA);
}, CAS);
}(cil, adresa, cas));
i,e, wrap your setInterval as above
this is also valid, but may be a little less obvious
(function(cil, adresa, cas) {
setInterval(function() {
$('#' + cil).load(adresa);
}, cas);
}(cil, adresa, cas));
P.S. as #fuyushimoya stated - it's a scope issue
As others have mentioned, it's a scope issue - your setInterval-ed function is called not when the loop is iterating, but after it's through, and only the latest vars are available.
Try this jsFiddle - I replaced your 'load()' with a logging function.
$(document).ready(function () {
log('loaded');
var pocet = $('[id^=komponenta]').length;
var i;
for (i = 0, text = ""; i < pocet; i++) {
log(i);
(function (j) {
var nazev = 'komponenta' + j;
var cil = 'target' + j;
var adresa = document.getElementById(nazev).adresa.value;
var cas = document.getElementById(nazev).reload.value;
setInterval(function () {
log(nazev);
}, cas);
}(i));
}
});
function log(msg) {
$('.log').append(msg + '<br/>');
}

Categories

Resources