How to debug injected javascript code in IE compatibility mode? - javascript

I need to inject some Javascript scripts to IE and then invoke some methods.
I tried the following simple C# code (the Javascript code is to build xpath from a known HTML element).
string xpath = #"
(function(win) {
""use strict"";
var doc = win.document;
if (doc._xpath_installed) return;
doc._xpath_installed = true;
doc.createXPath = function (node, optimized) {
if (node.nodeType === Node.DOCUMENT_NODE) {
return '/';
}
var steps = [];
var contextNode = node;
while (contextNode) {
var step = _xPathValue(contextNode, optimized);
if (!step) {
break;
} // Error - bail out early.
steps.push(step);
if (step.optimized) {
break;
}
contextNode = contextNode.parentNode;
}
steps.reverse();
var stepvalues = [];
steps.forEach(function (step) {
stepvalues.push(_steptostring(step));
});
return (steps.length && steps[0].optimized ? '' : '/') + stepvalues.join('/');
};
var _xPathValue = function (node, optimized) {
var ownValue;
var ownIndex = _xPathIndex(node);
if (ownIndex === -1) {
return null;
} // Error.
switch (node.nodeType) {
case Node.ELEMENT_NODE:
if (optimized && node.getAttribute('id')) {
return _stepnew('//*[#id=""' + node.getAttribute('id') + '""]', true);
}
ownValue = node.localName;
break;
case Node.ATTRIBUTE_NODE:
ownValue = '#' + node.nodeName;
break;
case Node.TEXT_NODE:
case Node.CDATA_SECTION_NODE:
ownValue = 'text()';
break;
case Node.PROCESSING_INSTRUCTION_NODE:
ownValue = 'processing-instruction()';
break;
case Node.COMMENT_NODE:
ownValue = 'comment()';
break;
case Node.DOCUMENT_NODE:
ownValue = '';
break;
default:
ownValue = '';
break;
}
if (ownIndex > 0) {
ownValue += '[' + ownIndex + ']';
}
return _stepnew(ownValue, node.nodeType === Node.DOCUMENT_NODE);
};
var _xPathIndex = function (node) {
// Returns -1 in case of error, 0 if no siblings matching the same expression,
// <XPath index among the same expression-matching sibling nodes> otherwise.
function areNodesSimilar(left, right) {
if (left === right) {
return true;
}
if (left.nodeType === Node.ELEMENT_NODE && right.nodeType === Node.ELEMENT_NODE) {
return left.localName === right.localName;
}
if (left.nodeType === right.nodeType) {
return true;
}
// XPath treats CDATA as text nodes.
var leftType = left.nodeType === Node.CDATA_SECTION_NODE ? Node.TEXT_NODE : left.nodeType;
var rightType = right.nodeType === Node.CDATA_SECTION_NODE ? Node.TEXT_NODE : right.nodeType;
return leftType === rightType;
}
var siblings = node.parentNode ? node.parentNode.children : null;
if (!siblings) {
return 0;
} // Root node - no siblings.
var hasSameNamedElements;
for (var i = 0; i < siblings.length; ++i) {
if (areNodesSimilar(node, siblings[i]) && siblings[i] !== node) {
hasSameNamedElements = true;
break;
}
}
if (!hasSameNamedElements) {
return 0;
}
var ownIndex = 1; // XPath indices start with 1.
for (var i = 0; i < siblings.length; ++i) {
if (areNodesSimilar(node, siblings[i])) {
if (siblings[i] === node) {
return ownIndex;
}
++ownIndex;
}
}
return -1;
};
var _stepnew = function(value, optimized) {
return {
value: value,
optimized: optimized || false
}
};
var _steptostring = function(step) {
return step[""value""];
};
})(window);
";
And then I try to inject the xpath string and invoke a method,
// doc is the html document (type: mshtml.IHTMLDocument2)
// element is the html element (type: mshtml.IHTMLElement)
doc.parentWindow.execScript(xpath, "JScript");
object[] args = new object[2];
args[0] = element;
args[1] = 1;
object result = doc.GetType().InvokeMember("createXPath", BindingFlags.Instance | BindingFlags.InvokeMethod, null, doc, args);
It works fine in Internet Explorer 11 (Windows 10).
However, when I add the website to Compatibility View (settings-> compatibility view settings), the InvokeMember call throws exception "Exception from HRESULT: 0x80020101", which means there are some script errors in the Javascript code.
My question is, is there a way to debug into this Javascript code in the above situation? Without debugging it is almost impossible to find the root cause only based on the information 0x80020101.

If you have script errors in your JS code, why don't you trace the client-side code's execution with console.log() or console.debug() so that you know what is happening in your application ?

