CKEditor JSON Output [duplicate] - javascript

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 2 years ago.
Improve this question
I'm attempting map HTML into JSON with structure intact. Are there any libraries out there that do this or will I need to write my own? I suppose if there are no html2json libraries out there I could take an xml2json library as a start. After all, html is only a variant of xml anyway right?
UPDATE: Okay, I should probably give an example. What I'm trying to do is the following. Parse a string of html:
<div>
<span>text</span>Text2
</div>
into a json object like so:
{
"type" : "div",
"content" : [
{
"type" : "span",
"content" : [
"Text2"
]
},
"Text2"
]
}
NOTE: In case you didn't notice the tag, I'm looking for a solution in Javascript

I just wrote this function that does what you want; try it out let me know if it doesn't work correctly for you:
// Test with an element.
var initElement = document.getElementsByTagName("html")[0];
var json = mapDOM(initElement, true);
console.log(json);
// Test with a string.
initElement = "<div><span>text</span>Text2</div>";
json = mapDOM(initElement, true);
console.log(json);
function mapDOM(element, json) {
var treeObject = {};
// If string convert to document Node
if (typeof element === "string") {
if (window.DOMParser) {
parser = new DOMParser();
docNode = parser.parseFromString(element,"text/xml");
} else { // Microsoft strikes again
docNode = new ActiveXObject("Microsoft.XMLDOM");
docNode.async = false;
docNode.loadXML(element);
}
element = docNode.firstChild;
}
//Recursively loop through DOM elements and assign properties to object
function treeHTML(element, object) {
object["type"] = element.nodeName;
var nodeList = element.childNodes;
if (nodeList != null) {
if (nodeList.length) {
object["content"] = [];
for (var i = 0; i < nodeList.length; i++) {
if (nodeList[i].nodeType == 3) {
object["content"].push(nodeList[i].nodeValue);
} else {
object["content"].push({});
treeHTML(nodeList[i], object["content"][object["content"].length -1]);
}
}
}
}
if (element.attributes != null) {
if (element.attributes.length) {
object["attributes"] = {};
for (var i = 0; i < element.attributes.length; i++) {
object["attributes"][element.attributes[i].nodeName] = element.attributes[i].nodeValue;
}
}
}
}
treeHTML(element, treeObject);
return (json) ? JSON.stringify(treeObject) : treeObject;
}
Working example: http://jsfiddle.net/JUSsf/ (Tested in Chrome, I can't guarantee full browser support - you will have to test this).
​It creates an object that contains the tree structure of the HTML page in the format you requested and then uses JSON.stringify() which is included in most modern browsers (IE8+, Firefox 3+ .etc); If you need to support older browsers you can include json2.js.
It can take either a DOM element or a string containing valid XHTML as an argument (I believe, I'm not sure whether the DOMParser() will choke in certain situations as it is set to "text/xml" or whether it just doesn't provide error handling. Unfortunately "text/html" has poor browser support).
You can easily change the range of this function by passing a different value as element. Whatever value you pass will be the root of your JSON map.

