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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "json-object-editor",
3
- "version": "0.10.439",
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
  }
@@ -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;
@@ -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',type:'objectList',properties:[
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',
@@ -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';
@@ -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>';