Web Components with angular.js & IE11 compatibility - javascript

I have angular.js application in which I would like to initialize a web component.
It works perfectly fine on other browsers but it seems that IE11 has issues with
document.importNode
angular.js onInit function:
vm.$onInit = function() {
vm.params = $location.search();
if(vm.params.merchantId && vm.params.apiToken && vm.params.amount && vm.params.orderId) {
vm.mid = vm.params.merchantId;
vm.apiToken = vm.params.apiToken;
vm.amount = vm.params.amount;
vm.orderId = vm.params.orderId;
let template = document.querySelector('#template');
let clone = document.importNode(template.content, true);
let cmp = clone.querySelector('cmp-request');
cmp.setAttribute('mid', vm.mid);
template.replaceWith(clone);
}
}
HTML:
<template id="template">
<cmp-request></cmp-request>
</template>
Is there any other way to clone web component and pass params inside without using importNode so it would work on IE11?

IE 11 doesn't support importNode and replaceWith. For importNode, I use children to get <template>'s children to get the web component in IE 11. For replaceWith, I use this polyfill to support it in IE 11.
You can refer to my code sample with dummy values:
function ReplaceWithPolyfill() {
'use-strict'; // For safari, and IE > 10
var parent = this.parentNode,
i = arguments.length,
currentNode;
if (!parent) return;
if (!i) // if there are no arguments
parent.removeChild(this);
while (i--) { // i-- decrements i and returns the value of i before the decrement
currentNode = arguments[i];
if (typeof currentNode !== 'object') {
currentNode = this.ownerDocument.createTextNode(currentNode);
} else if (currentNode.parentNode) {
currentNode.parentNode.removeChild(currentNode);
}
// the value of "i" below is after the decrement
if (!i) // if currentNode is the first argument (currentNode === arguments[0])
parent.replaceChild(currentNode, this);
else // if currentNode isn't the first
parent.insertBefore(currentNode, this.nextSibling);
}
}
if (!Element.prototype.replaceWith)
Element.prototype.replaceWith = ReplaceWithPolyfill;
if (!CharacterData.prototype.replaceWith)
CharacterData.prototype.replaceWith = ReplaceWithPolyfill;
if (!DocumentType.prototype.replaceWith)
DocumentType.prototype.replaceWith = ReplaceWithPolyfill;
var template = document.querySelector('#template');
if (navigator.userAgent.indexOf('MSIE') !== -1 || navigator.appVersion.indexOf('Trident/') > -1) { //IE11
var clone = template.children[0];
clone.setAttribute('mid', 'test');
} else {
var clone = document.importNode(template.content, true);
var cmp = clone.querySelector('cmp-request');
cmp.setAttribute('mid', 'test');
}
template.replaceWith(clone);
<template id="template">
<cmp-request></cmp-request>
</template>

Related

nextElementSibling Polyfill gives error 'Element' is undefined

I'm using IE in compatibility mode to support old web pages and also writing new pages.
I'm trying to use nextElementSibling so I've been adding the following Polyfill for it into my JS file. My goal is that if 'nextElementSibling' isn't supported then it will use the definition in the Polyfill.
Here's the Polyfill from the Mozilla site:
if (!("nextElementSibling" in document.documentElement)){
Object.defineProperty(Element.prototype, "nextElementSibling", {
get: function(){
var e = this.nextSibling;
while(e && 1 !== e.nodeType)
e = e.nextSibling;
return e;
}
});}
When I run this I get the error "'Element' is undefined."
I thought Element.prototype was built-in functionality.
Do I need to add something else before adding that Polyfill?
How do I get this working?
Any (relevant on topic) help would be greatly appreciated.
Update
Per a suggestion I tried the following but it's not executing the redefined nextElementSibling. Here's the code I put at the beginning of my JS file:
if (!("nextElementSibling" in document.documentElement))
{
if (!window.Element)
{
Element = function() { }
Element.prototype.nextElementSibling = function()
{
var e = this.nextSibling;
while (e && 1 !== e.nodeType)
e = e.nextSibling;
return e;
}
Element.prototype.firstElementChild = function()
{
var el = this.firstChild;
while (el && el.nodeType !== 1)
{
el = el.nextSibling;
}
return el;
}
var __createElement = document.createElement;
document.createElement = function(tagName)
{
var element = __createElement(tagName);
for (var key in Element.prototype)
element[key] = Element.prototype[key];
return element;
}
var __getElementById = document.getElementById;
document.getElementById = function(id)
{
var element = __getElementById(id);
for (var key in Element.prototype)
element[key] = Element.prototype[key];
return element;
}
}
}
Later in my JS file I do this:
var temp = this.parentElement.parentElement.nextElementSibling;
It doesn't work. The defined nextElementSibling never gets run and temp = undefined.