htlm2json
Representing complex HTML documents will be difficult and full of corner cases, but I just wanted to share a couple techniques to show how to get this kind of program started. This answer differs in that it uses data abstraction and the toJSON method to recursively build the result
Below, html2json is a tiny function which takes an HTML node as input and it returns a JSON string as the result. Pay particular attention to how the code is quite flat but it's still plenty capable of building a deeply nested tree structure – all possible with virtually zero complexity
const Elem = e => ({
tagName:
e.tagName,
textContent:
e.textContent,
attributes:
Array.from(e.attributes, ({name, value}) => [name, value]),
children:
Array.from(e.children, Elem)
})
const html2json = e =>
JSON.stringify(Elem(e), null, ' ')
console.log(html2json(document.querySelector('main')))
<main>
<h1 class="mainHeading">Some heading</h1>
<ul id="menu">
<li>a</li>
<li>b</li>
<li>c</li>
</ul>
<p>some text</p>
</main>
In the previous example, the textContent gets a little butchered. To remedy this, we introduce another data constructor, TextElem. We'll have to map over the childNodes (instead of children) and choose to return the correct data type based on e.nodeType – this gets us a littler closer to what we might need
const TextElem = e => ({
type:
'TextElem',
textContent:
e.textContent
})
const Elem = e => ({
type:
'Elem',
tagName:
e.tagName,
attributes:
Array.from(e.attributes, ({name, value}) => [name, value]),
children:
Array.from(e.childNodes, fromNode)
})
const fromNode = e => {
switch (e?.nodeType) {
case 1: return Elem(e)
case 3: return TextElem(e)
default: throw Error(`unsupported nodeType: ${e.nodeType}`)
}
}
const html2json = e =>
JSON.stringify(Elem(e), null, ' ')
console.log(html2json(document.querySelector('main')))
<main>
<h1 class="mainHeading">Some heading</h1>
<ul id="menu">
<li>a</li>
<li>b</li>
<li>c</li>
</ul>
<p>some text</p>
</main>
Anyway, that's just two iterations on the problem. Of course you'll have to address corner cases where they come up, but what's nice about this approach is that it gives you a lot of flexibility to encode the HTML however you wish in JSON – and without introducing too much complexity
In my experience, you could keep iterating with this technique and achieve really good results. If this answer is interesting to anyone and would like me to expand upon anything, let me know ^_^
Related: Recursive methods using JavaScript: building your own version of JSON.stringify
json2html
Above we go from HTML to JSON and now we can go from JSON to HTML. When we can convert between two data types without losing data, this is called an isomorphism. All we are essentially doing here is writing the inverses of each function above -
const HtmlNode = (tagName, attributes = [], children = []) => {
const e = document.createElement(tagName)
for (const [k, v] of attributes) e.setAttribute(k, v)
for (const child of children) e.appendChild(toNode(child))
return e
}
const TextNode = (text) => {
return document.createTextNode(text)
}
const toNode = t => {
switch (t?.type) {
case "Elem": return HtmlNode(t.tagName, t.attributes, t.children)
case "TextElem": return TextNode(t.textContent)
default: throw Error("unsupported type: " + t.type)
}
}
const json2html = json =>
toNode(JSON.parse(json))
const parsedJson =
{"type":"Elem","tagName":"MAIN","attributes":[],"children":[{"type":"TextElem","textContent":"\n "},{"type":"Elem","tagName":"H1","attributes":[["class","mainHeading"]],"children":[{"type":"TextElem","textContent":"Some heading"}]},{"type":"TextElem","textContent":"\n "},{"type":"Elem","tagName":"UL","attributes":[["id","menu"]],"children":[{"type":"TextElem","textContent":"\n "},{"type":"Elem","tagName":"LI","attributes":[],"children":[{"type":"Elem","tagName":"A","attributes":[["href","/a"]],"children":[{"type":"TextElem","textContent":"a"}]}]},{"type":"TextElem","textContent":"\n "},{"type":"Elem","tagName":"LI","attributes":[],"children":[{"type":"Elem","tagName":"A","attributes":[["href","/b"]],"children":[{"type":"TextElem","textContent":"b"}]}]},{"type":"TextElem","textContent":"\n "},{"type":"Elem","tagName":"LI","attributes":[],"children":[{"type":"Elem","tagName":"A","attributes":[["href","/c"]],"children":[{"type":"TextElem","textContent":"c"}]}]},{"type":"TextElem","textContent":"\n "}]},{"type":"TextElem","textContent":"\n "},{"type":"Elem","tagName":"P","attributes":[],"children":[{"type":"TextElem","textContent":"some text"}]},{"type":"TextElem","textContent":"\n"}]}
document.body.appendChild(toNode(parsedJson))

