Creating a dynamic toc.json to use with treesaver.js - javascript

I've been working for quite some time with a simple backend (based on Spagent - a flat file blogging script) to use with the amazing javascript library treesaver.js. My problem is that I have a lack in my json skill set and can't for the world figure out how to add arrays to my .json...
My file looks like this:
{
"contents": [
{
"url": "index.html",
"hidden": true
},
{
"url": "section1.html",
"title": "Section One",
"thumb": "openroad-thumb.jpg",
"byline": "John Doe"
},
{
"url": "one.html",
"title": "Article One",
"thumb": "river-thumb.jpg",
"byline": "Jane Doe"
},
{
"url": "two.html",
"title": "Article Two",
"thumb": "river-thumb.jpg",
"byline": "Jane Doe"
},
{
"url": "section2.html",
"title": "Section Two",
"thumb": "river-thumb.jpg",
"byline": "Jane Doe"
},
{
"url": "three.html",
"title": "Article Three",
"thumb": "river-thumb.jpg",
"byline": "Jane Doe"
},
{
"url": "four.html",
"title": "Article Four",
"thumb": "river-thumb.jpg",
"byline": "Jane Doe"
},
{
"url":"five.html",
"title":"Article Five",
"thumb":"unknown-thumb.jpeg",
"byline":"John Doe"
}
]
}
And when I use these scripts:
form.php
<!doctype html>
<html class="no-js no-treesaver">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,height=device-height,initial-scale=1,minimum-scale=1,maximum-scale=1">
<title>Treesaver - Article One</title>
</head>
<body>
<form name="postform" action="post.php" method="post" enctype="multipart/form-data">
<table class="postarea" id="postarea">
<tbody>
<tr> <td class="postblock">URL:</td><td><input type="text" name="url"></td></tr>
<tr> <td class="postblock">Titel:</td><td><input type="text" name="title"></td></tr>
<tr> <td class="postblock">Thumb:</td><td><textarea id="text" rows="5" cols="30" type="text" name="thumb"></textarea> </td> </tr>
<tr> <td class="postblock">Skribent:</td><td><input type="text" name="byline"></td></tr>
<tr> <td class="postblock"></td><td> <input type="submit" value="Submit Entry"> </td> </tr>
</tbody>
</table>
</form>
</form>
</body>
</html>
post.php
<?php
// check if a form was submitted
if( !empty( $_POST ) ){
// convert form data to json format
$postArray = array(
"url" => $_POST['url'],
"title" => $_POST['title'],
"thumb" => $_POST['thumb'],
"byline" => $_POST['byline']
);
//you might need to process any other post fields you have..
$json = json_encode( $postArray);
// make sure there were no problems
//if( json_last_error() != JSON_ERROR_NONE ){
//exit; // do your error handling here instead of exiting
// }
$file = 'entries.json';
// write to file
// note: _server_ path, NOT "web address (url)"!
file_put_contents( $file, $json, FILE_APPEND);
}
My added array is generated like this:
{
"url": "index.html",
"hidden": true
},
{
"url": "section1.html",
"title": "Section One",
"thumb": "openroad-thumb.jpg",
"byline": "John Doe"
},
{
"url": "one.html",
"title": "Article One",
"thumb": "river-thumb.jpg",
"byline": "Jane Doe"
},
{
"url": "two.html",
"title": "Article Two",
"thumb": "river-thumb.jpg",
"byline": "Jane Doe"
},
{
"url": "section2.html",
"title": "Section Two",
"thumb": "river-thumb.jpg",
"byline": "Jane Doe"
},
{
"url": "three.html",
"title": "Article Three",
"thumb": "river-thumb.jpg",
"byline": "Jane Doe"
},
{
"url": "four.html",
"title": "Article Four",
"thumb": "river-thumb.jpg",
"byline": "Jane Doe"
},
{
"url":"five.html",
"headline":"Article Five",
"thumb":"nagot.jpg",
"byline":"Gustaf"
}{"url":"six.html","title":"Article Six","thumb":"jasas.jpg","byline":"John Doe"}
No comma , is generated after my array and the script is broken. How do I solve this?

