Having problem overriding Sizzle()
We encountered "SCRIPT70: Permission denied" exception in IE apparently, our fix is to hack our current version of jquery however we dont want to modify original Sizzle()
(function ($) {
$.fn.Sizzle = function (selector, context, results, seed) {
var match, elem, m, nodeType,
// QSA vars
i, groups, old, nid, newContext, newSelector;
// This try/catch seems to fix IE 'permission denied' errors as described here:
// http://bugs.jquery.com/ticket/14535
try {
document === document; //may cause permission denied
}
catch (err) {
document = window.document; //resets document, and no more permission denied errors.
}
if ((context ? context.ownerDocument || context : preferredDoc) !== document) {
setDocument(context);
}
context = context || document;
results = results || [];
if (!selector || typeof selector !== "string") {
return results;
}
if ((nodeType = context.nodeType) !== 1 && nodeType !== 9) {
return [];
}
if (!documentIsXML && !seed) {
// Shortcuts
if ((match = rquickExpr.exec(selector))) {
// Speed-up: Sizzle("#ID")
if ((m = match[1])) {
if (nodeType === 9) {
elem = context.getElementById(m);
// Check parentNode to catch when Blackberry 4.6 returns
// nodes that are no longer in the document #6963
if (elem && elem.parentNode) {
// Handle the case where IE, Opera, and Webkit return items
// by name instead of ID
if (elem.id === m) {
results.push(elem);
return results;
}
} else {
return results;
}
} else {
// Context is not a document
if (context.ownerDocument && (elem = context.ownerDocument.getElementById(m)) &&
contains(context, elem) && elem.id === m) {
results.push(elem);
return results;
}
}
// Speed-up: Sizzle("TAG")
} else if (match[2]) {
push.apply(results, slice.call(context.getElementsByTagName(selector), 0));
return results;
// Speed-up: Sizzle(".CLASS")
} else if ((m = match[3]) && support.getByClassName && context.getElementsByClassName) {
push.apply(results, slice.call(context.getElementsByClassName(m), 0));
return results;
}
}
// QSA path
if (support.qsa && !rbuggyQSA.test(selector)) {
old = true;
nid = expando;
newContext = context;
newSelector = nodeType === 9 && selector;
// qSA works strangely on Element-rooted queries
// We can work around this by specifying an extra ID on the root
// and working up from there (Thanks to Andrew Dupont for the technique)
// IE 8 doesn't work on object elements
if (nodeType === 1 && context.nodeName.toLowerCase() !== "object") {
groups = tokenize(selector);
if ((old = context.getAttribute("id"))) {
nid = old.replace(rescape, "\\$&");
} else {
context.setAttribute("id", nid);
}
nid = "[id='" + nid + "'] ";
i = groups.length;
while (i--) {
groups[i] = nid + toSelector(groups[i]);
}
newContext = rsibling.test(selector) && context.parentNode || context;
newSelector = groups.join(",");
}
if (newSelector) {
try {
push.apply(results, slice.call(newContext.querySelectorAll(
newSelector
), 0));
return results;
} catch (qsaError) {
} finally {
if (!old) {
context.removeAttribute("id");
}
}
}
}
}
// All others
return select(selector.replace(rtrim, "$1"), context, results, seed);
};
}(jQuery));
Ref: https://bugs.jquery.com/ticket/14535
https://bugs.jquery.com/ticket/14535#comment:11
Related
I'm using xml2json for the first time to get an review feed to populate on a website and I keep getting errors such as;
Uncaught ReferenceError: X2JS is not defined
and
Uncaught TypeError: Cannot set property 'X2JS' of undefined
I can't seem to find a solution, this is the code;
jQuery(document).ready(function() {
//below here
//API Feed for Testimonials
(function (root, factory) {
if (typeof define === "function" && define.amd) {
define([], factory);
} else if (typeof exports === "object") {
module.exports = factory();
} else {
root.X2JS = factory();
}
}(this, function () {
return function (config) {
'use strict';
var VERSION = "1.2.0";
config = config || {};
initConfigDefaults();
initRequiredPolyfills();
function initConfigDefaults() {
if(config.escapeMode === undefined) {
config.escapeMode = true;
}
config.attributePrefix = config.attributePrefix || "_";
config.arrayAccessForm = config.arrayAccessForm || "none";
config.emptyNodeForm = config.emptyNodeForm || "text";
if(config.enableToStringFunc === undefined) {
config.enableToStringFunc = true;
}
config.arrayAccessFormPaths = config.arrayAccessFormPaths || [];
if(config.skipEmptyTextNodesForObj === undefined) {
config.skipEmptyTextNodesForObj = true;
}
if(config.stripWhitespaces === undefined) {
config.stripWhitespaces = true;
}
config.datetimeAccessFormPaths = config.datetimeAccessFormPaths || [];
if(config.useDoubleQuotes === undefined) {
config.useDoubleQuotes = false;
}
config.xmlElementsFilter = config.xmlElementsFilter || [];
config.jsonPropertiesFilter = config.jsonPropertiesFilter || [];
if(config.keepCData === undefined) {
config.keepCData = false;
}
}
var DOMNodeTypes = {
ELEMENT_NODE : 1,
TEXT_NODE : 3,
CDATA_SECTION_NODE : 4,
COMMENT_NODE : 8,
DOCUMENT_NODE : 9
};
function initRequiredPolyfills() {
}
function getNodeLocalName( node ) {
var nodeLocalName = node.localName;
if(nodeLocalName == null) // Yeah, this is IE!!
nodeLocalName = node.baseName;
if(nodeLocalName == null || nodeLocalName=="") // =="" is IE too
nodeLocalName = node.nodeName;
return nodeLocalName;
}
function getNodePrefix(node) {
return node.prefix;
}
function escapeXmlChars(str) {
if(typeof(str) == "string")
return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, ''');
else
return str;
}
function unescapeXmlChars(str) {
return str.replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, "'").replace(/&/g, '&');
}
function checkInStdFiltersArrayForm(stdFiltersArrayForm, obj, name, path) {
var idx = 0;
for(; idx < stdFiltersArrayForm.length; idx++) {
var filterPath = stdFiltersArrayForm[idx];
if( typeof filterPath === "string" ) {
if(filterPath == path)
break;
}
else
if( filterPath instanceof RegExp) {
if(filterPath.test(path))
break;
}
else
if( typeof filterPath === "function") {
if(filterPath(obj, name, path))
break;
}
}
return idx!=stdFiltersArrayForm.length;
}
function toArrayAccessForm(obj, childName, path) {
switch(config.arrayAccessForm) {
case "property":
if(!(obj[childName] instanceof Array))
obj[childName+"_asArray"] = [obj[childName]];
else
obj[childName+"_asArray"] = obj[childName];
break;
/*case "none":
break;*/
}
if(!(obj[childName] instanceof Array) && config.arrayAccessFormPaths.length > 0) {
if(checkInStdFiltersArrayForm(config.arrayAccessFormPaths, obj, childName, path)) {
obj[childName] = [obj[childName]];
}
}
}
function fromXmlDateTime(prop) {
// Implementation based up on http://stackoverflow.com/questions/8178598/xml-datetime-to-javascript-date-object
// Improved to support full spec and optional parts
var bits = prop.split(/[-T:+Z]/g);
var d = new Date(bits[0], bits[1]-1, bits[2]);
var secondBits = bits[5].split("\.");
d.setHours(bits[3], bits[4], secondBits[0]);
if(secondBits.length>1)
d.setMilliseconds(secondBits[1]);
// Get supplied time zone offset in minutes
if(bits[6] && bits[7]) {
var offsetMinutes = bits[6] * 60 + Number(bits[7]);
var sign = /\d\d-\d\d:\d\d$/.test(prop)? '-' : '+';
// Apply the sign
offsetMinutes = 0 + (sign == '-'? -1 * offsetMinutes : offsetMinutes);
// Apply offset and local timezone
d.setMinutes(d.getMinutes() - offsetMinutes - d.getTimezoneOffset())
}
else
if(prop.indexOf("Z", prop.length - 1) !== -1) {
d = new Date(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(), d.getMinutes(), d.getSeconds(), d.getMilliseconds()));
}
// d is now a local time equivalent to the supplied time
return d;
}
function checkFromXmlDateTimePaths(value, childName, fullPath) {
if(config.datetimeAccessFormPaths.length > 0) {
var path = fullPath.split("\.#")[0];
if(checkInStdFiltersArrayForm(config.datetimeAccessFormPaths, value, childName, path)) {
return fromXmlDateTime(value);
}
else
return value;
}
else
return value;
}
function checkXmlElementsFilter(obj, childType, childName, childPath) {
if( childType == DOMNodeTypes.ELEMENT_NODE && config.xmlElementsFilter.length > 0) {
return checkInStdFiltersArrayForm(config.xmlElementsFilter, obj, childName, childPath);
}
else
return true;
}
function parseDOMChildren( node, path ) {
if(node.nodeType == DOMNodeTypes.DOCUMENT_NODE) {
var result = new Object;
var nodeChildren = node.childNodes;
// Alternative for firstElementChild which is not supported in some environments
for(var cidx=0; cidx <nodeChildren.length; cidx++) {
var child = nodeChildren.item(cidx);
if(child.nodeType == DOMNodeTypes.ELEMENT_NODE) {
var childName = getNodeLocalName(child);
result[childName] = parseDOMChildren(child, childName);
}
}
return result;
}
else
if(node.nodeType == DOMNodeTypes.ELEMENT_NODE) {
var result = new Object;
result.__cnt=0;
var nodeChildren = node.childNodes;
// Children nodes
for(var cidx=0; cidx <nodeChildren.length; cidx++) {
var child = nodeChildren.item(cidx); // nodeChildren[cidx];
var childName = getNodeLocalName(child);
if(child.nodeType!= DOMNodeTypes.COMMENT_NODE) {
var childPath = path+"."+childName;
if (checkXmlElementsFilter(result,child.nodeType,childName,childPath)) {
result.__cnt++;
if(result[childName] == null) {
result[childName] = parseDOMChildren(child, childPath);
toArrayAccessForm(result, childName, childPath);
}
else {
if(result[childName] != null) {
if( !(result[childName] instanceof Array)) {
result[childName] = [result[childName]];
toArrayAccessForm(result, childName, childPath);
}
}
(result[childName])[result[childName].length] = parseDOMChildren(child, childPath);
}
}
}
}
// Attributes
for(var aidx=0; aidx <node.attributes.length; aidx++) {
var attr = node.attributes.item(aidx); // [aidx];
result.__cnt++;
result[config.attributePrefix+attr.name]=attr.value;
}
// Node namespace prefix
var nodePrefix = getNodePrefix(node);
if(nodePrefix!=null && nodePrefix!="") {
result.__cnt++;
result.__prefix=nodePrefix;
}
if(result["#text"]!=null) {
result.__text = result["#text"];
if(result.__text instanceof Array) {
result.__text = result.__text.join("\n");
}
//if(config.escapeMode)
// result.__text = unescapeXmlChars(result.__text);
if(config.stripWhitespaces)
result.__text = result.__text.trim();
delete result["#text"];
if(config.arrayAccessForm=="property")
delete result["#text_asArray"];
result.__text = checkFromXmlDateTimePaths(result.__text, childName, path+"."+childName);
}
if(result["#cdata-section"]!=null) {
result.__cdata = result["#cdata-section"];
delete result["#cdata-section"];
if(config.arrayAccessForm=="property")
delete result["#cdata-section_asArray"];
}
if( result.__cnt == 0 && config.emptyNodeForm=="text" ) {
result = '';
}
else
if( result.__cnt == 1 && result.__text!=null ) {
result = result.__text;
}
else
if( result.__cnt == 1 && result.__cdata!=null && !config.keepCData ) {
result = result.__cdata;
}
else
if ( result.__cnt > 1 && result.__text!=null && config.skipEmptyTextNodesForObj) {
if( (config.stripWhitespaces && result.__text=="") || (result.__text.trim()=="")) {
delete result.__text;
}
}
delete result.__cnt;
if( config.enableToStringFunc && (result.__text!=null || result.__cdata!=null )) {
result.toString = function() {
return (this.__text!=null? this.__text:'')+( this.__cdata!=null ? this.__cdata:'');
};
}
return result;
}
else
if(node.nodeType == DOMNodeTypes.TEXT_NODE || node.nodeType == DOMNodeTypes.CDATA_SECTION_NODE) {
return node.nodeValue;
}
}
function startTag(jsonObj, element, attrList, closed) {
var resultStr = "<"+ ( (jsonObj!=null && jsonObj.__prefix!=null)? (jsonObj.__prefix+":"):"") + element;
if(attrList!=null) {
for(var aidx = 0; aidx < attrList.length; aidx++) {
var attrName = attrList[aidx];
var attrVal = jsonObj[attrName];
if(config.escapeMode)
attrVal=escapeXmlChars(attrVal);
resultStr+=" "+attrName.substr(config.attributePrefix.length)+"=";
if(config.useDoubleQuotes)
resultStr+='"'+attrVal+'"';
else
resultStr+="'"+attrVal+"'";
}
}
if(!closed)
resultStr+=">";
else
resultStr+="/>";
return resultStr;
}
function endTag(jsonObj,elementName) {
return "</"+ (jsonObj.__prefix!=null? (jsonObj.__prefix+":"):"")+elementName+">";
}
function endsWith(str, suffix) {
return str.indexOf(suffix, str.length - suffix.length) !== -1;
}
function jsonXmlSpecialElem ( jsonObj, jsonObjField ) {
if((config.arrayAccessForm=="property" && endsWith(jsonObjField.toString(),("_asArray")))
|| jsonObjField.toString().indexOf(config.attributePrefix)==0
|| jsonObjField.toString().indexOf("__")==0
|| (jsonObj[jsonObjField] instanceof Function) )
return true;
else
return false;
}
function jsonXmlElemCount ( jsonObj ) {
var elementsCnt = 0;
if(jsonObj instanceof Object ) {
for( var it in jsonObj ) {
if(jsonXmlSpecialElem ( jsonObj, it) )
continue;
elementsCnt++;
}
}
return elementsCnt;
}
function checkJsonObjPropertiesFilter(jsonObj, propertyName, jsonObjPath) {
return config.jsonPropertiesFilter.length == 0
|| jsonObjPath==""
|| checkInStdFiltersArrayForm(config.jsonPropertiesFilter, jsonObj, propertyName, jsonObjPath);
}
function parseJSONAttributes ( jsonObj ) {
var attrList = [];
if(jsonObj instanceof Object ) {
for( var ait in jsonObj ) {
if(ait.toString().indexOf("__")== -1 && ait.toString().indexOf(config.attributePrefix)==0) {
attrList.push(ait);
}
}
}
return attrList;
}
function parseJSONTextAttrs ( jsonTxtObj ) {
var result ="";
if(jsonTxtObj.__cdata!=null) {
result+="<![CDATA["+jsonTxtObj.__cdata+"]]>";
}
if(jsonTxtObj.__text!=null) {
if(config.escapeMode)
result+=escapeXmlChars(jsonTxtObj.__text);
else
result+=jsonTxtObj.__text;
}
return result;
}
function parseJSONTextObject ( jsonTxtObj ) {
var result ="";
if( jsonTxtObj instanceof Object ) {
result+=parseJSONTextAttrs ( jsonTxtObj );
}
else
if(jsonTxtObj!=null) {
if(config.escapeMode)
result+=escapeXmlChars(jsonTxtObj);
else
result+=jsonTxtObj;
}
return result;
}
function getJsonPropertyPath(jsonObjPath, jsonPropName) {
if (jsonObjPath==="") {
return jsonPropName;
}
else
return jsonObjPath+"."+jsonPropName;
}
function parseJSONArray ( jsonArrRoot, jsonArrObj, attrList, jsonObjPath ) {
var result = "";
if(jsonArrRoot.length == 0) {
result+=startTag(jsonArrRoot, jsonArrObj, attrList, true);
}
else {
for(var arIdx = 0; arIdx < jsonArrRoot.length; arIdx++) {
result+=startTag(jsonArrRoot[arIdx], jsonArrObj, parseJSONAttributes(jsonArrRoot[arIdx]), false);
result+=parseJSONObject(jsonArrRoot[arIdx], getJsonPropertyPath(jsonObjPath,jsonArrObj));
result+=endTag(jsonArrRoot[arIdx],jsonArrObj);
}
}
return result;
}
function parseJSONObject ( jsonObj, jsonObjPath ) {
var result = "";
var elementsCnt = jsonXmlElemCount ( jsonObj );
if(elementsCnt > 0) {
for( var it in jsonObj ) {
if(jsonXmlSpecialElem ( jsonObj, it) || (jsonObjPath!="" && !checkJsonObjPropertiesFilter(jsonObj, it, getJsonPropertyPath(jsonObjPath,it))) )
continue;
var subObj = jsonObj[it];
var attrList = parseJSONAttributes( subObj )
if(subObj == null || subObj == undefined) {
result+=startTag(subObj, it, attrList, true);
}
else
if(subObj instanceof Object) {
if(subObj instanceof Array) {
result+=parseJSONArray( subObj, it, attrList, jsonObjPath );
}
else if(subObj instanceof Date) {
result+=startTag(subObj, it, attrList, false);
result+=subObj.toISOString();
result+=endTag(subObj,it);
}
else {
var subObjElementsCnt = jsonXmlElemCount ( subObj );
if(subObjElementsCnt > 0 || subObj.__text!=null || subObj.__cdata!=null) {
result+=startTag(subObj, it, attrList, false);
result+=parseJSONObject(subObj, getJsonPropertyPath(jsonObjPath,it));
result+=endTag(subObj,it);
}
else {
result+=startTag(subObj, it, attrList, true);
}
}
}
else {
result+=startTag(subObj, it, attrList, false);
result+=parseJSONTextObject(subObj);
result+=endTag(subObj,it);
}
}
}
result+=parseJSONTextObject(jsonObj);
return result;
}
this.parseXmlString = function(xmlDocStr) {
var isIEParser = window.ActiveXObject || "ActiveXObject" in window;
if (xmlDocStr === undefined) {
return null;
}
var xmlDoc;
if (window.DOMParser) {
var parser=new window.DOMParser();
var parsererrorNS = null;
// IE9+ now is here
if(!isIEParser) {
try {
parsererrorNS = parser.parseFromString("INVALID", "text/xml").getElementsByTagName("parsererror")[0].namespaceURI;
}
catch(err) {
parsererrorNS = null;
}
}
try {
xmlDoc = parser.parseFromString( xmlDocStr, "text/xml" );
if( parsererrorNS!= null && xmlDoc.getElementsByTagNameNS(parsererrorNS, "parsererror").length > 0) {
//throw new Error('Error parsing XML: '+xmlDocStr);
xmlDoc = null;
}
}
catch(err) {
xmlDoc = null;
}
}
else {
// IE :(
if(xmlDocStr.indexOf("<?")==0) {
xmlDocStr = xmlDocStr.substr( xmlDocStr.indexOf("?>") + 2 );
}
xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async="false";
xmlDoc.loadXML(xmlDocStr);
}
return xmlDoc;
};
this.asArray = function(prop) {
if (prop === undefined || prop == null)
return [];
else
if(prop instanceof Array)
return prop;
else
return [prop];
};
this.toXmlDateTime = function(dt) {
if(dt instanceof Date)
return dt.toISOString();
else
if(typeof(dt) === 'number' )
return new Date(dt).toISOString();
else
return null;
};
this.asDateTime = function(prop) {
if(typeof(prop) == "string") {
return fromXmlDateTime(prop);
}
else
return prop;
};
this.xml2json = function (xmlDoc) {
return parseDOMChildren ( xmlDoc );
};
this.xml_str2json = function (xmlDocStr) {
var xmlDoc = this.parseXmlString(xmlDocStr);
if(xmlDoc!=null)
return this.xml2json(xmlDoc);
else
return null;
};
this.json2xml_str = function (jsonObj) {
return parseJSONObject ( jsonObj, "" );
};
this.json2xml = function (jsonObj) {
var xmlDocStr = this.json2xml_str (jsonObj);
return this.parseXmlString(xmlDocStr);
};
this.getVersion = function () {
return VERSION;
};
}
}))
// Create x2js instance with default config
var x2js = new X2JS();
var xmlText = "";
jQuery.getJSON( "https://service1.homepro.com/smart.asmx/GetFAP_ProfileReviewsJSON?bid=141772&sort=1&page=1", function( data ) {
var xmlText = data,
x2js = new X2JS(),
jsonObj = x2js.xml_str2json( xmlText ),
html = '<div class="flex-wrapper">';
// console.log(jsonObj.SMART);
jQuery.each( jsonObj.SMART.XMLJSON, function( key, answer ) {
html += '<div class="flex-shell testimonial">';
html += '<div class="flex-item">';
html += '<div>';
html += '<span class="review-number"><i>' + answer.Quality + '</i> Quality of work</span>' ;
html += '<span class="review-number"><i>' + answer.Time + '</i> Timeliness</span>' ;
html += '<span class="review-number"><i>' + answer.Budget + '</i> Value for Money</span>' ;
html += '<span class="review-number"><i>' + answer.Courtesy + '</i> Courtesy</span>' ;
html += '<span class="review">' + answer.Testimonial + '</span>' ;
html += '<span class="name">' + answer.RefName + ' - ' + answer.refDate + '</span>';
html += '</div>';
html += '</div>';
html += '</div>';
});
jQuery('.start').html(html);
});
//above here
});
Apologies if I've gone about this in the wrong way. I've done;
npm install xml2json
Which didn't flag up any errors but I still can't seem to get the data to load correctly.
Solution that after you import <script> from package x2js, you should use window.X2JS to get constructor of X2JS. Almost packages implementing for both NPM and browser, the browser version usually use via object window, because it is shared and free connected in almost browsers.
This is my demo for the solution: https://jsfiddle.net/huynhsamha/2evdgt7r/
In my demo, I've include package x2js from NPM here https://unpkg.com/x2js#3.2.3/x2js.js
var X2JS = window.X2JS;
var x2js = new X2JS();
const data = {
a: {
b: 1
},
c: [1, 2]
}
console.log(x2js.js2xml(data))
// <a><b>1</b></a><c>1</c><c>2</c>
I currently have this code built in JS, but it's really, really ugly.
Is there any better way to approach it?
The way it works basically is pushing a string like app.chat.test to be the key, and value like teststr.
I test the lengths to see if the "parent" key is there, otherwise we build it.
function constructJson(jsonKey, jsonValue){
//REWRITE!!!!!!!!
let jsonObj = langFile;
let jsonKeyArr = jsonKey.split('.')
if (jsonKeyArr.length === 1) {
if (valToAdd === undefined) {
if (jsonObj[jsonKey] === undefined) {
jsonObj[jsonKey] = {}
}
} else {
if (jsonObj[jsonKey] === undefined) {
jsonObj[jsonKey] = valToAdd
}
}
} else if (jsonKeyArr.length === 2) {
if (jsonObj[jsonKeyArr[0]] === undefined) {
jsonObj[jsonKeyArr[0]] = {}
}
if (jsonObj[jsonKeyArr[0]][jsonKeyArr[1]] === undefined) {
jsonObj[jsonKeyArr[0]][jsonKeyArr[1]] = jsonValue
}
} else if (jsonKeyArr.length === 3) {
if (jsonObj[jsonKeyArr[0]] === undefined) {
jsonObj[jsonKeyArr[0]] = {}
}
if (jsonObj[jsonKeyArr[0]][jsonKeyArr[1]] === undefined) {
jsonObj[jsonKeyArr[0]][jsonKeyArr[1]] = {}
}
if (jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]] === undefined) {
jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]] = jsonValue
}
} else if (jsonKeyArr.length === 4) {
if (jsonObj[jsonKeyArr[0]] === undefined) {
jsonObj[jsonKeyArr[0]] = {}
}
if (jsonObj[jsonKeyArr[0]][jsonKeyArr[1]] === undefined) {
jsonObj[jsonKeyArr[0]][jsonKeyArr[1]] = {}
}
if (jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]] === undefined) {
jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]] = {}
}
if (jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]][jsonKeyArr[3]] === undefined) {
jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]][jsonKeyArr[3]] = jsonValue
}
} else if (jsonKeyArr.length === 5) {
if (jsonObj[jsonKeyArr[0]] === undefined) {
jsonObj[jsonKeyArr[0]] = {}
}
if (jsonObj[jsonKeyArr[0]][jsonKeyArr[1]] === undefined) {
jsonObj[jsonKeyArr[0]][jsonKeyArr[1]] = {}
}
if (jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]] === undefined) {
jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]] = {}
}
if (jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]][jsonKeyArr[3]] === undefined) {
jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]][jsonKeyArr[3]] = {}
}
if (jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]][jsonKeyArr[3]][jsonKeyArr[4]] === undefined) {
jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]][jsonKeyArr[3]][jsonKeyArr[4]] = jsonValue
}
} else if (jsonKeyArr.length > 5) {
return console.log("Length over 5 not supported yet!")
}
return jsonObj;
}
Regards.
OF course it's possible, a simple loop will perfeclty do the job.
function constructJson(jsonKey, jsonValue){
//REWRITE!!!!!!!!
langFile = {a:{}, foo:{}};// remove this for your own code
var jsonObj = langFile;
var jsonKeyArr = jsonKey.split('.');
var currentValue = jsonObj;
for(var i = 0; i < jsonKeyArr.length;i++){
if(currentValue[jsonKeyArr[i]]===undefined){
currentValue[jsonKeyArr[i]] = {};
}
if(i < jsonKeyArr.length-1){
currentValue = currentValue[jsonKeyArr[i]];
}else{
currentValue[jsonKeyArr[i]] = jsonValue;
}
}
return jsonObj;
}
alert(JSON.stringify(constructJson("a.b.cd.ef", "toto")));
I just assigning to a temporary variable each sublevel. When i'm on the last i'm assigning the value.
Yes you can, using the javascript reduce function on the array created from the splitted string.
function namespaceCreateExceptLast(representationOfElementToCreate, baseNamespace) {
var tokens;
if (typeof representationOfElementToCreate !== 'string')
throw new Error('Expecting string as first parameter');
if (baseNamespace === undefined)
baseNamespace = window;
tokens = representationOfElementToCreate.split('.');
// Remove the last element (which will contain the value)
tokens.pop();
// Use reduce to create part by part your new object
return tokens.reduce(function (prev, property) {
if (typeof prev !== 'object') {
throw Error('One property is already defined but not an object, namespace creation has failed', property);
return undefined;
} else {
if (!prev[property])
prev[property] = {};
return prev[property];
}
}, baseNamespace);
};
Then you can have:
function constructJson(jsonKey, jsonValue){
let jsonObj = langFile;
var lastItem = namespaceCreateExceptLast(jsonKey, jsonObj);
var lastKey = jsonKey.substring(jsonKey.lastIndexOf('.') + 1);
lastItem[lastKey] = jsonValue;
}
I have added some comments and exceptions to help you understand how it's done, but it's mainly based on the reduce function which you can easily get help for (https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Array/reduce).
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")]/..');
I am writing a custom method to return the DOM element reference but it seems to work on all modern browsers such as Chrome,Firefox,Safari but fails in IE 9 ... returned element is undefined it states i am not sure what i am doing wrong
var searchEle = function (parent, ref) {
var refEle;
if (typeof document.getElementByClassName === "function") {
if (ref.substr(0, 1) === ".") {
refEle = parent.getElementsByClassName(ref.replace(".", ""));
} else {
refEle = parent.getElementsByTagName(ref);
}
} else {
if (ref.substr(0, 1) === "#") {
refEle = parent.getElementById(ref.replace("#", ""));
} else if (ref.substr(0, 1) === ".") {
refEle = parent.querySelector(ref);
}
}
return refEle;
};
Check out demo here on IE9: http://jsbin.com/ubokop/5/edit
Thanks
First of all, use this polyfill for getElementsByClassName, since that's really the only function that requires one. It's not perfect, but it's close enough.
// Add a getElementsByClassName function if the browser doesn't have one
// Limitation: only works with one class name
// Copyright: Eike Send http://eike.se/nd
// License: MIT License
if (!document.getElementsByClassName) {
document.getElementsByClassName = function(search) {
var d = document, elements, pattern, i, results = [];
if (d.querySelectorAll) { // IE8
return d.querySelectorAll("." + search);
}
if (d.evaluate) { // IE6, IE7
pattern = ".//*[contains(concat(' ', #class, ' '), ' " + search + " ')]";
elements = d.evaluate(pattern, d, null, 0, null);
while (i = elements.iterateNext()) {
results.push(i);
}
} else {
elements = d.getElementsByTagName("*");
pattern = new RegExp("(^|\\s)" + search + "(\\s|$)");
for (i = 0; i < elements.length; i++) {
if ( pattern.test(elements[i].className) ) {
results.push(elements[i]);
}
}
}
return results;
}
}
(Source of this polyfill)
Then, this would be enough:
var searchEle = function (ref) {
if (ref.charAt(0) === "#") {
return document.getElementById(ref.substr(1));
}else if (ref.charAt(0) === ".") {
return document.getElementsByClassName(ref.substr(1));
}else{
return document.getElementsByTagName(ref);
}
};
I have searched high and low on the Interwebs, and found some really awesome JS code editors with syntax highlighting and indentation and more... but none seem to have support for Smarty template tags yet.
A new Smarty mode for CodeMirror would be the best, but I'll use a different editor if I need to.
I did find this blog post... but it is VERY simple, and I would like to still support mixed HTML/CSS/JS highlighting, like the PHP mode for CodeMirror.
I just thought I would check with the SO hive mind before embarking on rolling my own CodeMirror mode. If I do make a new mode (and get anywhere with it) I'll post it here.
Thanks!
I made some tries to get a mixed mode with smarty and although my work is not perfect, so far it works well enough for me. I started from de htmlmixedmode to add a smarty mode :
CodeMirror.defineMode("smartymixed", function(config, parserConfig) {
var htmlMode = CodeMirror.getMode(config, {name: "xml", htmlMode: true});
var smartyMode = CodeMirror.getMode(config, "smarty");
var jsMode = CodeMirror.getMode(config, "javascript");
var cssMode = CodeMirror.getMode(config, "css");
function html(stream, state) {
var style = htmlMode.token(stream, state.htmlState);
if (style == "tag" && stream.current() == ">" && state.htmlState.context) {
if (/^script$/i.test(state.htmlState.context.tagName)) {
state.token = javascript;
state.localState = jsMode.startState(htmlMode.indent(state.htmlState, ""));
state.mode = "javascript";
}
else if (/^style$/i.test(state.htmlState.context.tagName)) {
state.token = css;
state.localState = cssMode.startState(htmlMode.indent(state.htmlState, ""));
state.mode = "css";
}
}
return style;
}
function maybeBackup(stream, pat, style) {
var cur = stream.current();
var close = cur.search(pat);
if (close > -1) stream.backUp(cur.length - close);
return style;
}
function javascript(stream, state) {
if (stream.match(/^<\/\s*script\s*>/i, false)) {
state.token = html;
state.localState = null;
state.mode = "html";
return html(stream, state);
}
return maybeBackup(stream, /<\/\s*script\s*>/,
jsMode.token(stream, state.localState));
}
function css(stream, state) {
if (stream.match(/^<\/\s*style\s*>/i, false)) {
state.token = html;
state.localState = null;
state.mode = "html";
return html(stream, state);
}
return maybeBackup(stream, /<\/\s*style\s*>/,
cssMode.token(stream, state.localState));
}
function smarty(stream, state) {
style = smartyMode.token(stream, state.localState);
if ( state.localState.tokenize == null )
{ // back to anything from smarty
state.token = state.htmlState.tokens.pop();
state.mode = state.htmlState.modes.pop();
state.localState = state.htmlState.states.pop(); // state.htmlState;
}
return(style);
}
return {
startState: function() {
var state = htmlMode.startState();
state.modes = [];
state.tokens = [];
state.states = [];
return {token: html, localState: null, mode: "html", htmlState: state};
},
copyState: function(state) {
if (state.localState)
var local = CodeMirror.copyState(
( state.token == css ) ? cssMode : (( state.token == javascript ) ? jsMode : smartyMode ),
state.localState);
return {token: state.token, localState: local, mode: state.mode,
htmlState: CodeMirror.copyState(htmlMode, state.htmlState)};
},
token: function(stream, state) {
if ( stream.match(/^{[^ ]{1}/,false) )
{ // leaving anything to smarty
state.htmlState.states.push(state.localState);
state.htmlState.tokens.push(state.token);
state.htmlState.modes.push(state.mode);
state.token = smarty;
state.localState = smartyMode.startState();
state.mode = "smarty";
}
return state.token(stream, state);
},
compareStates: function(a, b) {
if (a.mode != b.mode) return false;
if (a.localState) return CodeMirror.Pass;
return htmlMode.compareStates(a.htmlState, b.htmlState);
},
electricChars: "/{}:"
}
}, "xml", "javascript", "css", "smarty");
CodeMirror.defineMIME("text/html", "smartymixed");
The switch to smarty mode is made in token function only but ...
You also have to patch the other basic modes ( css , javascript & xml ) to stop them on the { character so you can fall back in the token function to test it against a regexp ( { followed by a non blank character ).
This may help. I wrote a Smarty mode for CodeMirror2 this weekend. See:
http://www.benjaminkeen.com/misc/CodeMirror2/mode/smarty/
I've also forked the CodeMirror project with my change here:
https://github.com/benkeen/CodeMirror2
All the best -
Ben
[EDIT: this is now part of the main script. I'll be shortly adding a Smarty/HTML/CSS/JS mode].
The second part of the answer : a patch in benjamin smarty file to be able to leave it and fall back in smartymixedmode. So here is the patched verson of mode/smarty/smarty.js
CodeMirror.defineMode("smarty", function(config, parserConfig) {
var breakOnSmarty = ( config.mode == "smartymixed" ) ? true : false; // we are called in a "smartymixed" context
var keyFuncs = ["debug", "extends", "function", "include", "literal"];
var last;
var regs = {
operatorChars: /[+\-*&%=<>!?]/,
validIdentifier: /[a-zA-Z0-9\_]/,
stringChar: /[\'\"]/
}
var leftDelim = (typeof config.mode.leftDelimiter != 'undefined') ? config.mode.leftDelimiter : "{";
var rightDelim = (typeof config.mode.rightDelimiter != 'undefined') ? config.mode.rightDelimiter : "}";
function ret(style, lst) { last = lst; return style; }
function tokenizer(stream, state) {
function chain(parser) {
state.tokenize = parser;
return parser(stream, state);
}
if (stream.match(leftDelim, true)) {
if (stream.eat("*")) {
return chain(inBlock("comment", "*" + rightDelim));
}
else {
state.tokenize = inSmarty;
return ( breakOnSmarty == true ) ? "bracket" : "tag";
}
}
else {
// I'd like to do an eatWhile() here, but I can't get it to eat only up to the rightDelim string/char
stream.next();
return null;
}
}
function inSmarty(stream, state) {
if (stream.match(rightDelim, true)) {
state.tokenize = ( breakOnSmarty ) ? null : tokenizer;
return ( breakOnSmarty == true ) ? ret("bracket", null) : ret("tag", null);
}
var ch = stream.next();
if (ch == "$") {
stream.eatWhile(regs.validIdentifier);
return ret("variable-2", "variable");
}
else if (ch == ".") {
return ret("operator", "property");
}
else if (regs.stringChar.test(ch)) {
state.tokenize = inAttribute(ch);
return ret("string", "string");
}
else if (regs.operatorChars.test(ch)) {
stream.eatWhile(regs.operatorChars);
return ret("operator", "operator");
}
else if (ch == "[" || ch == "]") {
return ret("bracket", "bracket");
}
else if (/\d/.test(ch)) {
stream.eatWhile(/\d/);
return ret("number", "number");
}
else {
if (state.last == "variable") {
if (ch == "#") {
stream.eatWhile(regs.validIdentifier);
return ret("property", "property");
}
else if (ch == "|") {
stream.eatWhile(regs.validIdentifier);
return ret("qualifier", "modifier");
}
}
else if (state.last == "whitespace") {
stream.eatWhile(regs.validIdentifier);
return ret("attribute", "modifier");
}
else if (state.last == "property") {
stream.eatWhile(regs.validIdentifier);
return ret("property", null);
}
else if (/\s/.test(ch)) {
last = "whitespace";
return null;
}
var str = "";
if (ch != "/") {
str += ch;
}
var c = "";
while ((c = stream.eat(regs.validIdentifier))) {
str += c;
}
var i, j;
for (i=0, j=keyFuncs.length; i<j; i++) {
if (keyFuncs[i] == str) {
return ret("keyword", "keyword");
}
}
if (/\s/.test(ch)) {
return null;
}
return ret("tag", "tag");
}
}
function inAttribute(quote) {
return function(stream, state) {
while (!stream.eol()) {
if (stream.next() == quote) {
state.tokenize = inSmarty;
break;
}
}
return "string";
};
}
function inBlock(style, terminator) {
return function(stream, state) {
while (!stream.eol()) {
if (stream.match(terminator)) {
state.tokenize = ( breakOnSmarty == true ) ? null : tokenizer;
break;
}
stream.next();
}
return style;
};
}
return {
startState: function() {
return { tokenize: tokenizer, mode: "smarty", last: null };
},
token: function(stream, state) {
var style = state.tokenize(stream, state);
state.last = last;
return style;
},
electricChars: ""
}
});
CodeMirror.defineMIME("text/x-smarty", "smarty");
The 1st line check if we are called by the smartymixed mode and tests are made on this contition, allowing smarty mode to run as before.