I got few links sometime back while reading on ExtJS full framework in itself is JSON.
http://www.thomasfrank.se/xml_to_json.html
http://camel.apache.org/xmljson.html
online XML to JSON converter : http://jsontoxml.utilities-online.info/
UPDATE
BTW, To get JSON as added in question, HTML need to have type & content tags in it too like this or you need to use some xslt transformation to add these elements while doing JSON conversion
<?xml version="1.0" encoding="UTF-8" ?>
<type>div</type>
<content>
<type>span</type>
<content>Text2</content>
</content>
<content>Text2</content>

Thank you #Gorge Reith. Working off the solution provided by #George Reith, here is a function that furthers (1) separates out the individual 'hrefs' links (because they might be useful), (2) uses attributes as keys (since attributes are more descriptive), and (3) it's usable within Node.js without needing Chrome by using the 'jsdom' package:
const jsdom = require('jsdom') // npm install jsdom provides in-built Window.js without needing Chrome
// Function to map HTML DOM attributes to inner text and hrefs
function mapDOM(html_string, json) {
treeObject = {}
// IMPT: use jsdom because of in-built Window.js
// DOMParser() does not provide client-side window for element access if coding in Nodejs
dom = new jsdom.JSDOM(html_string)
document = dom.window.document
element = document.firstChild
// Recursively loop through DOM elements and assign attributes to inner text object
// Why attributes instead of elements? 1. attributes more descriptive, 2. usually important and lesser
function treeHTML(element, object) {
var nodeList = element.childNodes;
if (nodeList != null) {
if (nodeList.length) {
object[element.nodeName] = [] // IMPT: empty [] array for non-text recursivable elements (see below)
for (var i = 0; i < nodeList.length; i++) {
// if final text
if (nodeList[i].nodeType == 3) {
if (element.attributes != null) {
for (var j = 0; j < element.attributes.length; j++) {
if (element.attributes[j].nodeValue !== '' &&
nodeList[i].nodeValue !== '') {
if (element.attributes[j].name === 'href') { // separate href
object[element.attributes[j].name] = element.attributes[j].nodeValue;
} else {
object[element.attributes[j].nodeValue] = nodeList[i].nodeValue;
}
}
}
}
// else if non-text then recurse on recursivable elements
} else {
object[element.nodeName].push({}); // if non-text push {} into empty [] array
treeHTML(nodeList[i], object[element.nodeName][object[element.nodeName].length -1]);
}
}
}
}
}
treeHTML(element, treeObject);
return (json) ? JSON.stringify(treeObject) : treeObject;
}

I had a similar issue where I wanted to represent HTML as JSON in the following way:
For HTML text nodes, use a string
For HTML elements, use an array with:
The (tag) name of the element
An object, mapping attribute keys to attribute values
The (inlined) list of children nodes
Example:
<div>
<span>text</span>Text2
</div>
becomes
[
'div',
{},
['span', {}, 'text'],
'Text2'
]
I wrote a function which handles transforming a DOM Element into this kind of JS structure. You can find this function at the end of this answer. The function is written in Typescript. You can use the Typescript playground to convert it to clean JavaScript.
Furthermore, if you need to parse an html string into DOM, assign to .innerHtml:
let element = document.createElement('div')
element.innerHtml = htmlString
Also, this one is common knowledge but if you need a JSON string output, use JSON.stringify.
/**
* A NodeDescriptor stands for either an (HTML) Element, or for a text node
*/
export type NodeDescriptor = ElementDescriptor | string
/**
* Array representing an HTML Element. It consists of:
*
* - The (tag) name of the element
* - An object, mapping attribute keys to attribute values
* - The (inlined) list of children nodes
*/
export type ElementDescriptor = [
string,
Record<string, string>,
...NodeDescriptor[]
]
export let htmlToJs = (element: Element, trim = true): ElementDescriptor => {
let convertElement = (element: Element): ElementDescriptor => {
let attributeObject: Record<string, string> = {}
for (let { name, value } of element.attributes) {
attributeObject[name] = value
}
let childArray: NodeDescriptor[] = []
for (let node of element.childNodes) {
let converter = htmlToJsDispatch[node.nodeType]
if (converter) {
let descriptor = converter(node as any)
let skip = false
if (trim && typeof descriptor === 'string') {
descriptor = descriptor.trim()
if (descriptor === '') skip = true
}
if (!skip) childArray.push(descriptor)
}
}
return [element.tagName.toLowerCase(), attributeObject, ...childArray]
}
let htmlToJsDispatch = {
[element.ELEMENT_NODE]: convertElement,
[element.TEXT_NODE]: (node: Text): string => node.data,
}
return convertElement(element)
}