You're appending a fresh JSON object into a file already containing one. You might be able to solve it by prepending a comma to the data you are writing, but I'd say that's the wrong way to solve this. You're trying to write in JSON format directly, but you should be getting PHP to do this for you - it does this very well already, and there's no point re-inventing the wheel.
I would therefore read the contents of the file in, convert it to an object or array as appropriate (using json_decode). You can then append things to this structure and re-encode it, before writing the whole thing to a file without the append flag.
If the amount of data in this file is large, you could tackle the problem another way: for every new structure you wish to write, put it in a separate file, and then read them in your blogging script as you need them.

change
file_put_contents( $file, $json, FILE_APPEND);
to
file_put_contents( $file, ",".$json, FILE_APPEND);
You can put the above statement inside some if statement that checks if the file is not empty since you don't need a comma if you are making first insertion.

You would be best advised to read the existing json data and convert it back to its PHP condition which is a Class with the property 'contents' which is an array.
Then you push your new array onto this existing array, and then encode it all as json again and write it all back to your json file.
// check if a form was submitted
if( !empty( $_POST ) ){
$file = 'entries.json';
$json = file_get_contents($file);
// convert json back to a php stdClass
$phpClass = json_decode($json);
$postArray = array(
"url" => $_POST['url'],
"title" => $_POST['title'],
"thumb" => $_POST['thumb'],
"byline" => $_POST['byline']
);
// push the new $postArray onto the bottom of phpClass
array_push($phpClass->contents, $postArray);
// encode php class into json again
$new_json = json_encode($phpClass);
// write it out
file_put_contents( $file, $new_json);
}

Related

Lodash/Javascript Compare array or objects, fail if any props match

Preferably using Lodash, how can I compare two array of objects, and if any of the properties match, return false, while excluding 'name'.
array1 = [
{
"name": "componentA",
"img": "www.url.com/image1.jpg"
},
{
"name": "componentB",
"header": "this is the default header",
"text": "here is a default text post",
"buttons": [{
"title": "a button",
"url": "http://www.url.com"
}]
},
{
"name": "componentB",
"header": "this is the default header 2",
"text": "here is a default text post 2 ",
"buttons": [
{
"title": "a button 2",
"url": "http://www.url2.com"
},
{
"title": "a second button 2",
"url": "http://www.url2_1.com"
}
]
}
]
vs
array2 = [
{
"name": "componentA",
"img": "www.url.com/imageA.jpg"
},
{
"name": "componentB",
"header": "header changed",
"text": "text post changed",
"buttons": [{
"title": "button changed",
"url": "http://www.website.com"
}]
},
{
"name": "componentB",
"header": "header 2 changed",
"text": "here is a default text post 2 ",
"buttons": [
{
"title": "button 2 changed",
"url": "http://www.website2.com"
},
{
"title": "button 2 changed again",
"url": "http://www.website2_1.com"
}
]
},
]
As you can see every property has changed except in array2[2].text, which would result in error.
The goal is to compare two arrays and be sure none of the default placeholder texts exists in the final array. if any default placeholder texts exists, do not allow a form to submit. Each object has a name key that needs to be excluded from the check as it's what renders the component.
Started by using _.isEqual(), but unsure how go about checking each property between the two.
let results = _.isEqual(array1, array2)
You can use _.isEqualWith and customizer function Loadash Ref
let array1 = [{"name": "componentA","img": "www.url.com/image1.jpg"},{"name": "componentB","header": "this is the default header","text": "here is a default text post","buttons": [{"title": "a button","url": "http://www.url.com"}]},{"name": "componentB","header": "this is the default header 2","text": "here is a default text post 2 ","buttons": [{"title": "a button 2","url": "http://www.url2.com"},{"title": "a second button 2","url": "http://www.url2_1.com"}]}]
let array2 = [{"name": "componentA","img": "www.url.com/imageA.jpg"},{"name": "componentB","header": "header changed","text": "text post changed","buttons": [{"title": "button changed","url": "http://www.website.com"}]},{"name": "componentB","header": "header 2 changed","text": "here is a default text post 2 ","buttons": [{"title": "button 2 changed","url": "http://www.website2.com"},{"title": "button 2 changed again","url": "http://www.website2_1.com"}]},]
let array3 = [{"name": "component3","img": "www.url.com/image1.jpg"},{"name": "componentB","header": "this is the default header","text": "here is a default text post","buttons": [{"title": "a button","url": "http://www.url.com"}]},{"name": "componentB","header": "this is the default header 2","text": "here is a default text post 2 ","buttons": [{"title": "a button 2","url": "http://www.url2.com"},{"title": "a second button 2","url": "http://www.url2_1.com"}]}]
function check(val1,val2,index){
if(index === 'name') return true
}
console.log(_.isEqualWith(array1,array2,check))
console.log(_.isEqualWith(array1,array3,check))
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.15/lodash.min.js"></script>

