How to invoke IIFE function from external file in useEffect? - javascript

I was able to run scoper.js function by using script tag <script src="...">. Now I took that scoper.js function out of src and placed them in different file then try to invoke that function in App.js by importing it. But I'm having no luck. I tried window.onload and even setTimeout, but nothing works. My only guess is scoper.js is called immediately by IIFE so needs to be invoked differently if not invoking it by script tag? Please help.(If called successfully, "Hello World" should be in red color.)https://codesandbox.io/s/stylesheet-scoping-b0k9pp?file=/src/App.js
App.js
import React, { useEffect } from "react";
import "./styles.css";
import { scoper } from "./scoper.js";
export default function App() {
useEffect(() => {
const script = document.createElement("script");
script.src =
"https://cdn.rawgit.com/thomaspark/scoper/5de04619/scoper.min.js";
script.async = true;
// document.body.appendChild(script); // this method works
window.onload = function () {
scoper(); // this not working
};
let style = document.createElement("style");
style.setAttribute("scoped", "");
style.innerHTML =
".Puma {" +
"color: purple;" +
"font-size: 50px;" +
"text-align: left;" +
"}";
let main = document.getElementById("raptors");
main.appendChild(style);
}, []);
return (
<>
<div id="lakers" className="Puma">
<div>Hello World!</div>
</div>
<div id="raptors" className="Puma">
<h1>Raptors win!</h1>
</div>
</>
);
}
scoper.js
function scoperInit() {
var style = document.createElement("style");
style.appendChild(document.createTextNode(""));
document.head.appendChild(style);
style.sheet.insertRule("body { visibility: hidden; }", 0);
}
function scoper(css, prefix) {
console.log("css is ", css);
console.log("prefix is ", prefix);
var re = new RegExp("([^\r\n,{}]+)(,(?=[^}]*{)|s*{)", "g");
css = css.replace(re, function (g0, g1, g2) {
if (
g1.match(/^\s*(#media|#.*keyframes|to|from|#font-face|1?[0-9]?[0-9])/)
) {
return g1 + g2;
}
if (g1.match(/:scope/)) {
g1 = g1.replace(/([^\s]*):scope/, function (h0, h1) {
if (h1 === "") {
return "> *";
} else {
return "> " + h1;
}
});
}
g1 = g1.replace(/^(\s*)/, "$1" + prefix + " ");
return g1 + g2;
});
return css;
}
function scoperProcess() {
var styles = document.body.querySelectorAll("style[scoped]");
if (styles.length === 0) {
document.getElementsByTagName("body")[0].style.visibility = "visible";
return;
}
var head = document.head || document.getElementsByTagName("head")[0];
for (var i = 0; i < styles.length; i++) {
var style = styles[i];
var css = style.innerHTML;
if (css && style.parentElement.nodeName !== "BODY") {
var id = "scoper-" + i;
var prefix = "#" + id;
var wrapper = document.createElement("span");
wrapper.id = id;
var parent = style.parentNode;
var grandparent = parent.parentNode;
grandparent.replaceChild(wrapper, parent);
wrapper.appendChild(parent);
style.parentNode.removeChild(style);
var newstyle = document.createElement("style");
newstyle.setAttribute("data-scoped-style-for", id);
var csses = scoper(css, prefix);
if (newstyle.styleSheet) {
newstyle.styleSheet.cssText = csses;
} else {
newstyle.appendChild(document.createTextNode(csses));
}
head.appendChild(newstyle);
}
}
document.getElementsByTagName("body")[0].style.visibility = "visible";
}
function scoperReset() {
var styles = document.head.querySelectorAll("style[data-scoped-style-for]");
for (var i = 0; i < styles.length; i++) {
var style = styles[i];
var wrapperElementId = style.getAttribute("data-scoped-style-for");
var wrapperEl = document.getElementById(wrapperElementId);
if (wrapperEl) {
// Node may have disappeared, in that case nothing should happen
var css = style.innerHTML;
var resettedCss = css.replace("#" + wrapperElementId + " ", "");
var parent = wrapperEl.parentNode;
var targetEl = wrapperEl.childNodes[0];
parent.replaceChild(targetEl, wrapperEl);
var scopedStyle = document.createElement("style");
scopedStyle.setAttribute("scoped", "true");
if (scopedStyle.styleSheet) {
scopedStyle.styleSheet.cssText = resettedCss;
} else {
scopedStyle.appendChild(document.createTextNode(resettedCss));
}
targetEl.appendChild(scopedStyle);
}
style.parentNode.removeChild(style);
}
}
function scoperRestart() {
scoperReset();
scoperProcess();
}
(function () {
"use strict";
if (
typeof document === "undefined" ||
"scoped" in document.createElement("style")
) {
return;
}
scoperInit();
if (document.readyState === "complete" || document.readyState === "loaded") {
scoperProcess();
} else {
document.addEventListener("DOMContentLoaded", scoperProcess);
}
})();
if (typeof exports !== "undefined") {
exports.scoper = scoper;
}

Related

Browser shows < and > instead of <>

I'm creating a very simple HTML page using the Typewriter JavaScript plugin.
The page essentially should type out the code of an elementary Java program in which each declared variable is one of my contact details.
The problem is that if I write <span class="standard-highlight">List<String> list = Arrays</span>, the browser doesn't display List<String> list = but instead displays List<String> list =.
How can I fix this?
Here is a snippet from the output in the browser (Chrome)
JavaScript below:
function setupTypewriter(t) {
var HTML = t.innerHTML;
t.innerHTML = "";
var cursorPosition = 0,
tag = "",
writingTag = false,
tagOpen = false,
typeSpeed = 10,
tempTypeSpeed = 0;
var type = function() {
if (writingTag === true) {
tag += HTML[cursorPosition];
}
if (HTML[cursorPosition] === "<") {
tempTypeSpeed = 0;
if (tagOpen) {
tagOpen = false;
writingTag = true;
} else {
tag = "";
tagOpen = true;
writingTag = true;
tag += HTML[cursorPosition];
}
}
if (!writingTag && tagOpen) {
tag.innerHTML += HTML[cursorPosition];
}
if (!writingTag && !tagOpen) {
if (HTML[cursorPosition] === " ") {
tempTypeSpeed = 0;
}
else {
tempTypeSpeed = (Math.random() * typeSpeed) + 30;
}
t.innerHTML += HTML[cursorPosition];
}
if (writingTag === true && HTML[cursorPosition] === ">") {
tempTypeSpeed = (Math.random() * typeSpeed) + 30;
writingTag = false;
if (tagOpen) {
var newSpan = document.createElement("span");
t.appendChild(newSpan);
newSpan.innerHTML = tag;
tag = newSpan.firstChild;
}
}
cursorPosition += 1;
if (cursorPosition < HTML.length - 1) {
setTimeout(type, tempTypeSpeed);
}
};
return {
type: type
};
}
var typer = document.getElementById('typewriter');
typewriter = setupTypewriter(typewriter);
typewriter.type();
The below code works fine for me.
<span class="standard-highight" id="app"></span>
<script>
var app = document.getElementById('app');
var typewriter = new Typewriter(app, {
loop: true
});
typewriter.typeString('<span>List<String> list = Arrays</span>').start();
</script>
Place the string passing to the typeString() function within any html tag and only then the HTML symbols will be rendered by the function.

Can't appendChild to parent

I have div where i want to insert rendered content as a child. This is <div class="top-news-bar"></div>. And i have module for that
var fullNewsService = (function () {
var TEMPLATE_FULL;
var TOP_NEWS_CONTAINER;
function init() {
TEMPLATE_FULL = document.getElementById('template-full-news');
TOP_NEWS_CONTAINER = document.querySelector('.top-news-bar');
TOP_NEWS_CONTAINER.addEventListener('click', handleShowClick);
}
function handleShowClick(event) {
var target = event.target;
if (target.type != 'button')return;
while (!target.hasAttribute('data-id')) {
target = target.parentNode;
}
var id = target.getAttribute('data-id');
var templ = renderFullNews(id);
TOP_NEWS_CONTAINER.appendChild(templ);
}
function renderFullNews(id) {
var article = articlesService.getArticle(id);
var template = TEMPLATE_FULL;
template.content.querySelector('.top-image-full').style.backgroundImage = "url(" + article.picture + ")";
template.content.querySelector('.full-left').innerHTML = article.author;
var description = template.getElementsByClassName('full-right');
template.content.querySelector('.title-full').innerHTML = "<h5>" + article.title + "</h5>";
template.content.querySelector('.content-full').textContent = article.summary;
return template.content.querySelector('.full-news-wrapper').cloneNode(true);
}
return {
init: init,
}
}());
document.addEventListener('DOMContentLoaded', startApp);
function startApp() {
fullNewsService.init();
}
And when i click on button i get id correctly and template genereated successfully.But nothing happens,no erros and no appending.My html http://pastebin.com/jHxH6zPa

auto scrolling to find in page hilighted word

I have put this script on my every html page:
with this css:
strong.searchword {
background-color: #e8d850;
font-weight:normal;
}
My highlight.js code is:
function DocSearch() {
this.highlightWord = function(node,word) {
// Iterate into this nodes childNodes
if (node.hasChildNodes) {
var hi_cn;
for (hi_cn=0;hi_cn<node.childNodes.length;hi_cn++) {
this.highlightWord(node.childNodes[hi_cn],word);
}
}
// And do this node itself
if (node.nodeType == 3) { // text node
tempNodeVal = node.nodeValue.toLowerCase();
tempWordVal = word.toLowerCase();
if (tempNodeVal.indexOf(tempWordVal) != -1) {
pn = node.parentNode;
// check if we're inside a "nosearchhi" zone
checkn = pn;
while (checkn.nodeType != 9 &&
checkn.nodeName.toLowerCase() != 'body') {
// 9 = top of doc
if (checkn.className.match(/\bnosearchhi\b/)) { return; }
checkn = checkn.parentNode;
}
if (pn.className != "searchword") {
// word has not already been highlighted!
nv = node.nodeValue;
ni = tempNodeVal.indexOf(tempWordVal);
// Create a load of replacement nodes
before = document.createTextNode(nv.substr(0,ni));
docWordVal = nv.substr(ni,word.length);
after = document.createTextNode(nv.substr(ni+word.length));
hiwordtext = document.createTextNode(docWordVal);
hiword = document.createElement("strong");
hiword.className = "searchword";
hiword.appendChild(hiwordtext);
pn.insertBefore(before,node);
pn.insertBefore(hiword,node);
pn.insertBefore(after,node);
pn.removeChild(node);
}
}
}
}
}
var DOMContentLoaded = false;
function addContentLoadListener (func) {
if (document.addEventListener) {
var DOMContentLoadFunction = function () {
window.DOMContentLoaded = true;
func();
};
document.addEventListener("DOMContentLoaded", DOMContentLoadFunction, false);
}
var oldfunc = (window.onload || new Function());
window.onload = function () {
if (!window.DOMContentLoaded) {
oldfunc();
func();
}
};
}
addContentLoadListener( function() {
var q = window.location.search.substring(1).split('&');
if(!q.length)
return false;
var docSearch = new DocSearch();
var bodyEl = document.body;
for(var i=0; i<q.length; i++){
var vars = q[i].split('=');
new DocSearch().highlightWord(bodyEl,decodeURIComponent(vars[1]));
}
});
/*
window.onload = function() {
var q = window.location.search.substring(1).split('&');
if(!q.length)
return false;
var docSearch = new DocSearch();
var bodyEl = document.body;
for(var i=0; i<q.length; i++){
var vars = q[i].split('=');
new DocSearch().highlightWord(bodyEl,decodeURIComponent(vars[1]));
}
}
With this url mypage.html?suchwort=rose
I got word rose highlighted.
What I am having trouble with is then automatically scrolling to the highlighted word.
Is there any way to do this with javascript/jQuery?

Cannot read property `attachEvent` of null

I have a JavaScript file using speechSynthesis.
I keep having this error:
"Cannot read property 'attachEvent' of null" in line 129:
Here it is:
speech.bind = function(event, element, callback) {
**if (element.attachEvent) {**
element.attachEvent('on'+event, callback )
} else if (window.addEventListener) {
element.addEventListener(event, callback ,false);
};
};
I will put in here the role code in here so anyone can check the entire JavaScript:
var speech_def = speech_def || {
container: "#glb-materia"
,insert_before: true
,ico: "http://edg-1-1242075393.us-east-1.elb.amazonaws.com/speech/listen_icon.jpg"
,bt_txt: "OUÇA A REPORTAGEM"
,bt_stop: "PARAR!"
,source: ".materia-conteudo"
,ignore: [
".foto-legenda"
,".frase-materia"
,"script"
,"style"
,"#speech"
,".sub-header"
,".chamada-materia"
,".data-autor"
,".box-tags"
,".saibamais"
]
};
var speech = speech || {};
//Polyfill remove()
Element.prototype.remove = function() {
this.parentElement.removeChild(this);
};
NodeList.prototype.remove = HTMLCollection.prototype.remove = function() {
for (var i = 0, len = this.length; i < len; i++) {
if(this[i] && this[i].parentElement) {
this[i].parentElement.removeChild(this[i]);
}
}
};
//Polyfill innerText
if ( (!('innerText' in document.createElement('a'))) && ('getSelection' in window) ) {
HTMLElement.prototype.__defineGetter__("innerText", function() {
var selection = window.getSelection(),
ranges = [],
str;
for (var i = 0; i < selection.rangeCount; i++) {
ranges[i] = selection.getRangeAt(i);
}
selection.removeAllRanges();
selection.selectAllChildren(this);
str = selection.toString();
selection.removeAllRanges();
for (var i = 0; i < ranges.length; i++) {
selection.addRange(ranges[i]);
}
return str;
})
}
speech.iOS = /(iPad|iPhone|iPod)/g.test( navigator.userAgent );
speech.Android = /(Android)/g.test( navigator.userAgent );
speech.include = function() {
var bt = ""
bt += '<div id="speech" '
+'title="'+speech_def.bt_txt+'" '
+'style="'
+'display: none; '
+'margin: 5px; '
+'font-size: 12px; '
+'font-style: italic; '
+'color: #bbbbbb; '
+'cursor: pointer;"'
+'>';
bt += '<img style="width: 25px; height: 25px;" src="'+speech_def.ico+'"> ';
bt += '<i style="vertical-align: top; line-height: 28px;">'+speech_def.bt_txt+'</i>';
bt += '</div>';
var button = document.createElement("SPAN");
button.innerHTML = bt;
var box = document.querySelectorAll(speech_def.container)[0];
if (speech_def.insert_before) {
box.insertBefore(button,box.firstChild);
} else {
box.appendChild(button)
};
};
speech.stop = function() {
window.speechSynthesis.cancel();
}
speech.stop();
speech.content = function() {
var result = "";
var boxes = speech_def.source.split(",");
boxes.reverse();
for (var n = boxes.length - 1; n >= 0; n--) {
var doc = document.querySelector(boxes[n]);
if (doc) {
doc = doc.cloneNode(true);
for (var i = speech_def.ignore.length - 1; i >= 0; i--) {
var els = doc.querySelectorAll(speech_def.ignore[i]);
for (var j = els.length - 1; j >= 0; j--) {
els[j].remove();
};
};
result += "." + doc.innerText;
};
};
return result;
};
speech.start_speech = function() {
var content = speech.content();
// Note: some voices don't support altering params
if (!speech.Android) speech.msg.voice = speech.voices[0];
// msg.voiceURI = 'native';
speech.msg.volume = speech.iOS?1:1; // 0 to 1
speech.msg.rate = speech.iOS?0.6:1; // 0.1 to 10
speech.msg.pitch = speech.iOS?1:1; // 0 to 2
speech.msg.text = content;
speech.msg.lang = 'pt-BR';
speech.msg.onend = function(e) {
// console.log('Finished in ' + event.elapsedTime + ' seconds.');
};
window.speechSynthesis.speak(speech.msg);
};
speech.read = function(){}; //chrome problem
speech.bind = function(event, element, callback) {
if (element.attachEvent) {
element.attachEvent('on'+event, callback )
} else if (window.addEventListener) {
element.addEventListener(event, callback ,false);
};
};
speech.click = function(e){
event.stopPropagation()
if (window.event) window.event.cancelBubble = true;
var control = document.getElementById("speech");
var label;
if (window.speechSynthesis.speaking) {
label = speech_def.bt_txt;
speech.stop();
} else {
label = speech_def.bt_stop;
speech.start_speech();
};
control.querySelector("i").innerHTML = label;
}
speech.bind_button = function() {
var control = document.getElementById("speech");
speech.bind("click",control,speech.click);
};
speech.show_button = function() {
if (!speech.on_page) {
speech.on_page = true;
speech.include();
speech.bind_button();
};
var control = document.getElementById("speech");
control.style.display="inline-block";
};
speech.test_portuguese = function() {
speech.voices = [];
window.speechSynthesis.getVoices().forEach(function(voice) {
if (voice.lang == "pt-BR") {
speech.voices.push(voice);
};
});
if (speech.Android) {
var control = document.getElementById("speech");
var complement = (speech.voices.length > 0)?"*":"";
// control.querySelector("i").innerHTML = "OUÇA A REPORTAGEM"+complement;
return true;
} else {
return (speech.voices.length > 0);
};
};
speech.start = function() {
if ('speechSynthesis' in window) {
speech.msg = new SpeechSynthesisUtterance();
if (speech.test_portuguese()) {
speech.show_button();
} else {
window.speechSynthesis.onvoiceschanged = function() {
if (speech.test_portuguese()) {
speech.show_button();
};
};
};
speech.bind_button();
};
};
speech.start();
speech.bind("load",window,speech.start)
How can i solve this problem?
Thanks so much.
The problem is that element is null at that point.
Probably, because there is no element with id="speech", so control in null in this code:
speech.bind_button = function() {
var control = document.getElementById("speech");
speech.bind("click",control,speech.click);
};

Can this jQuery be done in vanilla JS?

I've got this working on mobile devices, but because of the 32kb gzip-ed of jQuery I wonder if it's possible to create this code
$(document).ready(function() {
$('body').addClass('js');
var $menu = $('#menu'),
$menulink = $('.menu-link'),
$wrap = $('#wrap');
$menulink.click(function() {
$menulink.toggleClass('active');
$wrap.toggleClass('active');
return false;
});
});
can be written in no library dependany vanilla JavaScript.
Can it be done? Where would I start?
JQuery uses javascript/DOMscripting to create its framework. Everything JQuery does, can be done in basic scripting. For example $('body').addClass('js') can be written as:
document.querySelector('body').className += ' js';
And $menulink.toggleClass('active'); as something like
var current = $menulink.className.split(/\s+/)
,toggleClass = 'active'
,exist = ~current.indexOf(toggleClass)
;
current.splice(exist ? current.indexOf(toggleClass) : 0,
exist ? 1 : 0,
exist ? null : toggleClass);
$menulink.className = current.join(' ').replace(/^\s+|\s+$/,'');
That's why JQuery wrapped this kind of code.
This jsfiddle contains a working example using javascript without a framework. Besides that it demonstrates how to program your own element wrapper.
Where to start? You'll have to dive into javascript I suppose. Or check this SO-question
For modern browsers only.®
document.addEventListener('DOMContentLoaded', function() {
document.body.classList.add('js');
var wrap = document.getElementById('wrap');
var menuLinks = Array.prototype.slice.call(document.getElementsByClassName('menu-link'));
var toggleActive = function(element) {
element.classList.toggle('active');
};
menuLinks.forEach(function(menuLink) {
menuLink.addEventListener('click', function(e) {
menuLinks.forEach(toggleActive);
toggleActive(wrap);
}, false);
});
}, false);
var toggleClass = function (el, className) {
if(el) {
if(el.className.indexOf(className)) {
el.className = el.className.replace(className, '');
}
else {
el.className += ' ' + className;
}
}
};
document.addEventListener('DOMContentLoaded', function () {
document.body.className += ' js';
var $menu = document.querySelector('#menu'),
$menulink = document.querySelectorAll('.menu-link'),
$wrap = document.querySelector('#wrap');
$menulink.addEventListener('click', function (e) {
toggleClass($menulink, 'active');
toggleClass($wrap, 'active');
e.preventDefault();
});
});
There's always classList (workaround for incompatible browsers included).
Absolutely. Since jQuery is a subset of JavaScript (written entirely in JavaScript) any function you like can be duplicated. It's a matter of how much effort you want to put into it. Below is how I would duplicate the limited subset of jQuery in your post and it's reasonably cross-browser compatible (if a wee bit long...).
var Vanilla;
if (!Vanilla) {
Vanilla = {};
}
//execute this now to have access to it immediately.
(function () {
'use strict';
Vanilla.addHandler = function (elem, event, handler) {
if (elem.addEventListener) {
elem.addEventListener(event, handler, false);
} else if (elem.attachEvent) {
elem.attachEvent('on' + event, handler);
}
};
Vanilla.hasClass = function (elem, cssClass) {
var classExists = false;
//
if (elem && typeof elem.className === 'string' && (/\S+/g).test(cssClass)) {
classExists = elem.className.indexOf(cssClass) > -1;
}
//
return classExists;
};
Vanilla.addClass = function (elem, cssClass) {
if (elem && typeof elem.className === 'string' && (/\S+/g).test(cssClass)) {
//put spaces on either side of the new class to ensure boundaries are always available
elem.className += ' ' + cssClass + ' ';
}
};
Vanilla.removeClass = function (elem, cssClass) {
if (elem && typeof elem.className === 'string'&& (/\S+/g).test(cssClass)) {
//replace the string with regex
cssClass = new RegExp('\\b' + cssClass + '\\b', 'g');
elem.className = elem.className.replace(cssClass, '').replace(/^\s+/g, '').replace(/\s+$/g, ''); //trim className
}
};
Vanilla.toggleClass = function (elem, cssClass) {
if (Vanilla.hasClass(elem, cssClass)) {
Vanilla.removeClass(elem, cssClass);
} else {
Vanilla.addClass(elem, cssClass);
}
};
Vanilla.getElementsByClassName = function (cssClass) {
var nodeList = [],
classList = [],
allNodes = null,
i = 0,
j = 0;
if (document.getElementsByClassName1) {
//native method exists in browser.
nodeList = document.getElementsByClassName(cssClass);
} else {
//need a custom function
classList = cssClass.split(' ');
allNodes = document.getElementsByTagName('*');
for (i = 0; i < allNodes.length; i += 1) {
for (j = 0; j < classList.length; j += 1) {
if (Vanilla.hasClass(allNodes[i], classList[j])) {
nodeList.push(allNodes[i]);
}
}
}
}
return nodeList;
};
}());
//Now we have a proper window onload
Vanilla.addHandler(window, 'load', function () {
'use strict';
var body = document.body,
menu = document.getElementById('menu'),
menulink = [],
wrap = document.getElementById('wrap'),
i = 0,
menulinkClickHandler = function (e) {
var i = 0;
for (i = 0; i < menulink.length; i += 1) {
Vanilla.toggleClass(menulink[i], 'active');
}
Vanilla.toggleClass(wrap, 'active');
return false;
};
Vanilla.addClass(body, 'js');
menulink = Vanilla.getElementsByClassName('menu-link');
for (i = 0; i < menulink.length; i += 1) {
Vanilla.addHandler(menulink[i], 'click', menulinkClickHandler);
}
});

Categories

Resources