Related

Stringify MutationObserver mutations [duplicate]

As title , how to JSON.stringify a dom element, and change back the json to a dom element.
Any one know how to do , thanks.
Here is the code :
var container = document.querySelectorAll('.container')
var json=JSON.stringify(container)
{"0":{},"1":{},"2":{},"3":{}}"//result
expected result:
{"tagname":"div","class":"container","value":"test","childelement":[...]}
I think the most reasonable approach would be to whitelist which properties of the DOM element you want to serialize:
JSON.stringify(container, ["id", "className", "tagName"])
The second parameter of the JSON.stringify function allows you to change the behavior of the stringification process. You can specify an array with the list of properties to serialize. More information here: JSON.stringify
If you want to serialize its child nodes too, some extra work is needed. In this case you will have to specify a replacer function as the second parameter of JSON.stringify, instead of an array.
let whitelist = ["id", "tagName", "className", "childNodes"];
function domToObj (domEl) {
var obj = {};
for (let i=0; i<whitelist.length; i++) {
if (domEl[whitelist[i]] instanceof NodeList) {
obj[whitelist[i]] = Array.from(domEl[whitelist[i]]);
}
else {
obj[whitelist[i]] = domEl[whitelist[i]];
}
};
return obj;
}
JSON.stringify(container, function (name, value) {
if (name === "") {
return domToObj(value);
}
if (Array.isArray(this)) {
if (typeof value === "object") {
return domToObj(value);
}
return value;
}
if (whitelist.find(x => (x === name)))
return value;
})
The replacer function transforms the hosted objects in childNodes to native objects, that JSON.stringify knows how to serialize. The whitelist array has the list of properties to serialize. You can add your own properties here.
Some extra work in the replacer function might be needed if you want to serialize other properties that reference hosted objects (for example, firstChild).
I wondered the same thing, and I appreciate the answer from #ncardeli. In my app, I needed something a little different, and I thought I'd share in case anyone is interested. It recursively displays properties of any children too.
Press the button below to run the example. You can add whatever properties you want to obj and therefore to the result.
function showStringifyResult(target) {
let result = document.getElementById("result");
result.select();
result.setRangeText(JSON.stringify(stringify(target), null, ' '));
}
function stringify(element) {
let obj = {};
obj.name = element.localName;
obj.attributes = [];
obj.children = [];
Array.from(element.attributes).forEach(a => {
obj.attributes.push({ name: a.name, value: a.value });
});
Array.from(element.children).forEach(c => {
obj.children.push(stringify(c));
});
return obj;
}
#list {
margin-top: 18px;
}
<h1>
Press the Stringify button to write the stringified object to the textarea below.
</h1>
<button onClick="showStringifyResult(document.body)" class="c1">
Stringify
</button>
<div id="list">
A list for example:
<ul class="first second">
<li id="First Item">Item 1</li>
<li>Item 2</li>
<li class="inactive">Item 3</li>
<li data-tag="tag">Item 4</li>
</ul>
</div>
<textarea id="result" cols="200" rows="20" ></textarea>
Even though this is an old thread here is my addition:
JSON.stringify(target, Object.getOwnPropertyNames(target["__proto__"]), 2)
Give you a quick list for some of the properties of the DOM element.
Old question but anyhow, I was in the same situation. All I needed was to grab the content of the outerHTML property on the DOM object. This gives you a string, which you could put into a JSON as a value or not.
let HTML = container.outerHTML