javascript - how to take selected element from function and pass it through as a parameter of another function

I have been trying for days upon weeks with trying to build a personal library without jQuery for my school club, and so far I am hitting a rut when it comes to passing through an element or objects through to another function. The notation I am trying for is this :
CC(function(){
CC('id:wrapper').set('html','Hello World!');
});
That is my test code, and the library looks as it does below:
"use strict";
var CC = function () {
var args = arguments[0] || {};
if(typeof args === "object") {
args = args || {};
}
else if(typeof args === "function") {
args = arguments[0];
return window.onload = args;
}
else if(typeof args !== "object" || typeof args !== "function") {
var elem = get(args);
return elem;
}
};
CC({
//Can only be done once. Will return TypeError because '$' won't exist afterward
noConflict : function (name) {
name = new CC();
return name;
}
});
//The way to modify things
CC.mod = CC.prototype = {};
CC.extend = CC.mod.extend = function () {
var args = arguments[0] || {};
var target = get(args);
return target;
};
CC.mod.extend({
//Use psuedo types to set specific values (required)
set : function(type, value) {
return set(this.target, type, value);
}
});
//General get function to get selectors, generate functions, or return values
function get() {
var args = arguments[0] || {};
//Check if the argument is a function
//If it is, return the function on page load
if (typeof args === "function") {
return window.onload = args;
}
//Check argument type
if(typeof args !== "object") {
args = arguments[0];
return args;
}
else {
args = {};
return args;
}
//Check if args has an elem psuedo
if(args.indexOf("id:") > -1 || args.indexOf("class:") > -1 || args.indexOf("tag:") > -1) {
var target = args;
//Run id psuedo
if(target.indexOf("id:") > -1) {
target = target.replace('id:','');
console.log(target);
return document.getElementById(target);
}
//Run class psuedo
else if(target.indexOf("class:") > -1) {
target = target.replace('class:','');
console.log(target);
return document.getElementsByClassName(target);
}
//Run tag psuedo
else if(target.indexOf("tag:") > -1) {
target = target.replace('class:','');
console.log(target);
return document.getElementsByTagName(target);
}
}
//Check if args is not null
//If not, then return args value
if(args !== null) {
return args.value;
}
else {
return null;
}
}
//General function to set things for elements
function set(elem, property, value) {
//If the element provided is part of getting an element
//If it is, run the psuedo checker
if(elem.indexOf("id:") > -1 || elem.indexOf("class:") > -1 || elem.indexOf("tag:") > -1) {
elem = get(elem);
//Rerun the set() function to set properties and values
set(elem, property, value);
}
//If not, then run the type psuedo checker
else {
//Check if style
if(property.indexOf("css:") > -1 || property.indexOf("style:") > -1) {
//Check for the independent types
if(property.indexOf("css:") > -1) {
property = property.replace('css:','');
return elem.style[property] = value;
}
else if(property.indexOf("style:") > -1) {
property = property.replace('style:','');
return elem.style[property] = value;
}
}
//Check if attribute
else if(property.indexOf("attr:") > -1) {
property = property.replace('attr:','');
return elem.setAttribute(property, value);
}
//Check if html
else if(property.indexOf("html") > -1) {
return elem.innerHTML = value;
}
//To add more, just add another else if(condition...) {Code} statement
//Condition must be defined in psuedo selectors
//Condition must be property.indexOf("selector:" > -1)
//return statement must consist of a return value from the value parameter
}
}
I don't know how to get my methods to pass through correctly and I don't know how to get my methods to apply to the element in the CC('id:wrapper') code. I already have the 'psuedo selector' made to get rid of the id: code. Any help would be much appreciated!
You've posted quite some code which I wasn't able to get to work quickly, so I'm not sure if this will help you out.
The basic idea is that your CC method will always have to return an object with a set method. If there's no element with id="wrapper", you'll have to figure out a way to handle exceptions.
You can use bind to create a new function from an earlier defined function with a pre-bound this context and pre-filled in arguments.
A simplified example:
var CC = function(query) {
return {
set: set.bind(null, document.querySelector(query))
};
}
function set(element, attr, val) {
element.setAttribute(attr, val);
}
CC("input").set("placeholder", "I was set by js");
<input type="text" />
If you want to do more advanced binding of arguments, I'd suggest you google "Currying". With some code, you can make functions automatically return new functions when called with less arguments than needed.
What .bind does:
The bind method is defined in Function.prototype. You can call it on any function you've defined to create a new function.
The first argument that goes in to bind, is used as the this context in the newly created function. You could, for example, do:
var myDiv = document.querySelector("div");
var logText = function() {
console.log(this.innerText);
};
var logDivText = logText.bind(myDiv);
logText(); // Bound to window, logs undefined
logDivText(); // Bound to div, logs text
<div>Text in a div</div>
Any other arguments passed to bind, are automatically passed as arguments. For example:
var sum = function(a, b) {
return a + b;
};
var sum3 = sum.bind(null, 3); // we don't use this, so we don't define it
console.log(sum3(5)); // Prints 8