Dialogflow html/js card json value v1

I am trying to access the card json value, to no avail.
In my scenario, I am asking the bot about "weather in London" and it replies back with "It is currently 9 degrees celcius in London." via the webhook.
Which is correct and dynamic.
However, I am trying to also pass the values to a card too.
In the json reply, I do get the card as so
{
"id": "REMOVED",
"timestamp": "2017-12-05T11:10:52.033Z",
"lang": "en",
"result": {
"source": "agent",
"resolvedQuery": "weather in london",
"action": "sayWeather",
"actionIncomplete": false,
"parameters": {
"geo-city": "London"
},
"contexts": [],
"metadata": {
"intentId": "REMOVED",
"webhookUsed": "true",
"webhookForSlotFillingUsed": "false",
"webhookResponseTime": 626,
"intentName": "Weather"
},
"fulfillment": {
"speech": "It is currently 9 degrees celcius in London.",
"source": "agent",
"displayText": "It is currently 9 degrees celcius in London.",
"messages": [
{
"type": 0,
"speech": "It is currently 9 degrees celcius in London."
}
],
"data": {
"items": [
{
"simpleResponse": {
"textToSpeech": "This is the first simple response for a basic card"
}
},
{
"basicCard": {
"title": "Title: this is a title",
"formattedText": "This is a basic card. Text in a\n basic card can include \"quotes\" and most other unicode characters\n including emoji 📱. Basic cards also support some markdown\n formatting like *emphasis* or _italics_, **strong** or __bold__,\n and ***bold itallic*** or ___strong emphasis___ as well as other things\n like line \nbreaks",
"subtitle": "This is a subtitle",
"image": {
"url": "https://developers.google.com/actions/images/badges/XPM_BADGING_GoogleAssistant_VER.png",
"accessibilityText": "Image alternate text"
},
"buttons": [
{
"title": "This is a button",
"openUrlAction": {
"url": "https://assistant.google.com/"
}
}
]
}
},
{
"simpleResponse": {
"textToSpeech": "This is the 2nd simple response ",
"displayText": "This is the 2nd simple response"
}
}
]
}
},
"score": 1
},
"status": {
"code": 200,
"errorType": "success",
"webhookTimedOut": false
},
"sessionId": "REMOVED"
}
Accessing the value of speech using data.result.fulfillment.speech works fine.
However, when using data.result.fulfillment.data.items.basicCard.image.url it just doesnt work. And if I go up several levels, I do get:
[object Object]
Your help is appreciated.
The items attribute is a list and not an object. As such, you'll have to use a numerical index to retrive the data. In the example you provided the index of the basicCard object is second so your code should look something like this:
data.result.fulfillment.data.items[1].basicCard.image.url
Notice the [1] after items.
Bear in mind that if the order of this list changes you may no longer be retrieving a basicCard object so you may want to add some checking to make sure you're retrieving the data you want.