How to JSON.stringify a dom element?

As title , how to JSON.stringify a dom element, and change back the json to a dom element.
Any one know how to do , thanks.
Here is the code :
var container = document.querySelectorAll('.container')
var json=JSON.stringify(container)
{"0":{},"1":{},"2":{},"3":{}}"//result
expected result:
{"tagname":"div","class":"container","value":"test","childelement":[...]}
I think the most reasonable approach would be to whitelist which properties of the DOM element you want to serialize:
JSON.stringify(container, ["id", "className", "tagName"])
The second parameter of the JSON.stringify function allows you to change the behavior of the stringification process. You can specify an array with the list of properties to serialize. More information here: JSON.stringify
If you want to serialize its child nodes too, some extra work is needed. In this case you will have to specify a replacer function as the second parameter of JSON.stringify, instead of an array.
let whitelist = ["id", "tagName", "className", "childNodes"];
function domToObj (domEl) {
var obj = {};
for (let i=0; i<whitelist.length; i++) {
if (domEl[whitelist[i]] instanceof NodeList) {
obj[whitelist[i]] = Array.from(domEl[whitelist[i]]);
}
else {
obj[whitelist[i]] = domEl[whitelist[i]];
}
};
return obj;
}
JSON.stringify(container, function (name, value) {
if (name === "") {
return domToObj(value);
}
if (Array.isArray(this)) {
if (typeof value === "object") {
return domToObj(value);
}
return value;
}
if (whitelist.find(x => (x === name)))
return value;
})
The replacer function transforms the hosted objects in childNodes to native objects, that JSON.stringify knows how to serialize. The whitelist array has the list of properties to serialize. You can add your own properties here.
Some extra work in the replacer function might be needed if you want to serialize other properties that reference hosted objects (for example, firstChild).
I wondered the same thing, and I appreciate the answer from #ncardeli. In my app, I needed something a little different, and I thought I'd share in case anyone is interested. It recursively displays properties of any children too.
Press the button below to run the example. You can add whatever properties you want to obj and therefore to the result.
function showStringifyResult(target) {
let result = document.getElementById("result");
result.select();
result.setRangeText(JSON.stringify(stringify(target), null, ' '));
}
function stringify(element) {
let obj = {};
obj.name = element.localName;
obj.attributes = [];
obj.children = [];
Array.from(element.attributes).forEach(a => {
obj.attributes.push({ name: a.name, value: a.value });
});
Array.from(element.children).forEach(c => {
obj.children.push(stringify(c));
});
return obj;
}
#list {
margin-top: 18px;
}
<h1>
Press the Stringify button to write the stringified object to the textarea below.
</h1>
<button onClick="showStringifyResult(document.body)" class="c1">
Stringify
</button>
<div id="list">
A list for example:
<ul class="first second">
<li id="First Item">Item 1</li>
<li>Item 2</li>
<li class="inactive">Item 3</li>
<li data-tag="tag">Item 4</li>
</ul>
</div>
<textarea id="result" cols="200" rows="20" ></textarea>
Even though this is an old thread here is my addition:
JSON.stringify(target, Object.getOwnPropertyNames(target["__proto__"]), 2)
Give you a quick list for some of the properties of the DOM element.
Old question but anyhow, I was in the same situation. All I needed was to grab the content of the outerHTML property on the DOM object. This gives you a string, which you could put into a JSON as a value or not.
let HTML = container.outerHTML

how to print a javascript object's elements