If you just want to debug code in Edge IE mode, you can use IEChooser to open Internet Explorer DevTools, as follows:
In Windows, open the Run dialog box. For example, press the Windows logo key + R.
Enter %systemroot%\system32\f12\IEChooser.exe, and then click OK.
In IEChooser, select the entry for the IE mode tab.
For more details, you could also refer to this doc: Open DevTools on a tab in IE mode.

Related

Disable script on condition

Good evening, could you help me, please? From this saved (static) page, page two, I’m running a script that extracts, in “Nome” field, the publisher from the bibliographic item (Feltrinelli, in the example). I would like the script to be NOT executed when on the previous page, page one, there is the expression “Editore moderno” (that is the publisher) under the heading “Persone, enti e famiglie”, that is in “fieldset.legami_tito”).
On Page one I tried to set a local variable if the expression “Editore moderno” is found:
var elencoLabel = document.querySelectorAll("span.grid-6");
if (elencoLabel.length > 8)
{
localStorage.removeItem("voce");
if (elencoLabel[8].innerText == "Editore moderno")
{
localStorage.setItem("voce","Editore moderno");
}
}
On Page two I tried this script (replacing the last line of the script):
function getNome(tmp) {
var idx = tmp.indexOf('. ((');
if(idx > -1){
tmp = tmp.substr(0, idx);
}
tmp = tmp.split('. - ');
switch(tmp.length){
case 3:
tmp = tmp[1];
break;
case 4:
tmp = tmp[2];
break;
default:
tmp = "";
break;
}
if(tmp !== ''){
tmp = tmp.substr(tmp.indexOf(' : ') + 2);
console.log(tmp);
if(tmp.indexOf('.') != -1 && tmp.split('.').length == 2){
tmp = tmp.substr(tmp.indexOf('. ') + 1, tmp.indexOf(', ') -3);
tmp = tmp.trim();
}
else {
tmp = tmp.split(",")[0];
tmp = tmp.trim();
}
}
return tmp;
}
function impostaNome(tmp) {
Array.from(document.querySelectorAll('article section.grid_container form div.grid-row label span')).filter( e => e.innerText.trim() === 'Nome')[0].parentNode.querySelector('input').value = tmp;
}
var elencoLabel = document.querySelectorAll("span.grid-6");
if (elencoLabel.length < 8 )
{
var miaVoce = localStorage.getItem("voce");
if (miaVoce == "Editore moderno")
{
impostaNome(getNome(document.querySelector('div.meta.tito div.evidence.isbd').innerText));
}
}
But with these changes, the publisher is never extracted.

In Google Docs under script control, can a paragraph inserted automatically after the insertion of a table be addressed programmatically?