Why do these 3 greasemonkey (javascript) scripts conflict with each other?

Ideally, I would like them all running, but when I have the second and/or third one active, Script 1 fails. (It just does nothing)
I wonder, is it possible to merge them into one script? Would that solve the problem? (I am tempted to try cutting and pasting them into one script just to see what happens)
Script 1 (the reloader)
(function () {
"use strict";
function walkTheDOM(node, func) {
if (node && node.nodeType) {
if (typeof func === "function") {
func(node);
}
node = node.firstChild;
while (node) {
walkTheDOM(node, func);
node = node.nextSibling;
}
}
}
function filterElementsByContains(elements, string) {
var toStringFN = {}.toString,
text = toStringFN.call(elements),
result,
length,
i,
element;
if (text !== "[object NodeList]" && text !== "[object Array]" && !($() instanceof jQuery)) {
return result;
}
result = [];
if (typeof string === "string") {
string = new RegExp("^" + string + "$");
} else if (toStringFN.call(string) !== "[object RegExp]") {
return result;
}
function getText(node) {
if (node.nodeType === 3) {
text += node.nodeValue;
}
}
length = elements.length;
i = 0;
while (i < length) {
text = "";
element = elements[i];
walkTheDOM(element, getText);
if (string.test(text)) {
result.push(element);
}
i += 1;
}
return result;
}
if(!filterElementsByContains([document.getElementsByTagName("table")[0]], /We are proud to announce that the November discounts have been chosen/).length) {
location.reload();
}
}());
Script 2 (Jump to last sheet, if it's multi sheet)
function getPreviousLink(){
var nextLink = document.getElementById('pagination-next-link');
var links = document.getElementsByClassName('v_page_nav')[0].getElementsByTagName("a");
for(var i=0; i < links.length; i++){
if(links[i] == nextLink) { return links[i-1]; }
}
}
var link = getPreviousLink();
link.target="_blank";
link.click();
Script 3 (open previous sheet, if there is one)
var link = document.getElementById('pagination-prev-link');
link.target="_blank";
link.click();
If the second 2 scripts aren't changing anything that would cause your first script to break (like something the first script looks for gets removed by script 2).... I would suggest going into 'manage scripts' and changing the order they run in... sometimes that can fix issues like this.

Getting Error: Could not convert JavaScript argument arg 0 [nsIDOMWindow.getComputedStyle]

I have a bit of javascript code to find and replace text into an image. I then gather the font size of the original text and use that to set the size of the new image.
Problem is, I keep getting the error: Could not convert JavaScript argument arg 0 [nsIDOMWindow.getComputedStyle]
Code:
function findAndReplace(searchText, replacement, searchNode) {
if (!searchText || typeof replacement === 'undefined') {
// Throw error here if you want...
return;
}
var regex = typeof searchText === 'string' ?
new RegExp(searchText, 'g') : searchText,
childNodes = (searchNode || $("body").get(0)).childNodes,
excludes = 'html,head,style,title,link,meta,script,object,iframe';
var cnLength = childNodes.length;
while (cnLength--) {
var currentNode = childNodes[cnLength];
if (currentNode.nodeType === 1 &&
(excludes + ',').indexOf(currentNode.nodeName.toLowerCase() + ',') === -1) {
arguments.callee(searchText, replacement, currentNode);
}
if (currentNode.nodeType !== 3 || !regex.test(currentNode.data) ) {
continue;
}
var parent = currentNode.parentNode;
var frag = (function(){
var html = currentNode.data.replace(regex, replacement);
var wrap = document.createElement('div');
var frag = document.createDocumentFragment();
wrap.innerHTML = html;
while (wrap.firstChild) {
frag.appendChild(wrap.firstChild);
}
console.log(currentNode);
var jQNode = $(currentNode);
console.log("yay");
// var fontSize = jQNode.css('font-size');
if (!currentNode || currentNode == document) currentNode = document.body
var fontSize = getStyle(currentNode, 'font-size');
console.log("tast");
var heightPixels = fontSizeToPixels(fontSize);
$(".InLogo",frag).each(function(){
$(this).css("height", heightPixels+"px");
});
return frag;
})();
parent.insertBefore(frag, currentNode);
parent.removeChild(currentNode);
}
}
function getStyle(el,styleProp) {
var camelize = function (str) {
return str.replace(/\-(\w)/g, function(str, letter){
return letter.toUpperCase();
});
};
if (el.currentStyle) {
return el.currentStyle[camelize(styleProp)];
} else if (document.defaultView && document.defaultView.getComputedStyle) {
return document.defaultView.getComputedStyle(el,null)
.getPropertyValue(styleProp);
} else {
return el.style[camelize(styleProp)];
}
}
The error occurs at this line return document.defaultView.getComputedStyle(el,null).getPropertyValue(styleProp); of getStyle()
something.childNodes includes textNodes as well as Elements, and that's a problem for the getStyle() function.
Nodes don't have a style (Elements do), so who knows what will happen when you feed getStyle something that has .data; a plain Node.
Check for the existence of style to avoid the run-time error:
FIX:
var fontSize = currentNode.style ? getStyle(currentNode, 'font-size') : 0;

Javascript IE 7 getting OBJECT element

I'm making a code that removes a videoplayer from the page and then places it back when needed (even if the element doesn't have an id).
I'm finding issues with IE7
Here is my code:
var weboElem, weboElemPar, weboElemIndex, weboStored;
function weboRemoveVideoplayer(vpId){
weboElem = document.getElementById(vpId);
if(!weboElem) return false;
weboElemPar = weboElem.parentNode;
weboElemIndex = 0;
var child = weboElem;
while( (child = child.previousSibling) != null )
weboElemIndex++;
weboElemPar.removeChild(weboElem);
return true;
}
function weboPlaceVideoplayerBack(){
if(weboElemPar.insertBefore !== undefined && weboElemPar.childNodes !== undefined)
{
weboElemPar.insertBefore(weboElem, weboElemPar.childNodes[weboElemIndex]);
return true;
}
return false;
}
var result = document.evaluate(
'//*/param[contains(#value, "autoplay=1")]/..', // XPath expression
document, // context node
null, // namespace resolver
XPathResult.ORDERED_NODE_SNAPSHOT_TYPE
);
if(result.snapshotLength > 0)
{
var node = result.snapshotItem(0);
node.id = "webo";
document.getElementById('info').innerHTML = node.nodeName.toLowerCase()+" -> "+node.id;
} else document.getElementById('info').innerHTML = "not found";
(Note that document.evaluate WORKS because I imported javascript-xpath library)
On IE7 if the XPath finds an IFRAME there are no problems and it works but if it finds an OBJECT does nothing and stops at weboElem = document.getElementById(vpId); as if it didn't find the id.
I tried modifying the code like this:
if(result.snapshotLength > 0)
{
var node = result.snapshotItem(0);
node.id = "webo";
node.parentNode.removeChild(node);
document.getElementById('info').innerHTML = node.nodeName.toLowerCase()+" -> "+node.id;
if(node.nodeName.toLowerCase() == "object") weboStored = node;
else weboStored = null;
} else document.getElementById('info').innerHTML = "not found";
and it works, the videoplayer disappears at page load. I want to use the function though, so I edited everything like this (storing the node into a global var that later I get in the weboRemoveVideoplayer function):
var weboElem, weboElemPar, weboElemIndex, weboStored;
function weboRemoveVideoplayer(vpId){
if(!weboStored) weboElem = document.getElementById(vpId);
else weboElem = weboStored;
if(!weboElem) return false;
weboElemPar = weboElem.parentNode;
weboElemIndex = 0;
var child = weboElem;
while( (child = child.previousSibling) != null )
weboElemIndex++;
weboElemPar.removeChild(weboElem);
alert("5");
return true;
}
function weboPlaceVideoplayerBack(){
if(weboElemPar.insertBefore !== undefined && weboElemPar.childNodes !== undefined)
{
weboElemPar.insertBefore(weboElem, weboElemPar.childNodes[weboElemIndex]);
return true;
}
return false;
}
// bind XPath methods to document and window objects
// NOTE: This will overwrite native XPath implementation if it exists
//XPathJS.bindDomLevel3XPath(); //solo per xpathJs
var result = document.evaluate(
'//*/param[contains(#value, "autoplay=1")]/..', // XPath expression
document, // context node
null, // namespace resolver
XPathResult.ORDERED_NODE_SNAPSHOT_TYPE
);
if(result.snapshotLength > 0)
{
var node = result.snapshotItem(0);
node.id = "webo";
node.parentNode.removeChild(node);
document.getElementById('info').innerHTML = node.nodeName.toLowerCase()+" -> "+node.id;
if(node.nodeName.toLowerCase() == "object") weboStored = node;
else weboStored = null;
} else document.getElementById('info').innerHTML = "not found";
This way the code blocks itself when trying to retrieve the parent node.
Could someone suggest me what to do here?
PS: with chrome and firefox the code works perfectly in the first version I posted.
Fixed it!
I solved the issue by wrapping the OBJECT inside a div with an id of my choice which I can retrieve whenever I want. I do this in the resolveXpath function.
Here the code:
var weboElem, weboElemPar, ieObject = false;
var weboElemIndex = 0;
function weboRemoveVideoplayer(vpId){
var child;
if(!ieObject) weboElem = document.getElementById(vpId);
else weboElem = document.getElementById('my_usage');
if(!weboElem) return false;
weboElemPar = weboElem.parentNode;
weboElemIndex = 0;
child = weboElem;
while( (child = child.previousSibling) != null ) weboElemIndex++;
if(typeof weboElemPar.removeChild !== 'undefined') weboElemPar.removeChild(weboElem);
else return false;
return true;
}
function weboPlaceVideoplayerBack(){
if(typeof weboElemPar.insertBefore !== 'undefined' && typeof weboElemPar.childNodes !== 'undefined' && typeof weboElemPar.appendChild !== 'undefined'){
if(weboElemPar.childNodes.length > 0 && weboElemIndex < weboElemPar.childNodes.length) weboElemPar.insertBefore(weboElem, weboElemPar.childNodes[weboElemIndex]);
else weboElemPar.appendChild(weboElem);
return true;
}
return false;
}
function resolveXpath(path)
{
//XPathJS.bindDomLevel3XPath(); //solo per xpathJs
var result = document.evaluate(path,document,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE);
if(result.snapshotLength > 0){
var child, node = result.snapshotItem(0);
if(node.nodeName.toLowerCase() == 'object'){
ieObject = true;
child = node;
while( (child = child.previousSibling) != null ) weboElemIndex++;
var div = document.createElement('div');
div.id = 'my_usage';
if(typeof node.parentNode.insertBefore !== 'undefined' && typeof node.parentNode.childNodes !== 'undefined' && typeof node.parentNode.appendChild !== 'undefined'){
if(node.parentNode.childNodes.length > 0 && weboElemIndex < node.parentNode.childNodes.length) node.parentNode.insertBefore(div,node.parentNode.childNodes[weboElemIndex]);
else node.parentNode.appendChild(div);
div.appendChild(node);
} else return false;
} else node.id = 'my_usage';
return true;
} else return false;
}
resolveXpath('//*/param[contains(#src, "autoplay=1")]/..');

Categories