i am new to javascript and i currently have an object printed to console when i use the following code:
clickEvents: {
click:function(target) {
console.log(target);
}
}
when i view console i can see the following object:
i am banging my head against a wall to write code that takes the object and prints it to a div using the .append() method. i am extermely new to working with javascript objects, and would appreciate any help trying to tease out an object and/or print the object data.
is events the object name? would i tease out the eventDate using something like events->eventDate?
I've made this over ~15 minutes so it's imperfect; there are types and edge cases surely unaccounted for and the design of the function could be better - not to mention that performing all of this as a giant string and then setting that as HTML is likely bad practice (I'm used to React now, ha!). Regardless, this will iterate over any array or object you pass to it and print it all in a big <ul> recursively.
const targetEl = document.querySelector('.js-target')
if (!targetEl) return
// Small helper functions
const isObj = data => typeof data === 'object' && !Array.isArray(data) && data !== null
const isArr = data => Array.isArray(data)
const dataToHTML = (data, noNode = false) => {
if (isObj(data)) {
const accumulator = Object.entries(data).reduce((acc, set) => acc + `<li><strong>${set[0]}</strong>: ${dataToHTML(set[1], true)}</li>`, '')
return `<ul>${accumulator}</ul>`
}
else if (isArr(data)) {
const accumulator = data.reduce((acc, item) => acc + dataToHTML(item), '')
return `<ul>${accumulator}</ul>`
}
else return noNode ? data : `<li>${data}</li>`
}
const logHTML = dataToHTML(exampleData)
targetEl.innerHTML = logHTML
Assuming that your data/variable is named exampleData.
Any questions pop them in the comments :-)
I'm not sure if you have a div that you want to append to already, but you would do something like this ->
document.getElementById("toBeAppendedTo").innerHTML = target.events[0].eventDate; where toBeAppendedTo is the id of the div you're trying to add this text to.
append() is a jquery function, not a javascript function.
That won't have any formatting and will just be the string value 07-28-2017 in a div.

Why does shift() work on one array but not the other, unless applied generically on the other