Check duplicate item in object

I have a structure like this and I want to check if there are duplicate URL in the array so I can target those and make some conditional statements depending on the Keyword property. Thank you in advance.
{
"prochat": [{
"Title": "Multiple KB Page",
"Message": "Hi, Multiple KB Page?",
"ProblemDescription": "Multiple KB Page",
"Keyword": "",
"Template": 1,
"URL": "www.abcd.com"
},
{
"Title": "URL 1",
"Message": "Do you want to Renew?",
"ProblemDescription": "Message about Installing",
"Keyword": "Renewals",
"Template": 1,
"URL": "www.nba.com"
},
{
"Title": "URL 1",
"Message": "Do you want to Install?",
"ProblemDescription": "Message about Installing",
"Keyword": "Installings",
"Template": 1,
"URL": "www.nba.com"
}
]
}
I have a condition statement like this
if (window.location.href.indexOf(data.prochat[i].URL) > -1) { // logic here }
basically I need to match the url and if it matches i''ll show a button. however there are some duplicate url too so I want if there are duplicates I will just rely on Keyword property if it has the same url.
Iterate your data, if the URL is new simply add it to a new array. If it's already in it, handle it as you wish since it is a duplicate.
You can try the following code:
var myJSON = {
"prochat": [{
"Title": "Multiple KB Page",
"Message": "Hi, Multiple KB Page?",
"ProblemDescription": "Multiple KB Page",
"Keyword": "",
"Template": 1,
"URL": "www.abcd.com"
},
{
"Title": "URL 1",
"Message": "Do you want to Renew?",
"ProblemDescription": "Message about Installing",
"Keyword": "Renewals",
"Template": 1,
"URL": "www.nba.com"
},
{
"Title": "URL 1",
"Message": "Do you want to Install?",
"ProblemDescription": "Message about Installing",
"Keyword": "Installings",
"Template": 1,
"URL": "www.nba.com"
}
]
};
var duplicateURLs = [];
for(var key in myJSON.prochat){
if(myJSON.prochat.hasOwnProperty(key)){
if(duplicateURLs.indexOf(myJSON.prochat[key].URL) > 0){
// URL is duplicate, do stuff
}
else{
duplicateURLs.push(myJSON.prochat[key].URL);
}
}
}
You can try it online on jsfiddle.
var newarray=[];
var object={
"prochat": [{
"Title": "Multiple KB Page",
"Message": "Hi, Multiple KB Page?",
"ProblemDescription": "Multiple KB Page",
"Keyword": "",
"Template": 1,
"URL": "www.abcd.com"
},
{
"Title": "URL 1",
"Message": "Do you want to Renew?",
"ProblemDescription": "Message about Installing",
"Keyword": "Renewals",
"Template": 1,
"URL": "www.nba.com"
},
{
"Title": "URL 1",
"Message": "Do you want to Install?",
"ProblemDescription": "Message about Installing",
"Keyword": "Installings",
"Template": 1,
"URL": "www.nba.com"
}
]
}
console.log(object.prochat.length);
for(var i=0;i<object.prochat.length;i++){
for(var j=i+1;j<object.prochat.length;j++){
if(object.prochat[i].URL==object.prochat[j].URL){
console.log("url matches"+i+j);
newarray.push(object.projact[i].URL);
}
}

Extracting JSON data into Javascript object array

I have a JSON file with dummy articles in it for testing purposes. I'm trying to extract the information from the JSON file using jQuery to create an array of objects using the pulled information.
Here's my JSON file:
{
"news": [
{
"title": "Test 1",
"author": "Chicago Tribune",
"source": "http://www.chicagotribune.com/",
"preview": "Long-simmering . . .",
"picture": "IMG"
},
{
"title": "Test 2",
"author": "New York Times",
"source": "http://www.nytimes.com/",
"preview": "Information . . .",
"picture": "IMG"
},
{
"title": "Test 3",
"author": "Chicago Tribune",
"source": "http://www.chicagotribune.com/",
"preview": "Blah blah blah . . .",
"picture": "IMG"
}
]
}
Here's my Javascript file:
// Article array
var articles = [];
// Article 'class'
function Article (title, author, preview, picture) {
this.title = title;
this.author = author;
this.preview = preview;
this.picture = picture
}
// Pull data from JSON file
$.getJSON('data.json', function(data) {
$.each(data.news, function (i, j) {
articles.push(new Article(j.title, j.author, j.preview, j.picture));
});
});
for (i = 0; i < articles.length; i++) {
Console.log('Article ' + i + ": " + articles[i].title);
}
The articles array is not filling up and there doesn't seem to be any objects created. My next step would be iterating through each file in the array and posting that data to a page using the newly-filled array of articles.
Three things:
Your JSON is invalid. You're likely getting it pasted wrong, but it should look like this:
ex:
{
"news": [
{
"title": "Test 1",
"author": "Chicago Tribune",
"source": "http://www.chicagotribune.com/",
"preview": "Long-simmering . . .",
"picture": "IMG"
},
{
"title": "Test 2",
"author": "New York Times",
"source": "http://www.nytimes.com/",
"preview": "Information . . .",
"picture": "IMG"
},
{
"title": "Test 3",
"author": "Chicago Tribune",
"source": "http://www.chicagotribune.com/",
"preview": "Blah blah blah . . .",
"picture": "IMG"
},
]
};
the $.each() will loop through each element of the news array, so you will only get one element into your anonymous function. Try this instead:
ex:
$.getJSON('data.json', function(data) {
$.each(data.news, function (i) {
articles.push(new Article(i.title, i.author, i.preview, i.picture));
});
});
You're running into async issues because the for loop executes before your JSON arrives. Try adding in your for loop inside your $.getJSON call if you have code that depends on the articles being there. Here's a great explanation on async behavior.
Additionally, whenever in doubt as to what you're receiving in your parameters, add a debugger; inside your function - that way you can inspect and ensure you're getting what you inspect.

extjs 3.4 unable to access children of a node in a tree

I am trying to build a file explorer kind of tree structure with javascript, JSON data and extjs . The JSON data that I am using for the same is
[
{
"id": "Folder One",
"text": "<font color=\"#000000\" size=\"2\"><b>Folder One</b></font>",
"children": [
{
"id": "111",
"text": "<font color=\"#000000\" size=\"2\"><b>File1 (111)</b></font>",
"leaf": true
}
]
},
{
"id": "Folder Two",
"text": "<font color=\"#000000\" size=\"2\"><b>Folder Two</b></font>",
"children": [
{
"id": "111",
"text": "<font color=\"#000000\" size=\"2\"><b>File1 (111)</b></font>",
"leaf": true
}
]
}
]
This JSON is passed to the Asynctreenode by the following code:
var fileList = JSON.parse(resp);
//alert("fileList from Server : "+JSON.stringify(fileList));
asyncTree = new Ext.tree.AsyncTreeNode({
id:'asyncTree',
expanded: true,
border : false,
children: [
{
"id":"asyncTreeChild",
"text":"<font color=#000000 size=2><b>My Computer</b></font>",
children:fileList
}
]
});
The issue is when that the files under the node "Folder One" are unclickable. Instead the selection directly moves to the files under "Folder Two" node. The nodes "Folder One" and "Folder Two" are also returning proper paths. Its just the files under the "folder one" which are not accessible. Any ideas ?
I found what was the problem.. The id attribute of the children was same which was causing the problem. Changing it to distinct values (from 111 to something else) solved the issue.

Categories