json-object-editor 0.10.439 → 0.10.443
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +3 -0
- package/build.js +61 -0
- package/css/joe-styles.css +16 -0
- package/css/joe.css +32 -10
- package/css/joe.min.css +7 -0
- package/js/JsonObjectEditor.jquery.craydent.js +50 -4
- package/js/joe-full.js +50 -4
- package/js/joe.js +63 -13
- package/js/joe.min.js +1 -15
- package/package.json +8 -3
- package/server/fields/core.js +1 -1
- package/server/plugins/engagementTracker.js +78 -0
- package/server/schemas/engagement_event.js +33 -0
- package/server/schemas/goal.js +17 -3
- package/server/schemas/page.js +18 -1
- package/server/schemas/tag.js +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "json-object-editor",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.443",
|
|
4
4
|
"description": "JOE the Json Object Editor | Platform Edition",
|
|
5
5
|
"main": "app.js",
|
|
6
6
|
"scripts": {
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
"grunt": "start grunt --gruntfile grunt/Gruntfile.js",
|
|
11
11
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
12
12
|
"babel-wc": "babel web-components -d es5-build/web-components",
|
|
13
|
-
"babel-joe": "babel js/JsonObjectEditor.jquery.craydent.js -d es5-build/js/JsonObjectEditor_es5.jquery.craydent.js"
|
|
13
|
+
"babel-joe": "babel js/JsonObjectEditor.jquery.craydent.js -d es5-build/js/JsonObjectEditor_es5.jquery.craydent.js",
|
|
14
|
+
"build": "node build.js"
|
|
14
15
|
},
|
|
15
16
|
"repository": {
|
|
16
17
|
"type": "git",
|
|
@@ -56,10 +57,14 @@
|
|
|
56
57
|
"@babel/core": "^7.7.4",
|
|
57
58
|
"@babel/preset-env": "^7.7.4",
|
|
58
59
|
"babel-plugin-transform-es2015-template-literals": "^6.22.0",
|
|
60
|
+
"clean-css-cli": "^5.6.3",
|
|
61
|
+
"concat": "^1.0.3",
|
|
59
62
|
"del": "^2.0.1",
|
|
63
|
+
"fs-extra": "^11.3.0",
|
|
60
64
|
"grunt-traceur": "^0.5.5",
|
|
61
65
|
"gulp": "^3.9.0",
|
|
62
66
|
"gulp-concat": "^2.6.0",
|
|
63
|
-
"gulp-notify": "^2.2.0"
|
|
67
|
+
"gulp-notify": "^2.2.0",
|
|
68
|
+
"terser": "^5.43.1"
|
|
64
69
|
}
|
|
65
70
|
}
|
package/server/fields/core.js
CHANGED
|
@@ -256,7 +256,7 @@ var fields = {
|
|
|
256
256
|
return html;
|
|
257
257
|
}},
|
|
258
258
|
milestone:{name:'milestone',width:'100px'},
|
|
259
|
-
tasks:{display:'Incomplete Tasks',type:'content',icon:'task',run:function(item){
|
|
259
|
+
tasks:{display:'Incomplete Tasks',type:'content',icon:'task',reloadable:true, run:function(item){
|
|
260
260
|
var tasks = (_joe.Data.task.where({$and:[{project:item._id},{complete:{$in:[false,'false',undefined]}}]})||[]).sortBy('priority,!due_date,project_phase');
|
|
261
261
|
var html = '';
|
|
262
262
|
html+= _joe.renderMenuButtons({display:'view all '+tasks.length+' tasks',
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
function EngagementTracker() {
|
|
2
|
+
const self = this;
|
|
3
|
+
|
|
4
|
+
// 📸 Email open pixel endpoint
|
|
5
|
+
// Called as: /API/plugin/engagementTracker/pixel?campaign=...&visitor=...
|
|
6
|
+
this.pixel = async function(data, req, res) {
|
|
7
|
+
const campaign_id = req.query.campaign;
|
|
8
|
+
const visitor = req.query.visitor;
|
|
9
|
+
|
|
10
|
+
if (!campaign_id) return res.status(400).send({ error: "Missing campaign ID" });
|
|
11
|
+
|
|
12
|
+
const engagement = {
|
|
13
|
+
_id: cuid(),
|
|
14
|
+
itemtype: "engagement_event",
|
|
15
|
+
eventType: "email_open",
|
|
16
|
+
eventTarget: "email",
|
|
17
|
+
eventLabel: "Email opened",
|
|
18
|
+
campaign: campaign_id,
|
|
19
|
+
visitor: visitor || "anonymous",
|
|
20
|
+
eventLocation: "email",
|
|
21
|
+
created: new Date()
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
await JOE.Storage.save(engagement, "engagement_event");
|
|
25
|
+
|
|
26
|
+
// Transparent 1x1 gif
|
|
27
|
+
const img = Buffer.from("R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==", "base64");
|
|
28
|
+
res.writeHead(200, {
|
|
29
|
+
"Content-Type": "image/gif",
|
|
30
|
+
"Content-Length": img.length
|
|
31
|
+
});
|
|
32
|
+
return res.end(img);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
// 🔗 Click-through tracking + redirect
|
|
36
|
+
// Called as: /API/plugin/engagementTracker/redirect?campaign=...&to=URL&target=cta_1&visitor=...
|
|
37
|
+
this.redirect = async function(data, req, res) {
|
|
38
|
+
const { campaign, to, target, visitor } = req.query;
|
|
39
|
+
if (!to || !campaign) return res.status(400).send({ error: "Missing required parameters" });
|
|
40
|
+
|
|
41
|
+
const engagement = {
|
|
42
|
+
_id: cuid(),
|
|
43
|
+
itemtype: "engagement_event",
|
|
44
|
+
eventType: "click_cta",
|
|
45
|
+
eventTarget: target || "unspecified",
|
|
46
|
+
eventLabel: `Clicked ${target || "link"}`,
|
|
47
|
+
campaign,
|
|
48
|
+
visitor: visitor || "anonymous",
|
|
49
|
+
eventLocation: "email_or_landing",
|
|
50
|
+
created: new Date()
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
await JOE.Storage.save(engagement, "engagement_event");
|
|
54
|
+
return res.redirect(to);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// ✍️ Generic event logger
|
|
58
|
+
// Called via POST to /API/plugin/engagementTracker/log with JSON body
|
|
59
|
+
this.log = async function(data, req, res) {
|
|
60
|
+
if (!data || !data.eventType || !data.campaign) {
|
|
61
|
+
return res.status(400).send({ error: "Missing eventType or campaign" });
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const engagement = {
|
|
65
|
+
...data,
|
|
66
|
+
_id: cuid(),
|
|
67
|
+
itemtype: "engagement_event",
|
|
68
|
+
created: new Date()
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
await JOE.Storage.save(engagement, "engagement_event");
|
|
72
|
+
return res.send({ status: "ok" });
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
return self;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
module.exports = new EngagementTracker();
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
var schema = {
|
|
2
|
+
title: "Engagement Event | ${eventType}",
|
|
3
|
+
info: "Tracks visitor interactions across email campaigns, landing pages, and CTAs for analytics and engagement insight.",
|
|
4
|
+
menuicon: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024"><path d="..."/></svg>`, // optional: stylized icon
|
|
5
|
+
idprop: "_id",
|
|
6
|
+
sorter: ["-created", "eventType", "eventTarget"],
|
|
7
|
+
listView: {
|
|
8
|
+
title: "<joe-title>${eventType}</joe-title><joe-subtitle>${eventLabel}</joe-subtitle><joe-subtitle>${visitor}</joe-subtitle>",
|
|
9
|
+
listWindowTitle: "Engagement Events"
|
|
10
|
+
},
|
|
11
|
+
fields: function(){
|
|
12
|
+
var fields = [
|
|
13
|
+
|
|
14
|
+
{section_start:'objects'},
|
|
15
|
+
{ name: "campaign", type: "objectReference", ref: "campaign", label: "Campaign" },
|
|
16
|
+
{section_end:'objects'},
|
|
17
|
+
{ name: "eventType", type: "select", options: ["email_open", "email_click", "landing_visit", "click_cta", "form_submit"], required: true },
|
|
18
|
+
{ name: "eventTarget", type: "text", label: "Target Element", placeholder: "e.g. CTA 1, Header Link" },
|
|
19
|
+
{ name: "name", type: "text", label: "Event Label", placeholder: "Descriptive text of action" },
|
|
20
|
+
{ name: "eventLocation", type: "select", options: ["email", "landingPage", "external"], label: "Location" },
|
|
21
|
+
{ name: "visitor", type: "text", label: "Visitor ID or Email" },
|
|
22
|
+
{ name: "session", type: "text", label: "Session ID" },
|
|
23
|
+
|
|
24
|
+
{section_start:'system',collapsed:true},
|
|
25
|
+
'_id','created','itemtype',
|
|
26
|
+
{section_end:'system'},
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
return fields;
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
module.exports = schema;
|
package/server/schemas/goal.js
CHANGED
|
@@ -42,20 +42,34 @@ var schema = {
|
|
|
42
42
|
`
|
|
43
43
|
return html;
|
|
44
44
|
},
|
|
45
|
+
|
|
45
46
|
fields:[
|
|
46
47
|
{extend:'name',specs:{width:'75%'}},
|
|
47
48
|
{name:'code',width:'25%'},
|
|
48
49
|
'info',
|
|
49
50
|
'description',
|
|
51
|
+
{name:'completion_equation',display:'completion equation',type:'code',language:'javascript',comment:'This is a javascript function that takes an item as an argument and returns a number between 0 and 1 representing the completion percentage of the goal. It can use any properties of the item or datasets in joe'},
|
|
52
|
+
{name:'complettion_percentage', reloadable:true, display:'completion percentage',type:'content',run:function(item){
|
|
53
|
+
const fn = tryEval(item.completion_equation);
|
|
54
|
+
const result = fn(item); // or any item
|
|
55
|
+
return Math.round(result*100) + '%'; // Assuming the function returns a number between 0 and 1
|
|
56
|
+
return 80 + '%'; // Placeholder, should be calculated based on completion_equation
|
|
57
|
+
}},
|
|
50
58
|
'impact',
|
|
51
59
|
'group',
|
|
52
|
-
|
|
53
|
-
{name:'milestones',
|
|
60
|
+
// {name:'has_milestones',display:'has milestones',type:'boolean',comment:'If true, this goal has milestones that can be tracked.',rerender:['milestones','timeline']},
|
|
61
|
+
{name:'milestones',
|
|
62
|
+
/*condition:function(item){return !!!item.has_milestones;},*/
|
|
63
|
+
type:'objectList',properties:[
|
|
54
64
|
{name:'name'},
|
|
55
65
|
{name:'status',type:'select',values:['','roadmap','in-progress','completed'],width:'120px'}
|
|
56
66
|
]},
|
|
57
67
|
|
|
58
|
-
{section_start:'timeline'
|
|
68
|
+
{section_start:'timeline',
|
|
69
|
+
// condition:function(item){
|
|
70
|
+
// return !!!item.has_milestones;
|
|
71
|
+
// }
|
|
72
|
+
},
|
|
59
73
|
{name:'start_dt',display:'kickoff',type:'date', native:true,width:'50%'},
|
|
60
74
|
{name:'end_dt',display:'completion',type:'date', native:true,width:'50%'},
|
|
61
75
|
{name:'phases',type:'objectList',
|
package/server/schemas/page.js
CHANGED
|
@@ -96,9 +96,26 @@ var page = {
|
|
|
96
96
|
hidden:function(item){
|
|
97
97
|
return item.content_type =='plugin';
|
|
98
98
|
},
|
|
99
|
+
language:function(item){
|
|
100
|
+
return 'javascript';
|
|
101
|
+
},
|
|
99
102
|
comment:'${this.DATA.dataset_name}<br/>'+
|
|
100
103
|
`also available: INCLUDES,PAGE,LAYOUT,SITE,JOEPATH,DATA,WEBCONFIG
|
|
101
|
-
<div>for module: export function(data) that returns an html string.</div
|
|
104
|
+
<div>for module: export function(data) that returns an html string.</div>
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
<h4>Example:</h4>
|
|
108
|
+
<div class="pad10">
|
|
109
|
+
<pre>
|
|
110
|
+
module.exports = async function(data){
|
|
111
|
+
// data contains all the page data, including dynamic items
|
|
112
|
+
return "html as string";
|
|
113
|
+
|
|
114
|
+
};
|
|
115
|
+
</pre>
|
|
116
|
+
</div>
|
|
117
|
+
</div>`
|
|
118
|
+
,
|
|
102
119
|
type:function(item){
|
|
103
120
|
if(!item.content_type){
|
|
104
121
|
return 'code';
|
package/server/schemas/tag.js
CHANGED
|
@@ -92,7 +92,7 @@ var tag ={
|
|
|
92
92
|
tags.map(function(tag){
|
|
93
93
|
let tagObj = _joe.Cache.get(tag);//$J.get(tag);
|
|
94
94
|
if(tagObj){
|
|
95
|
-
html+= `<joe-tag data-id="${tagObj._id}" title="${tagObj.info}" style="${tagObj.color && (`background:'${tagObj.color}'`)}">${tagObj.name}</joe-tag>`;
|
|
95
|
+
html+= `<joe-tag data-id="${tagObj._id}" title="${tagObj.info}" style="${tagObj.color && (`background:'${tagObj.color}'`)||''}">${tagObj.name}</joe-tag>`;
|
|
96
96
|
}
|
|
97
97
|
})
|
|
98
98
|
html+= '</joe-tags>';
|