In the following code the compiler (at 'compile' time) makes no complaints about groups.shift() but complains that depths.shift() is not a function. What am I being blind to? (I tried renaming depths, retyping, etc.)
const tag1x = (elem, content, groups = ['?','?','?'], depths = ['?','?'], optional = true, level = 0) => {
let option = optional ? '?' : '';
let template = `
${'\t'.repeat(level)}(${groups.shift()}:<$1[^>]*?DDD(${depths.shift()}:[0-9]+)[^>]*>)$3
${'\t'.repeat(level)}(${groups.shift()}:$2)
${'\t'.repeat(level)}(${groups.shift()}:</$1[^>]*?DDD(${depths.shift()}:[0-9]+)[^>]*>)$3
`;
return form(template, elem, content, option);
}
However, if I use shift generically it works fine on all counts:
const tag1x = (elem, content, groups = ['?','?','?'], depths = ['?','?'], optional = true, level = 0) => {
let option = optional ? '?' : '';
let template = `
${'\t'.repeat(level)}(${groups.shift()}:<$1[^>]*?DDD(${[].shift.call(depths)}:[0-9]+)[^>]*>)$3
${'\t'.repeat(level)}(${groups.shift()}:$2)
${'\t'.repeat(level)}(${groups.shift()}:</$1[^>]*?DDD(${[].shift.call(depths)}:[0-9]+)[^>]*>)$3
`;
return form(template, elem, content, option);
}
The above is fully functional.
I misread the situation. The error was occurring at runtime, and thus pretty clearly because of a string input instead of an array input. A string input will get fixed up by [].shift.call(myAccidentallyAString) while, of course, a shift() call directly on the string is not a function.
It acts like Array.isArray(myStuff) ? myStuff.shift() : [myStuff].shift(), which makes sense because (I'll guess) myStuff is getting boxed to an object then called on by shift().

Using element attr in Javascript function

In a page I call external js file and its includes a dictionary. I want to replace element text by their attiributes.
<p data-text="dict.dataP"></p>
<p data-text="dict.data.P2"></p>
I want to fill it with external file dict
var dict = {
"dataP1": "this is my p text",
"data" : {
"p2": "my another paragraph"
},
};
I tried to use as this
$.each(function () {
if ($(this).attr("data-text").length > 0) {
$(this).html(
$(this).attr('data-text') /*we got a problem here. it returns string*/ );
}
});
codePen here:
codepen.io
JSFiddle here
jsfiddle.net
How can I do this?
edited dict. we have dictionary in dictionary.
In order to access the data attribute, use:
$(this).data('text');
Text is the part after the hyphen within your attribute declaration.
There are a few things that you should change to get this working, taking Jimbo's answer and adding a few other things:
var dict = {
"dataP": "this is my p tag text"
};
$('[data-text]').each(function () {
if ( $(this).data("text") ) {
var dictAttr = $(this).data("text");
if ( dictAttr && dict[dictAttr] ) {
$(this).html( dict[dictAttr] );
}
}
});
You should also change your mark-up to make things easier (expecially if you are only dealing with one dict object):
<p data-text="dataP"></p>
With the above changes you should get things working as you expect.
http://jsfiddle.net/b2zgw/
string-based object navigation
Rather oddly I'm actually working on a framework for string-based object navigation as we speak. However the codebase if far too complicated to just tack on the end of a stackoverflow answer. As an addition to my comment I realised there is a third option which might be the best of both worlds (depending on what you need).
:: eval
I don't recommend this method, but it can't be argued with for simplicity — the following is a snippet from the code above and should replace that part:
var dictNav = $(this).data("text"); /// e.g. say dictNav == 'dict.dataP'
var ref; eval('ref='+dictNav);
if ( ref && red.substr ) {
$(this).html( ref );
}
The problem with the above is that eval will evaluate any JavaScript - so all an attacker would have to do is find a way to add a data-text attribute to something on your page and they would be able to execute any JavaScript they liked.
:: string-based navigation
The following is a simple function that could be improved, but should give you the idea:
function navigate( obj, path ){
var cur = obj, bits = path.split('.');
for ( var i=0, l=bits.length; i<l && cur; i++ ) {
cur = cur[bits[i]];
}
return cur;
}
Using the above you can navigate your dictionary structure - be aware because you start your 'navigation path' with a particular var name (i.e. dict) you'll have to place your dictionary one level down of the object you wish to traverse; this is the reason for {dict:dict}. To support multiple dictionaries you'd just need to extend that object like so {dict:dict,dict2:dict2} — again the following is a snippet and should replace the original code:
var dictNav = $(this).data("text"); /// e.g. say dictNav == 'dict.dataP.test'
var ref = navigate({dict:dict}, dictNav);
if ( ref && red.substr ) {
$(this).html( ref );
}
:: third option - simplify your dictionary
The third option is probably the most optimal, but means that the dictionary can't be modified in realtime (or at least not easily). Basically before you run the rest of your code, push your dictionary through a parsing function that modifies it's structure:
var dict = {
"dataP": "this is a test",
"forms": {
"inputLabel": "this is a second level"
}
};
function simplifyDict( obj, target, path, subpath ){
if ( !target ) { target = {}; }
if ( !path ) { path = ''; }
for( var i in obj ) {
subpath = (path ? path + '.' : '') + i;
if ( typeof obj[i] == 'object' ) {
simplifyDict( obj[i], target, subpath );
}
else {
target[subpath] = obj[i];
}
}
return target;
}
dict = simplifyDict( dict );
The above simplify function should return something like:
{
"dataP" : "this is a test",
"forms.inputLabel" : "this is a second level"
}
Then all you need to do is use my original code right at the top of this answer. Instead of converting your strings to separate object properties and navigating the dictionary, you've switched the dictionary to be a string-based lookup... so now you can just use strings directly i.e. dict['forms.inputLabel']
You'd like to set the text from the dictionary to the element with matching data attribute, right?
Try this:
var dict = {
"dataP": "this is my p tag text",
"dataDiv": "dummy div"
};
$('p').each(function () {
var data = $(this).data('text');
$(this).html(dict[data.split('.')[1]])
});
http://jsfiddle.net/eB6E2/1/

Categories

Resources