I have a Google Docs document with a PARAGRAPH followed by a TABLE followed by a TABLE. Visually there is a PARAGRAPH between the two TABLEs. Programatically, however, using the following code, the run log demonstrates that there is no PARAGRAPH, viz
[1] PARAGRAPH {'LEFT_TO_RIGHT' : true, 'LINE_SPACING' : 1.15, 'SPACING_AFTER' : 0, 'SPACING_BEFORE' : 0, 'INDENT_FIRST_LINE' : 0, 'INDENT_END' : 0, 'INDENT_START' : 0}
[1/1] TEXT {} perth influencer
[2] TABLE {'BORDER_WIDTH' : 1, 'BORDER_COLOR' : '#000000'}
[3] TABLE {'BORDER_WIDTH' : 1, 'BORDER_COLOR' : '#000000'} Keyword Research Volume
...
According to the Google Apps Script documentation for appendTable:
This method will also append an empty paragraph after the table, since Google Docs documents cannot end with a table.
This paragraph can be seen with the eyes but the script as it stands cannot "see" it. That is, stepping through the child elements of the document's body fails to detect the presence of the automatically-inserted paragraph. This is a problem because I want to reduce the point size of that paragraph.
This may be a known limitation of Google Docs via Google Apps Script. Or it may be my bad code, so below are the functions that I base my assertion on. They do nothing other than report on what they find but even so, maybe I'm missing something.
The output above was generated by coding LogChildren with a parameter of type GoogleAppsScript.Document.Body and referring to the body of the generated document.
String.prototype.quoted = function () {
return "'" + this.replace(/'/g,"\\'") + "'";
}
Number.prototype.quoted = function () {
return String(this);
}
Boolean.prototype.quoted = function () {
return this ? "true" : "false";
}
function getInnerText(child) {
switch (child.getType().toString()) {
case "BODY_SECTION":
return child.asBody().getText();
break;
case "EQUATION":
return child.asEquation().getText();
break;
case "EQUATION_FUNCTION":
return child.asEquationFunction().getText();
break;
case "FOOTER_SECTION":
return child.asFooterSection().getText();
break;
case "FOOTNOTE_SECTION":
return child.asFootnoteSection().getText();
break;
case "HEADER_SECTION":
return child.asHeaderSection().getText();
break;
case "LIST_ITEM":
return child.asListItem().getText();
break;
case "PARAGRAPH":
return "";
break;
case "TABLE":
return child.asTable().getText();
break;
case "TABLE_CELL":
return child.asTableCell().getText();
break;
case "TABLE_OF_CONTENTS":
return child.asTableOfContents().getText();
break;
case "TABLE_ROW":
return child.asTableRow().getText();
break;
case "TEXT":
return child.asText().getText();
break;
case "PAGE_BREAK":
return "";
break;
case "INLINE_IMAGE":
return child.asInlineImage().getLinkUrl();
break;
default:
return child.asText().getText();
break;
}
}
function getStyles(child) {
const attribs = child.getAttributes();
const attribList = [];
for (let att in attribs) {
try {
if (null !== attribs[att])
attribList.push(att.quoted() + " : " + attribs[att].quoted());
}
catch (E) { }
}
return "{" + attribList.join(", ") + "}";
}
function LogChild(index, child) {
Logger.log("[%s] %s %s %s", index, child.getType().toString(), getStyles(child), getInnerText(child));
}
function LogChildren(body) {
function LogDeeper(cc, child) {
const childCount = child.getNumChildren();
for (let c = 0; c < childCount; c++) {
LogChild(String(cc) + "/" + String(c + 1), child.getChild(c));
}
}
const childCount = body.getNumChildren();
for (let c = 0; c < childCount; c++) {
const child = body.getChild(c);
LogChild(String(c + 1), child);
if (isParagraph(child)) {
LogDeeper(c + 1, child.asParagraph());
}
else if (isListItem(child)) {
LogDeeper(c + 1, child.asListItem());
}
}
}
function isPageBreak(elem) {
return elem.getType() === DocumentApp.ElementType.PAGE_BREAK;
}
function isText(elem) {
return elem.getType() === DocumentApp.ElementType.TEXT;
}
function isParagraph(elem) {
return elem.getType() === DocumentApp.ElementType.PARAGRAPH;
}
function isListItem(elem) {
return elem.getType() === DocumentApp.ElementType.LIST_ITEM;
}
function isTable(elem) {
return elem.getType() === DocumentApp.ElementType.TABLE;
}
Use google-docs-api 's Document#get to retrieve the document structure and if there is a intervening paragraph recorded between the two tables, issue UpdateParagraphStyleRequest to modify that paragraph.
You can access the api from apps script through Advanced Google services

How to stop executing Javascript function containing infinite loop after some time

Suppose I have following piece of code that contains an infinite loop:
function infiniteLoop() {
while(true) {
//do something, eg.
document.getElementById("someID").innerHTML = "Blah";
}
}
If we execute this code in an online compiler, browser will crash. I want to prevent that from happening. So I tried following code following this answer:
function willNotCrash() {
myVar = setInterval(infiniteLoop, 5000);
setTimeout(function(){
clearInterval(myVar);
}, 4000);
}
This code doesn't make the browser to crash, because I am stopping the execution before infiniteLoop() gets called by clearInterval(myVar).
My question is how do I stop executing such functions if they don't response within some period of time (eg. after 5 seconds or before the browser is crashed).
For example, if we copy paste following java code in https://www.compilejava.net/
public class HelloWorld {
public static void main(String[] args) {
while(true) {
System.out.println("Blah");
}
}
}
we get a nice output saying,
Script was taking longer than 5 seconds to execute so it was killed.
Here is my current code: http://js.do/code/106546
This is a bit tricky but perfectly doable. You need to tokenize the script and then rebuild it but insert a counter increment in every loop and function call. If the counter goes above some threshold, then bomb out. I did it here: https://littleminigames.com/
You can see the source at https://bitbucket.org/cskilbeck/littleminigames/src
The interesting bits are in wrapper.js (https://bitbucket.org/cskilbeck/littleminigames/src/ac29d0d0787abe93c75b88520050a6792c04d34d/public_html/static/js/wrapper.js?at=master&fileviewer=file-view-default)
Google escodegen, estraverse and esprima
I relied heavily on this: https://github.com/CodeCosmos/codecosmos/blob/master/www/js/sandbox.js
wrapper.js, as requested:
// Don't obfuscate this file! We depend on the toString() of functions!
// this was all nicked from https://github.com/CodeCosmos/codecosmos/blob/master/www/js/sandbox.js
(function(mainApp) {
'use strict';
var esprima = window.esprima,
estraverse = window.estraverse,
escodegen = window.escodegen,
errors = [],
eng,
Syntax = estraverse.Syntax;
// This implements the jankiest possible "source map", where we keep an array
// of [generatedLine, knownSourceLine]. Seems to essentially work.
function SourceNode(line, col, _sourceMap, generated) {
this.line = line;
this.col = col;
this.generated = generated;
}
SourceNode.prototype.toStringWithSourceMap = function toStringWithSourceMap() {
var code = [];
var mapLines = {};
var map = [];
// assumes that wrapCode adds two lines
var line = 3;
var lastMapLine = null;
function walk(node) {
if (typeof(node) === "string") {
if (node) {
code.push(node);
var matches = node.match(/\n/g);
if (matches !== null) {
line += matches.length;
}
}
} else if (node instanceof SourceNode) {
if (node.line !== null) {
if (!mapLines[line]) {
map.push([line, node.line]);
mapLines[line] = node.line;
}
}
walk(node.generated);
} else {
node.forEach(walk);
}
}
walk(this);
return {
code: code.join(''),
map: map
};
};
SourceNode.prototype.toString = function toString() {
return this.toStringWithSourceMap().code;
};
// This is used by escodegen
window.sourceMap = {
SourceNode: SourceNode
};
// TODO (chs): add in all the things that need to be masked
function runWrapper($userCode, __sys) {
var clear = __sys.clear,
setpixel = __sys.setpixel,
rectangle = __sys.rectangle,
box = __sys.box,
line = __sys.line,
getpixel = __sys.getpixel,
getpixeli = __sys.getpixeli,
keypress = __sys.keypress,
keyrelease = __sys.keyrelease,
keyheld = __sys.keyheld,
reset = __sys.reset;
__sys.userFunction = __sys.catchErrors($userCode);
}
function extractCode(fn) {
var code = fn.toString();
return code.substring(code.indexOf('{') + 1, code.lastIndexOf('}'));
}
function makeOneLine(code) {
return code.replace(/(\/\/[^\n]+|\n\s|\r\n\s*)/g, '');
}
var runTemplate = makeOneLine(extractCode(runWrapper));
function wrapCode(code, template, functionName, postCode) {
// avoid interpretation of the replacement string by using a fun.
// otherwise mo' $ mo problems.
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#Specifying_a_string_as_a_parameter
return ("'use strict';" + template.replace(/\$userCode/, function() {
return 'function ' + functionName + '() {\n' + code + postCode + '\n}';
}));
}
var injectStatement = esprima.parse("if (++__sys.ctr >= __sys.maxctr) throw new Error('Script halted - infinite loop?');").body[0];
var injectElseStatement = esprima.parse("if (++__sys.ctr >= __sys.maxctr) throw new Error('Script halted - infinite loop?'); else ;").body[0];
function CallExpression(callee, args) {
this.callee = callee;
this.arguments = args;
}
CallExpression.prototype.type = Syntax.CallExpression;
function Identifier(name) {
this.name = name;
}
Identifier.prototype.type = Syntax.Identifier;
function BlockStatement(body) {
this.body = body;
}
BlockStatement.prototype.type = Syntax.BlockStatement;
function ReturnStatement(argument) {
this.argument = argument;
}
ReturnStatement.prototype.type = Syntax.ReturnStatement;
function FunctionExpression(id, params, body) {
this.id = id;
this.params = params;
this.body = body;
this.defaults = [];
this.expression = false;
this.generator = false;
this.rest = null;
}
FunctionExpression.prototype.type = Syntax.FunctionExpression;
function wrapId(node, defaultName) {
if (node.loc) {
var id = (node.id || {
name: null,
loc: null
});
var loc = id.loc || node.loc;
var name = id.name || defaultName;
return new Identifier(name + '$' + loc.start.line);
} else {
return node.id;
}
}
function instrumentAST(ast) {
var identifierStack = [];
function pushIdentifier(s) {
identifierStack[identifierStack.length - 1].push(s);
}
function popIdentifierStack() {
identifierStack.pop();
}
function pushIdentifierStack() {
identifierStack.push([]);
}
function peekLastIdentifier() {
var lastStackIdx = identifierStack.length - 1;
if (lastStackIdx >= 0) {
var stack = identifierStack[lastStackIdx];
if (stack.length) {
return stack[stack.length - 1];
}
}
return '';
}
pushIdentifierStack();
return estraverse.replace(ast, {
enter: function enterAST(node) {
switch (node.type) {
case Syntax.VariableDeclarator:
if (node.id.type === Syntax.Identifier) {
pushIdentifier(node.id.name);
}
break;
case Syntax.MemberExpression:
if (node.object.type === Syntax.Identifier) {
var id = node.object.name;
if (node.property.type === Syntax.Identifier) {
id += '__dot__' + node.property.name; // huh? why mangle these?
// console.log(id);
}
pushIdentifier(id);
} else if (node.property.type === Syntax.Identifier) {
pushIdentifier(node.property.name);
}
break;
case Syntax.FunctionDeclaration:
pushIdentifierStack();
break;
case Syntax.FunctionExpression:
pushIdentifierStack();
break;
default:
break;
}
return node;
},
leave: function leaveAST(node) {
switch (node.type) {
case Syntax.DoWhileStatement:
break;
case Syntax.ForStatement:
break;
case Syntax.FunctionDeclaration:
break;
case Syntax.FunctionExpression:
break;
case Syntax.WhileStatement:
break;
default:
return estraverse.SKIP;
}
// modify the BlockStatement in-place to inject the instruction counter
if(node.body.body === undefined) {
// they have used a non-block statement as the body of a function or loop construct
// not allowed for function declarations - should never get here
if(node.type === Syntax.FunctionDeclaration) {
errors.push({
message: "Missing {",
line: node.loc.start.line,
column: node.loc.start.column
});
}
else {
// otherwise insert the test
var newBody = angular.copy(injectElseStatement);
newBody.alternate = node.body;
node.body = newBody;
}
return estraverse.SKIP;
}
node.body.body.unshift(injectStatement);
if (node.type === Syntax.FunctionExpression) {
popIdentifierStack();
// __catchErrors(node)
node.id = wrapId(node, peekLastIdentifier());
return new CallExpression(
new Identifier("__sys.catchErrors"), [node]);
}
if (node.type === Syntax.FunctionDeclaration) {
popIdentifierStack();
// modify the BlockStatement in-place to be
// return __catchErrors(function id() { body });
var funBody = node.body;
node.body = new BlockStatement([
new ReturnStatement(
new CallExpression(
new CallExpression(
new Identifier("__sys.catchErrors"), [new FunctionExpression(
wrapId(node, peekLastIdentifier()), [],
funBody)]), []))
]);
}
return node;
}
});
}
// mainApp.sandbox('var a = 1; function update(frame) { clear(0); }').code
// give it the source code as a string
mainApp.sandbox = function(code) {
var rc = {};
this.errors = [];
try {
this.ast = instrumentAST(esprima.parse(code, { range: true, loc: true }));
this.map = escodegen.generate(this.ast, { sourceMap: true, sourceMapWithCode: true });
this.code = wrapCode(this.map.code, runTemplate, '', ';\n__sys.updateFunction = (typeof update === "function") ? update : null;');
}
catch(e) {
this.errors.push({
message: e.description,
line: e.lineNumber,
column: e.column
});
}
if(this.code) {
this.code = "eng.clientFunction = function(__sys) {" + this.code + "};";
}
};
mainApp.sandbox.prototype.searchMap = function(needle) {
// binary search
var lo = 0;
var hi = this.map.map.length;
var mid, here;
while (true) {
mid = lo + ((hi - lo) >> 1);
here = this.map.map[mid];
if (mid === lo || here[0] === needle) {
return here[1];
} else if (here[0] > needle) {
hi = mid;
} else {
lo = mid;
}
}
};
})(mainApp);
Typically all JavaScript runs in one thread, so it is impossible to run any JavaScript that could stop your loop while your loop is running. Using HTML5 web workers, you can run the infinite loop in a separate thread, and then you can terminate it:
var myWorker = new Worker( '/infinite.js ');
setTimeout( function ( ) {
myWorker.terminate( );
}, 5000 );
However your web worker won't have access to the DOM, so the contents of your infinite loop would need to be different that what you have in your question.
I found exactly what I was looking for in Bergi's comment,
Alternatively, place a if (Date.now() > dateAtStartOfExecution+5000) return; in every loop body.
So now my code looks like:
function infiniteLoop() {
dateAtStartOfExecution = Date.now();
while(true) {
//do something
document.getElementById("someID").innerHTML = "Blah";
if (Date.now() > dateAtStartOfExecution+5000) {
alert("Taking too much time. Killing.");
return;
}
}
}
If I run this code after 5 seconds I will get an alert and the execution will stop. Try this:
http://js.do/code/106565

Regex to change a html element class with javascript not working

I have the following javascript function to open and close sub list elements on an onclick event:
function ShowHideDtls(itId) {
var subMen = document.getElementById(itId);
if (subMen != null) {
if (subMen.className == "nav nav-second-level collapse in") {
subMen.className = "nav nav-second-level collapse";
} else {
subMen.className += " in";
}
}
}
The "collapse" is a css class which makes display=none hiding the sub list and "in" is a class which makes display=block showing the sub list, creating a menu with submenus.
I found in this question Change an element's class with JavaScript in the first(accepted) answer use of a regex in order to do this. I tried it like this:
function ShowHideDtls(itId) {
var subMen = document.getElementById(itId);
if (subMen != null) {
if (subMen.className.match(/(?:^|\s)in(?!\S)/)) {
subMen.className.replace(/(?:^|\s)in(?!\S)/g, '');
} else {
subMen.className += " in";
}
}
}
The code without the regex works perfectly but with the regex it doesn't. I checked the regex in regex101.com and it seems to work there. As I understand it's more appropriate to use the regex than a long string of all the class names and also I also have a nav-third-level class that I have to close and open so the regex seems to be the convenient and proper way to do it.
What's wrong?
Thank you.
No need of regex here. You can use classList
Using classList is a convenient alternative to accessing an element's list of classes as a space-delimited string via element.className.
function ShowHideDtls(itId) {
var subMen = document.getElementById(itId);
if (subMen != null) {
subMen.classList.toggle('in');
}
}
toggle() will toggle the class of the element. If the element already has the class, it'll remove it, if not then toggle will add the class to the element.
Check the Browser Compatibility.
You can use following SHIM from MDN for IE9,
/*
* classList.js: Cross-browser full element.classList implementation.
* 2014-07-23
*
* By Eli Grey, http://eligrey.com
* Public Domain.
* NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
*/
/*global self, document, DOMException */
/*! #source http://purl.eligrey.com/github/classList.js/blob/master/classList.js*/
if ("document" in self) {
// Full polyfill for browsers with no classList support
if (!("classList" in document.createElement("_"))) {
(function (view) {
"use strict";
if (!('Element' in view)) return;
var
classListProp = "classList",
protoProp = "prototype",
elemCtrProto = view.Element[protoProp],
objCtr = Object,
strTrim = String[protoProp].trim || function () {
return this.replace(/^\s+|\s+$/g, "");
},
arrIndexOf = Array[protoProp].indexOf || function (item) {
var
i = 0,
len = this.length;
for (; i < len; i++) {
if (i in this && this[i] === item) {
return i;
}
}
return -1;
}
// Vendors: please allow content code to instantiate DOMExceptions
,
DOMEx = function (type, message) {
this.name = type;
this.code = DOMException[type];
this.message = message;
},
checkTokenAndGetIndex = function (classList, token) {
if (token === "") {
throw new DOMEx(
"SYNTAX_ERR", "An invalid or illegal string was specified"
);
}
if (/\s/.test(token)) {
throw new DOMEx(
"INVALID_CHARACTER_ERR", "String contains an invalid character"
);
}
return arrIndexOf.call(classList, token);
},
ClassList = function (elem) {
var
trimmedClasses = strTrim.call(elem.getAttribute("class") || ""),
classes = trimmedClasses ? trimmedClasses.split(/\s+/) : [],
i = 0,
len = classes.length;
for (; i < len; i++) {
this.push(classes[i]);
}
this._updateClassName = function () {
elem.setAttribute("class", this.toString());
};
},
classListProto = ClassList[protoProp] = [],
classListGetter = function () {
return new ClassList(this);
};
// Most DOMException implementations don't allow calling DOMException's toString()
// on non-DOMExceptions. Error's toString() is sufficient here.
DOMEx[protoProp] = Error[protoProp];
classListProto.item = function (i) {
return this[i] || null;
};
classListProto.contains = function (token) {
token += "";
return checkTokenAndGetIndex(this, token) !== -1;
};
classListProto.add = function () {
var
tokens = arguments,
i = 0,
l = tokens.length,
token, updated = false;
do {
token = tokens[i] + "";
if (checkTokenAndGetIndex(this, token) === -1) {
this.push(token);
updated = true;
}
}
while (++i < l);
if (updated) {
this._updateClassName();
}
};
classListProto.remove = function () {
var
tokens = arguments,
i = 0,
l = tokens.length,
token, updated = false,
index;
do {
token = tokens[i] + "";
index = checkTokenAndGetIndex(this, token);
while (index !== -1) {
this.splice(index, 1);
updated = true;
index = checkTokenAndGetIndex(this, token);
}
}
while (++i < l);
if (updated) {
this._updateClassName();
}
};
classListProto.toggle = function (token, force) {
token += "";
var
result = this.contains(token),
method = result ?
force !== true && "remove" :
force !== false && "add";
if (method) {
this[method](token);
}
if (force === true || force === false) {
return force;
} else {
return !result;
}
};
classListProto.toString = function () {
return this.join(" ");
};
if (objCtr.defineProperty) {
var classListPropDesc = {
get: classListGetter,
enumerable: true,
configurable: true
};
try {
objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
} catch (ex) { // IE 8 doesn't support enumerable:true
if (ex.number === -0x7FF5EC54) {
classListPropDesc.enumerable = false;
objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
}
}
} else if (objCtr[protoProp].__defineGetter__) {
elemCtrProto.__defineGetter__(classListProp, classListGetter);
}
}(self));
} else {
// There is full or partial native classList support, so just check if we need
// to normalize the add/remove and toggle APIs.
(function () {
"use strict";
var testElement = document.createElement("_");
testElement.classList.add("c1", "c2");
// Polyfill for IE 10/11 and Firefox <26, where classList.add and
// classList.remove exist but support only one argument at a time.
if (!testElement.classList.contains("c2")) {
var createMethod = function (method) {
var original = DOMTokenList.prototype[method];
DOMTokenList.prototype[method] = function (token) {
var i, len = arguments.length;
for (i = 0; i < len; i++) {
token = arguments[i];
original.call(this, token);
}
};
};
createMethod('add');
createMethod('remove');
}
testElement.classList.toggle("c3", false);
// Polyfill for IE 10 and Firefox <24, where classList.toggle does not
// support the second argument.
if (testElement.classList.contains("c3")) {
var _toggle = DOMTokenList.prototype.toggle;
DOMTokenList.prototype.toggle = function (token, force) {
if (1 in arguments && !this.contains(token) === !force) {
return force;
} else {
return _toggle.call(this, token);
}
};
}
testElement = null;
}());
}
}
If you're using jQuery, you can use toggleClass():
function ShowHideDtls(itId) {
$('#' + itId).toggleClass('in');
}
Edit
If you still want to use regex:
if (/\bin\b/.test(subMen.className))
subMen.className.replace(/\bin\b/, '');
} else {
subMen.className += " in";
}
You can also use split() and indexOf as follow to check if a class is present on element.
var classes = className.split(/\s+/),
classIndex = classes.indexOf('in');
if (classIndex > -1) {
classes.splice(classIndex, 1);
subMen.className = classes.join(' ');
} else {
subMen.className += " in";
}
replace function returns the resultant value, it do not assign value indirectly.
So do following:
function ShowHideDtls(itId) {
var subMen = document.getElementById(itId);
if (subMen != null) {
if (subMen.className.match(/(?:^|\s)in(?!\S)/)) {
subMen.className = subMen.className.replace(/(?:^|\s)in(?!\S)/g, '');
}
else {
subMen.className += " in";
}
}
}

Unable to display the PDF object in IE8

I would like to request help to resolve an IE browser incompatibility issue which is facing in ASP.Net MVC application. One of the pages of the application contains a link which displays a PDF. In IE8, the page shows an error ("Internet explorer cannot display this page" or Blank page). However, i am able to access the pdf in Google Chrome, Mozilla Firefox and IE9.
Actually, I need to display PDF in IE8.
If anyone has faced a similar issue before or have any resolutions, could you please help us resolve this? i tried out a couple of options, but could not resolve it with that.
HTML
<div id="pdf1" class="message_details_pdf"></div>
Java script Code
var myPDF = new PDFObject({
url: 'my_pdf_url',
pdfOpenParams: {
view: 'Fit',
scrollbars: '0',
toolbar: '0',
statusbar: '0',
navpanes: '0'
}
}).embed("pdf1");
I faced a problem similar to yours, but I was fighting against IE11. I added some lines of code to pdfobject.js to solve my problem. I do not know if this works with IE8, but I assume my mod can help you in some way.
Search the mods by finding "//#" without quotes, in the code below. Hope this helps.
var PDFObject = function (obj)
{
if (!obj || !obj.url) { return false; }
var pdfobjectversion = "1.2",
//Set reasonable defaults
id = obj.id || false,
width = obj.width || "100%",
height = obj.height || "100%",
pdfOpenParams = obj.pdfOpenParams,
url,
pluginTypeFound;
/* ----------------------------------------------------
Supporting functions
---------------------------------------------------- */
//Tests specifically for Adobe Reader (aka Acrobat) in Internet Explorer
var hasReaderActiveX = function ()
{
var axObj = null;
if (window.ActiveXObject)
{
axObj = new ActiveXObject("AcroPDF.PDF");
//If "AcroPDF.PDF" didn't work, try "PDF.PdfCtrl"
if (!axObj) { axObj = new ActiveXObject("PDF.PdfCtrl"); }
//If either "AcroPDF.PDF" or "PDF.PdfCtrl" are found, return true
if (axObj !== null) { return true; }
}
//If you got to this point, there's no ActiveXObject for PDFs
return false;
};
//Tests specifically for Adobe Reader (aka Adobe Acrobat) in non-IE browsers
var hasReader = function ()
{
var i,
n = navigator.plugins,
count = n.length,
regx = /Adobe Reader|Adobe PDF|Acrobat/gi;
for (i = 0; i < count; i++) { if (regx.test(n[i].name)) { return true; } }
return false;
};
//Detects unbranded PDF support
var hasGeneric = function ()
{
var plugin = navigator.mimeTypes["application/pdf"];
return (plugin && plugin.enabledPlugin);
};
//# ===============================================
//# taken from http://www.quirksmode.org/js/detect.html
//# ===============================================
var BrowserDetect = {
init: function () {
this.browser = this.searchString(this.dataBrowser) || "Other";
this.version = this.searchVersion(navigator.userAgent) || this.searchVersion(navigator.appVersion) || "Unknown";
},
searchString: function (data) {
for (var i = 0; i < data.length; i++) {
var dataString = data[i].string;
this.versionSearchString = data[i].subString;
if (dataString.indexOf(data[i].subString) !== -1) {
return data[i].identity;
}
}
},
searchVersion: function (dataString) {
var index = dataString.indexOf(this.versionSearchString);
if (index === -1) {
return;
}
var rv = dataString.indexOf("rv:");
if (this.versionSearchString === "Trident" && rv !== -1) {
return parseFloat(dataString.substring(rv + 3));
} else {
return parseFloat(dataString.substring(index + this.versionSearchString.length + 1));
}
},
dataBrowser: [{string: navigator.userAgent,subString: "Chrome",identity: "Chrome"}, {string: navigator.userAgent,subString: "MSIE",identity: "Explorer"}, {string: navigator.userAgent,subString: "Trident",identity: "Explorer"}, {string: navigator.userAgent,subString: "Firefox",identity: "Firefox"}, {string: navigator.userAgent,subString: "Safari",identity: "Safari"}, {string: navigator.userAgent,subString: "Opera",identity: "Opera"}]
};
//# END===============================================
//Determines what kind of PDF support is available: Adobe or generic
var pluginFound = function ()
{
var type = null;
var versione = null;
//# ===============================================
//# Start browser detecting
//# ===============================================
BrowserDetect.init();
if (hasReader() || hasReaderActiveX())
{
type = "Adobe";
version = null;
} else if (hasGeneric())
{
type = "generic";
version = null;
//# ===============================================
//# ...check if explorer
//# ===============================================
} else if (BrowserDetect.browser == 'Explorer')
{
type = "IE";
version = BrowserDetect.version;
}
return {'type': type,'version': version};
};
//If setting PDF to fill page, need to handle some CSS first
var setCssForFullWindowPdf = function ()
{
var html = document.getElementsByTagName("html");
if (!html) { return false; }
var html_style = html[0].style,
body_style = document.body.style;
html_style.height = "100%";
html_style.overflow = "hidden";
body_style.margin = "0";
body_style.padding = "0";
body_style.height = "100%";
body_style.overflow = "hidden";
};
//Creating a querystring for using PDF Open parameters when embedding PDF
var buildQueryString = function (pdfParams)
{
var string = "",
prop;
if (!pdfParams) { return string; }
for (prop in pdfParams) {
if (pdfParams.hasOwnProperty(prop)) {
string += prop + "=";
if (prop === "search") {
string += encodeURI(pdfParams[prop]);
} else {
string += pdfParams[prop];
}
string += "&";
}
}
//Remove last ampersand
return string.slice(0, string.length - 1);
};
//Simple function for returning values from PDFObject
var get = function (prop)
{
var value = null;
switch (prop) {
case "url":
value = url;
break;
case "id":
value = id;
break;
case "width":
value = width;
break;
case "height":
value = height;
break;
case "pdfOpenParams":
value = pdfOpenParams;
break;
case "pluginTypeFound":
value = pluginTypeFound;
break;
case "pdfobjectversion":
value = pdfobjectversion;
break;
}
return value;
};
/* ----------------------------------------------------
PDF Embedding functions
---------------------------------------------------- */
var embed = function (targetID)
{
if (!pluginTypeFound) { return false; }
var targetNode = null;
if (targetID)
{
//Allow users to pass an element OR an element's ID
targetNode = (targetID.nodeType && targetID.nodeType === 1) ? targetID : document.getElementById(targetID);
//Ensure target element is found in document before continuing
if (!targetNode) {
return false;
}
} else
{
targetNode = document.body;
setCssForFullWindowPdf();
width = "100%";
height = "100%";
}
//# ===============================================
//# ...and, if explorer found, write an iframe instead of an object
//# ===============================================
if (pluginTypeFound == 'IE')
{
targetNode.innerHTML = '<iframe type="application/pdf" width="' + width + '" height="' + height + '" src="' + url + '"><p>nineoclick</p></iframe>';
} else
{
targetNode.innerHTML = '<object data="' + url + '" type="application/pdf" width="' + width + '" height="' + height + '" style="z-index:800 !important;"></object>';
}
return targetNode.getElementsByTagName("object")[0];
};
//The hash (#) prevents odd behavior in Windows
//Append optional Adobe params for opening document
url = encodeURI(obj.url) + "#" + buildQueryString(pdfOpenParams);
plugin = pluginFound();
pluginTypeFound = plugin.type;
pluginVersionFound = plugin.version;
this.get = function (prop) {
return get(prop);
};
this.embed = function (id) {
return embed(id);
};
return this;
};

Categories

Resources