remove Highlighted Text SectionWise in Iframe - javascript

I am following this plugin https://github.com/mir3z/texthighlighter for text Highlighitng in IFrame. Upon Selection Text if i want to remove perticular section of the Selected{colored} text it is not happening. even though this plugin provides removing of highlighted text line by line ... but i need it differently as below
(function() {
var iframe = document.getElementById('iframeDiv'), colors = new ColorPicker(
document.querySelector('.color-picker')), hltr;
var i = 0;
highlights = 1;
iframe.onload = function() {
var hltr = new TextHighlighter(
iframe.contentDocument.body,
{
onAfterHighlight : function(range, highlights) {
i++;
var xColor = $('.selected').css(
'border-right-color');
highlights[highlights.length - 1].parentNode.innerHTML += '<div class="clored_div'+i+'" style="position: absolute;right: 13px;width: 40px;border-right: 14px solid '+xColor+';height: 40px;background:none;border-bottom: 14px solid transparent;border-top: 10px solid transparent;box-shadow: none;height: 0;margin: 0 auto 20px;width: 0;"><img id="removeHighLight" onClick="removeColor();"; title="<fmt:message key="colorRemove"/>" src="<fmt:message key="images"/>/close_rm.png" alt="Close" style="height: 15px;position: absolute;right: -21px;top: -23px;width: 15px;z-index: 9999;"/></div><div id=section' + i +'></div>'
function removeColor(){
$('.clored_div"'+i+'"').remove();
}
},
colors.onColorChange(function(color) {
hltr.setColor(color);
});
};
//for the src HTML please keep any HTML under same application and access like this
iframe.src = 'http://localhost:8080/html/example.htm';
})();
i want to call this function of this section of colored text in order to remove the color.
function removeColor(){$('.clored_div"'+i+'"').remove();}
anyOne help me out with this problem.. if you need more code or understanding for this problem please ask
Thank you so much in Advance.

parent.removeColor();
Iframe is having this function declared, but it is defined in mainPage.

Related

Invalid characters in HTML preventing my menu from toggling?

I'm creating a button that makes a table and a drop down menu. But the drop down menu doesn't work when it's clicked, like it should.
I keep receiving this error: 'Uncaught InvalidCharacterError: Failed to execute 'toggle' on 'DOMTokenList': The token provided ('[object HTMLCollection]') contains HTML space characters, which are not valid in tokens.' This error occurs near the last line here where I use toggle.
I've checked the HTML generated with JS and it seems fine. I just can't figure out what exactly this error is referring to. I've gone through the code at least a half dozen times and don't see any spaces within the html. This makes me question whether this is where the problem actually is. If anyone has a solution or insight into how to correct this, that would be much appreciated.
Here is the code:
//**HTML**
<div class = 'insertsGrid buttonStyle'>Grid</div>
//**CSS**
.buttonStyle{
width: 12vh;
height: 12vh;
border: 1px solid;
position: fixed;
display:flex;
justify-content:center;
align-items: center;
font-weight: 900;
font-size: 4vh;
color: #b8860b;
cursor:pointer;
background-color:white;
user-select: none;
}
th, td, tr {
border: 1px solid black;
}
//**Javascript**
const insertsGrid = document.getElementsByClassName('insertsGrid');
insertsGrid[0].addEventListener('mousedown', createGrid);
let z =0;
function createGrid (){
z++;
document.execCommand('insertHTML', true,/*this is the bar */'<div class=bar'+z.toString()+'></div>'+/*this is the menu options that show when bar is clicked */ '<div class =dropDownContent'+z.toString()+'><div class =dropDownContentX'+z.toString()+'><p>Add Row</p><p class=addColumn'+z.toString()+'>Add Column</p></div></div>'+/*this is the table */ '<table><tr><td>Head1</td><td>Head2</td></tr><tr><td></td><td></td></tr></table><br>');
let bar = document.getElementsByClassName('bar'+z.toString());
let dropDownContent = document.getElementsByClassName('dropDownContent'+z.toString());
let dropDownContentX = document.getElementsByClassName('dropDownContentX'+z.toString());
let addColumn = document.getElementsByClassName('addColumn'+z.toString());
//dom css for the html created in the dom
bar[0].style.width = '10%';
bar[0].style.height = '1%';
bar[0].style.border = '1px solid black';
bar[0].style.cursor = 'pointer';
bar[0].style.marginBottom = '50px';
dropDownContent[0].style.display = 'none';
dropDownContentX[0].style.display = 'inline';
dropDownContentX[0].style.backgroundColor = 'white';
dropDownContentX[0].style.width = '100%';
dropDownContentX[0].style.fontSize = '80%';
//action executed when the nav button is pressed
bar[0].addEventListener('mousedown' , tog);
function tog (){
dropDownContent[0].classList.toggle('dropDownContentX');
}
You are passing dropDownContentX into the toggle() method. This is a collection of DOM nodes, not a string. The toggle() method expects a CSS class name without spaces. You are passing the wrong data type to this method.
Source: https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList/toggle

How to sync printing of characters with sound?

I need to emulate what an old manual typewriter does when printing what is being typed on a web page. I want to develop JavaScript functions to pass it a string, and it would print out each character with a delay, and the sound file synced with each letter.
I'm new to JavaScript. What is the preferred method to do this? Should I be looking at jQuery for this? Or is this something simple to do?
I've seen problems with sound files being triggered like this on some web browsers, is there an audio file format which is best for this sort of thing?
I've found this, but the problem is, it doesn't work on all web browsers:
https://rawgit.com/mehaase/js-typewriter/master/example3-typewriter/index.html
You can try something like this:
// The delay between each keystroke
var delay = 300;
// The typewriter sound file url
var clickURL = "https://cdn.rawgit.com/halimb/res/6ffa798d/typewriter.wav";
// Get a reference to the container div
var container = document.getElementById("container");
var sampleString = "Hello world!";
//get a reference to the start button and typewrite onclick
var start = document.getElementById("btn");
start.onclick = function() { typewrite( sampleString ); };
function typewrite( str ) {
var i = 0;
container.innerHTML = "";
type();
function type() {
var click = new Audio( clickURL );
// This is triggered when the browser has enough of the file to play through
click.oncanplaythrough = function() {
click.play();
// Add the character to the container div
container.innerHTML += str[i];
i++;
if(i < str.length) {
window.setTimeout(type, delay);
}
}
}
}
* {
font-family: Courier;
font-size: 32px;
}
.btn {
display: inline-block;
border: 1px solid black;
border-radius: 5px;
padding: 10px;
cursor: pointer;
margin: 10px;
}
<div class="btn" id="btn">Start</div>
<div id="container"></div>
Update: on Safari. It seems the audio has to be triggered by a user event (e.g: onclick..), so I added a button, and made the typewriter start onclick.
The downside is that there's no way to pre-load the audio file, Safari make a server request and downloads the audio each time it is played. the only (dirty) way I could think of to overcome this is to provide a data URI instead of the audioURL.. you can try that if the playback speed really matters (this can be helpful: https://www.ibm.com/developerworks/library/wa-ioshtml5/)

Clone, Play and Replace the Cloned Dom - Javascript / Jquery

I'm trying to export the whole page as PDF. During certain situation's like, if the CSS is loaded from separate file is not applied in exported PDF. So I'm trying to convert all CSS as inline using this code.
(function ($) {
var rules = document.styleSheets;
for(var rl in rules){
var rule = rules[rl].cssRules;
try{
for (var idx = 0, len = rule.length; idx < len; idx++) {
$(rule[idx].selectorText).each(function (i, elem) {
if($(elem).is(":visible"))
elem.style.cssText += rule[idx].style.cssText;
});
}
}catch(e){
console.log(e);
}
}
})(jQuery);
After I ran this code, my exported PDF is working good. But my DOM is not as before. So is there anyway where I can clone my DOM before operations, and replace the cloned DOM as before after playing with DOM. Hope my question is clear. Thanks in anticipation for the help.
In this Snippet there are 2 much more simpler ways than modifying a stylesheet:
Isolate the <iframe>,<embed>, or <object> by wrapping an element around it then apply styles referencing the wrapper element. This is demonstrated in the Snippet with div.jframe as the wrapper.
Inject a <style> block with new rulesets.
If either one is done with moderate care, you shouldn't be left with conflicting styles.
Note: The PDF in the iframe is sandboxed, so it's not there but everything still applies.
SNIPPET
function injectStyles(rule) {
document.body.insertAdjacentHTML('afterbegin',
'­<style>' + rule + '</style>');
}
injectStyles('iframe:hover { border: 5px solid blue; }');
.jframe iframe {
outline: 10px solid tomato;
}
<div class='jframe'>
<iframe src='http://che.org.il/wp-content/uploads/2016/12/pdf-sample.pdf' height='400' width='400'></iframe>
</div>

Force browser to immediately repaint a dom element

I need to insert a huge html markup to some dom element which will take awhile. It is a reason why I want to display some preloader indicator. I have two blocks: #preloader and #container. Some code displays the preloader firstly and then starts to paste a big html markup.
The problem - preloader hasn't really displayed until browser will not finish render html markup. I've tried a lot of solutions (a lot of them are described here) but still haven't success.
An example is avalable below:
https://jsfiddle.net/f9f5atzu/
<div id='preloader'>Preloader...</div>
<div id='container'>Container...</div>
#preloader {
display: none;
background-color: #f00;
color: #fff;
hight: 100px;
text-align: center;
padding: 10px 20px;
}
#container {
background-color: #ccc;
}
setTimeout(function() {
// Define variables
let domPreloader = document.getElementById('preloader');
let domContainer = document.getElementById('container');
const html = Array(100000).fill("<div>1</div>");
// Display preloader
domPreloader.style.display = 'hide';
domPreloader.offsetHeight;
domPreloader.style.webkitTransform = 'scale(1)';
domPreloader.style.display = 'block';
// Render a big html
domContainer.innerHTML = html;
}, 1000);
Is there any solutions for the problem?
The way you did it, you're not releasing control to the browser between the display of the preloader and the display of the 'big html'.
Rather than encapsulating this whole block inside a setTimeout(), you should just differ the rendering part.
Please try something along those lines:
// Define variables
let domPreloader = document.getElementById('preloader');
let domContainer = document.getElementById('container');
// Display preloader
domPreloader.style.webkitTransform = 'scale(1)';
domPreloader.style.display = 'block';
// Render a big html
setTimeout(render, 100);
function render() {
const html = Array(100000).fill("<div>1</div>");
domContainer.innerHTML = html;
// Hide preloader
domPreloader.style.display = 'none';
}
JSFiddle

How to target "hidden" iframes? (application: links to starting positions of a "poster image hidden"-embedded Youtube video)

Meta: A similar question about locally stored A/V files can be found here: Clickable "positioning" hyperlinks to A/V (locally stored on your website and “hidden” behind a poster image).
Dear people from the Stackoverflow community,
The application
I am having an iframe <iframe name="video"... which is named video, and which is to be seen as the "main player" of a certain video.
Since I haven't been able to get interactive transcript on this video yet, I call different playing/starting positions in the video using: 1:00, e.g. for second 60.
This is working fine when the <iframe name="video".. is already "active": then the link shifts the video's playing position inside the iframe. This is great!
However it is not working fine, when the <iframe name="video".. isn't "active" yet, which is the case: then the link then opens in a different browser tab, instead of inside the iframe (or where the iframe is supposed to show up).
What I mean by hidden
What I mean with the iframe not being "active" is the following: it is "hidden" behind a "poster image" via the following code:
<div onclick="play();" id="vid" style="...; background: ... url('...poster.image.url...') no-repeat center;-webkit-background-size: cover; ...;overflow:hidden"></div>
<script type="text/javascript">function play(){document.getElementById('vid').innerHTML = '<iframe name="video" ... src="//www.youtube.com/embed/...?&...start=0"></iframe>';}</script>
In other words: i specifically don't want "<a target="_blank""-behaviour. I guess the target="video" is not working properly now, since the iframe is "hidden" behind the poster image.
I know for sure this behavior isn't occuring when the iframe wouldn't be hidden at all. I tested this multiple times. Further more, with the current "hidden" poster feature, this behavior is also not occuring when the poster image is clicked FIRST (before clicking on a <a href="...></a>).
If you would to see this behaviour for yourself, you can see it on my site. The best is to look/CTRL-F for "stef", and open the ▾̲ ̲u̲n̲d̲e̲r̲l̲i̲n̲e̲d̲ ̲t̲o̲g̲g̲l̲e̲, which you will find there.
So how to sucessfully "target" the "hidden" iframe without opening a new browser window/tab?
Any help would be greatly appreciated. Many thanks, Vincent Verheyen.
Well here we are! The fiddle.
HTML
Your html will contain both facades and jumpers to accomplish what you asked.
What's a facade?
facade: "the principal front of a building, that faces on to a street or open space."
This will be the image shown before you play the video or click on any jumpers, it's html will look like this:
<div class="videoFacade" data-name="video1" data-video="ByJFdTFEwF4" data-start="8">
<img src="http://i.imgur.com/xeUiWGn.png" />
</div>
What's a jumper?
A jumper is an anchor that will update the iframe's url to the desired time in the video, it will look like this:
JavaScript
window.addEventListener("load", initVideoFacade);
function initVideoFacade() {
var allFacades = document.querySelectorAll(".videoFacade");
for (var i = 0; i < allFacades.length; i++) {
var facade = allFacades[i];
setUpFacade(facade);
}
var allJumpers = document.querySelectorAll(".videoJumper");
for (var i = 0; i < allJumpers.length; i++) {
var jumper = allJumpers[i];
setUpJumper(jumper);
}
}
function setUpJumper(jumper) {
jumper.addEventListener("click", function (e) {
e.preventDefault();
jumpTo(jumper);
var video = jumper.dataset.video;
var facade = getFacadeByVideo(video);
if (facade) playVideo(facade);
return false;
});
}
function setUpFacade(facade) {
facade.addEventListener("click", function () {
playVideo(facade);
});
}
function getFacadeByVideo(video) {
return document.querySelector(".videoFacade[data-name=" + video + "]");
}
function getIframeByVideo(video) {
return document.querySelector(".videoIframe[data-name=" + video + "]");
}
function updateVideoSource(iframe, start, end) {
var iframeSrc = iframe.src.replace(/start=[0-9]+/i, "start=" + start);
var hasEnd = iframeSrc.indexOf("end") != -1;
if (hasEnd) iframeSrc = iframeSrc.replace(/end=[0-9]+/i, "end=" + end);
else iframeSrc += "&end=" + end;
return iframeSrc;
}
function updateFacadeData(facade, start, end) {
facade.setAttribute("data-start", start);
facade.setAttribute("data-end", end);
}
function jumpTo(jumper) {
var start = jumper.dataset.start;
var end = jumper.dataset.end;
var video = jumper.dataset.video;
var iframe = getIframeByVideo(video);
if (iframe) {
var iframeSrc = updateVideoSource(iframe, start, end);
iframe.src = iframeSrc;
} else {
var facade = getFacadeByVideo(video);
updateFacadeData(facade, start, end);
}
}
function playVideo(facade) {
var start = facade.dataset.start || 0;
var end = facade.dataset.end;
var name = facade.dataset.name;
var video = facade.dataset.video;
var iframe = document.createElement("iframe");
iframe.dataset.name = name;
iframe.className = "videoIframe";
var iframeSrc = "http://www.youtube.com/embed/" + video + "?&cc_load_policy=1&modestbranding=1&autoplay=1&rel=0&showinfo=0&theme=light&start=" + start;
if (end) iframeSrc += "&end=" + end;
iframe.src = iframeSrc;
iframe.frameBorder = 0;
replaceNode(facade, iframe);
}
function replaceNode(node1, node2) {
var parent = node1.parentNode;
var next = node1.nextSibling;
parent.insertBefore(node2, next);
parent.removeChild(node1);
}
Here is a timeline:
We add the initVideoFacade() method to the load event in the page, this will make sure all our facades and jumpers are up and running before doing anything.
The initVideoFacade() method will find all jumpers and facades and set them up using the setUpFacade() and setUpJumper() methods.
The setUpJumper() method will add a click event on the jumper and tell it to jump to a determined time in the video, specified in the jumper. Also, if the video is not yet playing, it will do so now.
The jumpTo() method will update the iframe's src (or the facade initial data if the video is not playing) using a couple of regular expressions to replace the &start= and &end= parts of the iframe src.
The setUpFacade() method will simply play the video, removing the facade and inserting the iframe.
The playVideo() method will create a new iframe from a facade, replacing it and assigning it's source, start and end time to the video.
CSS
This just handles the styling of the facade and iframe :)
.videoFacade, .videoIframe {
position: relative;
width: 360px;
height: 202.5px;
margin:5px;
}
.videoFacade {
cursor: pointer;
border:1px solid black;
}
.videoFacade img {
position: absolute;
width: 50px;
height: 50px;
left: 50%;
top: 50%;
margin: -25px 0 0 -25px;
}
Hope it helped!

Categories