json-object-editor 0.10.642 → 0.10.653
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 +22 -0
- package/_www/mcp-test.html +18 -0
- package/css/joe-styles.css +2 -1
- package/css/joe.css +4 -2
- package/css/joe.min.css +1 -1
- package/docs/Thought_Concept_for_JOE.md +137 -0
- package/docs/joe_agent_custom_gpt_instructions_v_3.md +57 -3
- package/img/joe-sprite.ai +1155 -758
- package/js/JsonObjectEditor.jquery.craydent.js +185 -5
- package/js/joe-ai.js +57 -0
- package/js/joe.js +186 -6
- package/js/joe.min.js +1 -1
- package/package.json +1 -1
- package/readme.md +19 -0
- package/server/apps/aihub.js +2 -0
- package/server/fields/core.js +49 -0
- package/server/modules/MCP.js +1237 -847
- package/server/modules/ThoughtPipeline.js +599 -0
- package/server/plugins/chatgpt.js +76 -7
- package/server/schemas/ai_pipeline.js +90 -0
- package/server/schemas/ai_response.js +165 -16
- package/server/schemas/task.js +4 -1
- package/server/schemas/thought.js +332 -0
- package/server/webconfig.js +1 -1
|
@@ -5104,9 +5104,145 @@ this.renderHTMLContent = function(specs){
|
|
|
5104
5104
|
} else if (elem.msRequestFullscreen) { /* IE11 */
|
|
5105
5105
|
elem.msRequestFullscreen();
|
|
5106
5106
|
}
|
|
5107
|
-
}
|
|
5107
|
+
};
|
|
5108
5108
|
encapsulateFieldType('code',self.renderCodeField,
|
|
5109
5109
|
{fullscreen:this.fullScreenCodeEditor});
|
|
5110
|
+
|
|
5111
|
+
/*----------------------------->
|
|
5112
|
+
Q.1 | JSON Field
|
|
5113
|
+
<-----------------------------*/
|
|
5114
|
+
this.renderJsonField = function(prop){
|
|
5115
|
+
/*|{
|
|
5116
|
+
tags:'render,field,json',
|
|
5117
|
+
specs:'value,standard_field_properties',
|
|
5118
|
+
description:'JSON object editor using Ace in JSON mode; always pretty-prints on load/blur/save.'
|
|
5119
|
+
}|*/
|
|
5120
|
+
var height = (prop.height)?'style="height:'+prop.height+';"' : '';
|
|
5121
|
+
var editor_id = cuid();
|
|
5122
|
+
var rawValue = (typeof prop.value == "undefined") ? {} : prop.value;
|
|
5123
|
+
var displayValue;
|
|
5124
|
+
// Ensure we start from an object and pretty JSON string
|
|
5125
|
+
if (typeof rawValue == "string") {
|
|
5126
|
+
try{
|
|
5127
|
+
rawValue = JSON.parse(rawValue);
|
|
5128
|
+
}catch(e){
|
|
5129
|
+
// fallback: leave as raw string, Ace/validation will handle parse errors on blur/save
|
|
5130
|
+
}
|
|
5131
|
+
}
|
|
5132
|
+
if (rawValue === null || typeof rawValue == "undefined") {
|
|
5133
|
+
rawValue = {};
|
|
5134
|
+
}
|
|
5135
|
+
if (typeof rawValue == "object") {
|
|
5136
|
+
try{
|
|
5137
|
+
displayValue = JSON.stringify(rawValue,null,2);
|
|
5138
|
+
}catch(e){
|
|
5139
|
+
displayValue = "{}";
|
|
5140
|
+
}
|
|
5141
|
+
}else{
|
|
5142
|
+
// Non-object (number/boolean/etc.) – stringify as-is but still require valid JSON
|
|
5143
|
+
try{
|
|
5144
|
+
displayValue = JSON.stringify(rawValue,null,2);
|
|
5145
|
+
}catch(e){
|
|
5146
|
+
displayValue = "{}";
|
|
5147
|
+
}
|
|
5148
|
+
}
|
|
5149
|
+
var html =
|
|
5150
|
+
'<div class="clear joe-ace-holder joe-rendering-field joe-field" '
|
|
5151
|
+
+height+' data-ace_id="'+editor_id+'" data-ftype="ace" name="'+prop.name+'">'+
|
|
5152
|
+
'<textarea class="" id="'+editor_id+'" >'
|
|
5153
|
+
+(displayValue || "{}")+
|
|
5154
|
+
'</textarea>'+
|
|
5155
|
+
'</div>'+
|
|
5156
|
+
'<script>'+
|
|
5157
|
+
'try{\
|
|
5158
|
+
var editor = ace.edit("'+editor_id+'");\
|
|
5159
|
+
editor.setTheme("ace/theme/tomorrow");\
|
|
5160
|
+
editor.getSession().setUseWrapMode(true);\
|
|
5161
|
+
editor.getSession().setMode("ace/mode/json");\
|
|
5162
|
+
editor.setOptions({\
|
|
5163
|
+
enableBasicAutocompletion: true,\
|
|
5164
|
+
enableLiveAutocompletion: false\
|
|
5165
|
+
});\
|
|
5166
|
+
_joe.ace_editors["'+editor_id+'"] = editor;\
|
|
5167
|
+
}catch(e){ console && console.warn && console.warn("ACE json init error",e);}'
|
|
5168
|
+
+' </script>';
|
|
5169
|
+
return html;
|
|
5170
|
+
};
|
|
5171
|
+
// Helper to (re)parse and pretty-print a json field from its Ace editor.
|
|
5172
|
+
function _normalizeJsonField(fieldName,opts){
|
|
5173
|
+
opts = opts || {};
|
|
5174
|
+
var parent = getJoe(self.joe_index);
|
|
5175
|
+
var $holder = parent.overlay.find('.joe-ace-holder[name="'+fieldName+'"]');
|
|
5176
|
+
if(!$holder.length){ return { ok:true }; }
|
|
5177
|
+
var editorId = $holder.data('ace_id');
|
|
5178
|
+
var editor = _joe.ace_editors[editorId];
|
|
5179
|
+
if(!editor){ return { ok:true }; }
|
|
5180
|
+
var text = editor.getValue();
|
|
5181
|
+
if(!text || !text.trim()){
|
|
5182
|
+
// default to empty object
|
|
5183
|
+
text = '{}';
|
|
5184
|
+
}
|
|
5185
|
+
try{
|
|
5186
|
+
var parsed = JSON.parse(text);
|
|
5187
|
+
// must be an object; if not, still allow but keep as-is
|
|
5188
|
+
try{
|
|
5189
|
+
var pretty = JSON.stringify(parsed,null,2);
|
|
5190
|
+
editor.setValue(pretty,-1);
|
|
5191
|
+
}catch(_e){}
|
|
5192
|
+
$holder.removeClass('joe-field-error');
|
|
5193
|
+
return { ok:true, parsed:parsed };
|
|
5194
|
+
}catch(e){
|
|
5195
|
+
// Attempt a light-weight "loose JSON" fix for common cases:
|
|
5196
|
+
// - Unquoted identifier keys: { name:"Corey" } -> { "name":"Corey" }
|
|
5197
|
+
// - Single-quoted strings: { "name":'Corey' } -> { "name":"Corey" }
|
|
5198
|
+
// - Trailing commas: { "a":1, } -> { "a":1 }
|
|
5199
|
+
var fixed = text;
|
|
5200
|
+
try{
|
|
5201
|
+
// Quote bare identifier keys following { or , and before :
|
|
5202
|
+
fixed = fixed.replace(/([{\[],\s*|[{]\s*|,\s*)([A-Za-z_][A-Za-z0-9_]*)\s*:/g,function(m,prefix,key){
|
|
5203
|
+
return prefix+'"'+key+'":';
|
|
5204
|
+
});
|
|
5205
|
+
// Convert single-quoted strings to double-quoted strings
|
|
5206
|
+
fixed = fixed.replace(/'([^'\\]*(?:\\.[^'\\]*)*)'/g,'"$1"');
|
|
5207
|
+
// Remove trailing commas before } or ]
|
|
5208
|
+
fixed = fixed.replace(/,\s*([}\]])/g,'$1');
|
|
5209
|
+
|
|
5210
|
+
var reparsed = JSON.parse(fixed);
|
|
5211
|
+
try{
|
|
5212
|
+
var prettyFixed = JSON.stringify(reparsed,null,2);
|
|
5213
|
+
editor.setValue(prettyFixed,-1);
|
|
5214
|
+
}catch(_e2){}
|
|
5215
|
+
$holder.removeClass('joe-field-error');
|
|
5216
|
+
return { ok:true, parsed:reparsed };
|
|
5217
|
+
}catch(_fixErr){
|
|
5218
|
+
$holder.addClass('joe-field-error');
|
|
5219
|
+
if(opts.showMessage && parent.showMessage){
|
|
5220
|
+
parent.showMessage("Field '"+fieldName+"' must be valid JSON (object).");
|
|
5221
|
+
}
|
|
5222
|
+
return { ok:false, error:e };
|
|
5223
|
+
}
|
|
5224
|
+
}
|
|
5225
|
+
}
|
|
5226
|
+
encapsulateFieldType('json',self.renderJsonField,{
|
|
5227
|
+
ready:function(){
|
|
5228
|
+
// Attach blur handlers to normalize/validate json fields when panel shows
|
|
5229
|
+
var parent = getJoe(self.joe_index);
|
|
5230
|
+
parent.overlay.find('.joe-ace-holder[name]').each(function(){
|
|
5231
|
+
var name = $(this).attr('name');
|
|
5232
|
+
var field = self.getField(name);
|
|
5233
|
+
if(!field){ return true; }
|
|
5234
|
+
var ftype = (self.propAsFuncOrValue(field.type)||'').toLowerCase();
|
|
5235
|
+
if(ftype != 'json'){ return true; }
|
|
5236
|
+
var editorId = $(this).data('ace_id');
|
|
5237
|
+
var editor = _joe.ace_editors[editorId];
|
|
5238
|
+
if(!editor){ return true; }
|
|
5239
|
+
editor.on('blur',function(){
|
|
5240
|
+
_normalizeJsonField(name,{showMessage:false});
|
|
5241
|
+
});
|
|
5242
|
+
});
|
|
5243
|
+
},
|
|
5244
|
+
normalize:_normalizeJsonField
|
|
5245
|
+
});
|
|
5110
5246
|
/*----------------------------->
|
|
5111
5247
|
Q.2 | QR Field
|
|
5112
5248
|
<-----------------------------*/
|
|
@@ -7557,6 +7693,11 @@ Field Rendering Helpers
|
|
|
7557
7693
|
//ready objectlist
|
|
7558
7694
|
self.Fields.objectlist.ready();
|
|
7559
7695
|
|
|
7696
|
+
//ready json (Ace-based) fields
|
|
7697
|
+
if(self.Fields.json && self.Fields.json.ready){
|
|
7698
|
+
self.Fields.json.ready();
|
|
7699
|
+
}
|
|
7700
|
+
|
|
7560
7701
|
|
|
7561
7702
|
//sidebars
|
|
7562
7703
|
if(self.current.sidebars){
|
|
@@ -7682,10 +7823,26 @@ Field Rendering Helpers
|
|
|
7682
7823
|
var f,test_info;
|
|
7683
7824
|
for(var c in changes){
|
|
7684
7825
|
f = self.getField(c);
|
|
7685
|
-
|
|
7686
|
-
|
|
7687
7826
|
if(c[0] != '$' && c != 'joeUpdated' && f && f.type !='content' && !parseBoolean(f.passthrough)){
|
|
7688
|
-
|
|
7827
|
+
// Special handling for json fields: compare parsed objects so
|
|
7828
|
+
// whitespace/formatting-only changes are ignored.
|
|
7829
|
+
var ftype = (self.propAsFuncOrValue(f.type)||'').toLowerCase();
|
|
7830
|
+
if(ftype == 'json'){
|
|
7831
|
+
var orig = _joe.current.object[c];
|
|
7832
|
+
var rawNew = cc_construct[c];
|
|
7833
|
+
var sameJson = false;
|
|
7834
|
+
try{
|
|
7835
|
+
var parsedOrig = (typeof orig == "string") ? JSON.parse(orig) : orig;
|
|
7836
|
+
var parsedNew = (typeof rawNew == "string") ? JSON.parse(rawNew) : rawNew;
|
|
7837
|
+
sameJson = (JSON.stringify(parsedOrig) == JSON.stringify(parsedNew));
|
|
7838
|
+
}catch(_e){
|
|
7839
|
+
// parse failure means it is definitely a change that needs attention
|
|
7840
|
+
sameJson = false;
|
|
7841
|
+
}
|
|
7842
|
+
if(sameJson){
|
|
7843
|
+
continue;
|
|
7844
|
+
}
|
|
7845
|
+
}else if(JSON.stringify(_joe.current.object[c]) == JSON.stringify(cc_construct[c])){
|
|
7689
7846
|
continue;
|
|
7690
7847
|
}
|
|
7691
7848
|
if(['qrcode'].indexOf(f.type) != -1){
|
|
@@ -7988,6 +8145,27 @@ Field Rendering Helpers
|
|
|
7988
8145
|
}
|
|
7989
8146
|
var callback = callback || self.current.callback || (self.current.schema && self.current.schema.callback) || defaultCallback; //logit;
|
|
7990
8147
|
var newObj = self.constructObjectFromFields(self.joe_index);
|
|
8148
|
+
// Normalize json fields: parse to objects and block save on invalid JSON.
|
|
8149
|
+
if(_joe && _joe.current && _joe.current.fields){
|
|
8150
|
+
var jsonField, ftype, normResult;
|
|
8151
|
+
for(var i=0, tot=_joe.current.fields.length; i<tot; i++){
|
|
8152
|
+
jsonField = _joe.current.fields[i];
|
|
8153
|
+
ftype = (self.propAsFuncOrValue(jsonField.type)||'').toLowerCase();
|
|
8154
|
+
if(ftype != 'json'){ continue; }
|
|
8155
|
+
// Ensure editor content is normalized and valid
|
|
8156
|
+
normResult = self.Fields.json && self.Fields.json.normalize
|
|
8157
|
+
? self.Fields.json.normalize(jsonField.name,{showMessage:true})
|
|
8158
|
+
: { ok:true };
|
|
8159
|
+
if(!normResult.ok){
|
|
8160
|
+
// invalid JSON – do not proceed with save
|
|
8161
|
+
return false;
|
|
8162
|
+
}
|
|
8163
|
+
// Use parsed object if available; default to {} when missing
|
|
8164
|
+
var parsed = (normResult.parsed || (newObj[jsonField.name] && typeof newObj[jsonField.name] == "object"
|
|
8165
|
+
? newObj[jsonField.name] : {}));
|
|
8166
|
+
newObj[jsonField.name] = parsed;
|
|
8167
|
+
}
|
|
8168
|
+
}
|
|
7991
8169
|
newObj.joeUpdated = new Date();
|
|
7992
8170
|
overwrites = overwrites || {};
|
|
7993
8171
|
var obj = $.extend(newObj,overwrites);
|
|
@@ -10679,7 +10857,9 @@ logit(intent)
|
|
|
10679
10857
|
/*-------------------------------------------------------------------->
|
|
10680
10858
|
//Colors
|
|
10681
10859
|
<--------------------------------------------------------------------*/
|
|
10682
|
-
this.Colors={
|
|
10860
|
+
this.Colors={
|
|
10861
|
+
"ai":"#0D9488"
|
|
10862
|
+
}
|
|
10683
10863
|
this.Colors.priority = {
|
|
10684
10864
|
1:'#cc4500',
|
|
10685
10865
|
2:'#FFee33',
|
package/js/joe-ai.js
CHANGED
|
@@ -1675,6 +1675,63 @@
|
|
|
1675
1675
|
}
|
|
1676
1676
|
};
|
|
1677
1677
|
|
|
1678
|
+
/**
|
|
1679
|
+
* Run the Thought agent for the current schema object.
|
|
1680
|
+
* Used by the core `proposeThought` field.
|
|
1681
|
+
*/
|
|
1682
|
+
Ai.runProposeThought = function(scopeId, textareaId, model){
|
|
1683
|
+
try{
|
|
1684
|
+
if (!scopeId) {
|
|
1685
|
+
alert('Save the item before proposing thoughts.');
|
|
1686
|
+
return;
|
|
1687
|
+
}
|
|
1688
|
+
var ta = document.getElementById(textareaId);
|
|
1689
|
+
if (!ta) {
|
|
1690
|
+
alert('Prompt field not found.');
|
|
1691
|
+
return;
|
|
1692
|
+
}
|
|
1693
|
+
var prompt = (ta.value || '').trim();
|
|
1694
|
+
if (!prompt) {
|
|
1695
|
+
alert('Please enter a prompt for the Thought run.');
|
|
1696
|
+
return;
|
|
1697
|
+
}
|
|
1698
|
+
var params = {
|
|
1699
|
+
agent_id: 'thought_agent_default',
|
|
1700
|
+
scope_id: scopeId,
|
|
1701
|
+
user_input: prompt
|
|
1702
|
+
};
|
|
1703
|
+
if (model) {
|
|
1704
|
+
params.model = model;
|
|
1705
|
+
}
|
|
1706
|
+
var body = {
|
|
1707
|
+
jsonrpc: '2.0',
|
|
1708
|
+
id: String(Date.now()),
|
|
1709
|
+
method: 'runThoughtAgent',
|
|
1710
|
+
params: params
|
|
1711
|
+
};
|
|
1712
|
+
fetch('/mcp', {
|
|
1713
|
+
method: 'POST',
|
|
1714
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1715
|
+
body: JSON.stringify(body)
|
|
1716
|
+
}).then(function(res){
|
|
1717
|
+
return res.json();
|
|
1718
|
+
}).then(function(payload){
|
|
1719
|
+
var result = (payload && (payload.result || payload)) || {};
|
|
1720
|
+
var count = result.proposed_thoughts_count || 0;
|
|
1721
|
+
if (window._joe && _joe.toast) {
|
|
1722
|
+
_joe.toast('Thought agent run complete. Proposed ' + count + ' thoughts.');
|
|
1723
|
+
} else {
|
|
1724
|
+
alert('Thought agent run complete. Proposed ' + count + ' thoughts.');
|
|
1725
|
+
}
|
|
1726
|
+
}).catch(function(err){
|
|
1727
|
+
console.error('Ai.runProposeThought error', err);
|
|
1728
|
+
alert('Failed to run Thought agent: ' + (err && err.message || err));
|
|
1729
|
+
});
|
|
1730
|
+
}catch(e){
|
|
1731
|
+
console.error('Ai.runProposeThought error', e);
|
|
1732
|
+
}
|
|
1733
|
+
};
|
|
1734
|
+
|
|
1678
1735
|
Ai.applyAutofillPatch = function(patch = {}){
|
|
1679
1736
|
Object.keys(patch).forEach(function(fname){
|
|
1680
1737
|
try {
|
package/js/joe.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* --------------------------------------------------------
|
|
2
2
|
*
|
|
3
|
-
* json-object-editor - v0.10.
|
|
3
|
+
* json-object-editor - v0.10.653
|
|
4
4
|
* Created by: Corey Hadden
|
|
5
5
|
*
|
|
6
6
|
* -------------------------------------------------------- */
|
|
@@ -5110,9 +5110,145 @@ this.renderHTMLContent = function(specs){
|
|
|
5110
5110
|
} else if (elem.msRequestFullscreen) { /* IE11 */
|
|
5111
5111
|
elem.msRequestFullscreen();
|
|
5112
5112
|
}
|
|
5113
|
-
}
|
|
5113
|
+
};
|
|
5114
5114
|
encapsulateFieldType('code',self.renderCodeField,
|
|
5115
5115
|
{fullscreen:this.fullScreenCodeEditor});
|
|
5116
|
+
|
|
5117
|
+
/*----------------------------->
|
|
5118
|
+
Q.1 | JSON Field
|
|
5119
|
+
<-----------------------------*/
|
|
5120
|
+
this.renderJsonField = function(prop){
|
|
5121
|
+
/*|{
|
|
5122
|
+
tags:'render,field,json',
|
|
5123
|
+
specs:'value,standard_field_properties',
|
|
5124
|
+
description:'JSON object editor using Ace in JSON mode; always pretty-prints on load/blur/save.'
|
|
5125
|
+
}|*/
|
|
5126
|
+
var height = (prop.height)?'style="height:'+prop.height+';"' : '';
|
|
5127
|
+
var editor_id = cuid();
|
|
5128
|
+
var rawValue = (typeof prop.value == "undefined") ? {} : prop.value;
|
|
5129
|
+
var displayValue;
|
|
5130
|
+
// Ensure we start from an object and pretty JSON string
|
|
5131
|
+
if (typeof rawValue == "string") {
|
|
5132
|
+
try{
|
|
5133
|
+
rawValue = JSON.parse(rawValue);
|
|
5134
|
+
}catch(e){
|
|
5135
|
+
// fallback: leave as raw string, Ace/validation will handle parse errors on blur/save
|
|
5136
|
+
}
|
|
5137
|
+
}
|
|
5138
|
+
if (rawValue === null || typeof rawValue == "undefined") {
|
|
5139
|
+
rawValue = {};
|
|
5140
|
+
}
|
|
5141
|
+
if (typeof rawValue == "object") {
|
|
5142
|
+
try{
|
|
5143
|
+
displayValue = JSON.stringify(rawValue,null,2);
|
|
5144
|
+
}catch(e){
|
|
5145
|
+
displayValue = "{}";
|
|
5146
|
+
}
|
|
5147
|
+
}else{
|
|
5148
|
+
// Non-object (number/boolean/etc.) – stringify as-is but still require valid JSON
|
|
5149
|
+
try{
|
|
5150
|
+
displayValue = JSON.stringify(rawValue,null,2);
|
|
5151
|
+
}catch(e){
|
|
5152
|
+
displayValue = "{}";
|
|
5153
|
+
}
|
|
5154
|
+
}
|
|
5155
|
+
var html =
|
|
5156
|
+
'<div class="clear joe-ace-holder joe-rendering-field joe-field" '
|
|
5157
|
+
+height+' data-ace_id="'+editor_id+'" data-ftype="ace" name="'+prop.name+'">'+
|
|
5158
|
+
'<textarea class="" id="'+editor_id+'" >'
|
|
5159
|
+
+(displayValue || "{}")+
|
|
5160
|
+
'</textarea>'+
|
|
5161
|
+
'</div>'+
|
|
5162
|
+
'<script>'+
|
|
5163
|
+
'try{\
|
|
5164
|
+
var editor = ace.edit("'+editor_id+'");\
|
|
5165
|
+
editor.setTheme("ace/theme/tomorrow");\
|
|
5166
|
+
editor.getSession().setUseWrapMode(true);\
|
|
5167
|
+
editor.getSession().setMode("ace/mode/json");\
|
|
5168
|
+
editor.setOptions({\
|
|
5169
|
+
enableBasicAutocompletion: true,\
|
|
5170
|
+
enableLiveAutocompletion: false\
|
|
5171
|
+
});\
|
|
5172
|
+
_joe.ace_editors["'+editor_id+'"] = editor;\
|
|
5173
|
+
}catch(e){ console && console.warn && console.warn("ACE json init error",e);}'
|
|
5174
|
+
+' </script>';
|
|
5175
|
+
return html;
|
|
5176
|
+
};
|
|
5177
|
+
// Helper to (re)parse and pretty-print a json field from its Ace editor.
|
|
5178
|
+
function _normalizeJsonField(fieldName,opts){
|
|
5179
|
+
opts = opts || {};
|
|
5180
|
+
var parent = getJoe(self.joe_index);
|
|
5181
|
+
var $holder = parent.overlay.find('.joe-ace-holder[name="'+fieldName+'"]');
|
|
5182
|
+
if(!$holder.length){ return { ok:true }; }
|
|
5183
|
+
var editorId = $holder.data('ace_id');
|
|
5184
|
+
var editor = _joe.ace_editors[editorId];
|
|
5185
|
+
if(!editor){ return { ok:true }; }
|
|
5186
|
+
var text = editor.getValue();
|
|
5187
|
+
if(!text || !text.trim()){
|
|
5188
|
+
// default to empty object
|
|
5189
|
+
text = '{}';
|
|
5190
|
+
}
|
|
5191
|
+
try{
|
|
5192
|
+
var parsed = JSON.parse(text);
|
|
5193
|
+
// must be an object; if not, still allow but keep as-is
|
|
5194
|
+
try{
|
|
5195
|
+
var pretty = JSON.stringify(parsed,null,2);
|
|
5196
|
+
editor.setValue(pretty,-1);
|
|
5197
|
+
}catch(_e){}
|
|
5198
|
+
$holder.removeClass('joe-field-error');
|
|
5199
|
+
return { ok:true, parsed:parsed };
|
|
5200
|
+
}catch(e){
|
|
5201
|
+
// Attempt a light-weight "loose JSON" fix for common cases:
|
|
5202
|
+
// - Unquoted identifier keys: { name:"Corey" } -> { "name":"Corey" }
|
|
5203
|
+
// - Single-quoted strings: { "name":'Corey' } -> { "name":"Corey" }
|
|
5204
|
+
// - Trailing commas: { "a":1, } -> { "a":1 }
|
|
5205
|
+
var fixed = text;
|
|
5206
|
+
try{
|
|
5207
|
+
// Quote bare identifier keys following { or , and before :
|
|
5208
|
+
fixed = fixed.replace(/([{\[],\s*|[{]\s*|,\s*)([A-Za-z_][A-Za-z0-9_]*)\s*:/g,function(m,prefix,key){
|
|
5209
|
+
return prefix+'"'+key+'":';
|
|
5210
|
+
});
|
|
5211
|
+
// Convert single-quoted strings to double-quoted strings
|
|
5212
|
+
fixed = fixed.replace(/'([^'\\]*(?:\\.[^'\\]*)*)'/g,'"$1"');
|
|
5213
|
+
// Remove trailing commas before } or ]
|
|
5214
|
+
fixed = fixed.replace(/,\s*([}\]])/g,'$1');
|
|
5215
|
+
|
|
5216
|
+
var reparsed = JSON.parse(fixed);
|
|
5217
|
+
try{
|
|
5218
|
+
var prettyFixed = JSON.stringify(reparsed,null,2);
|
|
5219
|
+
editor.setValue(prettyFixed,-1);
|
|
5220
|
+
}catch(_e2){}
|
|
5221
|
+
$holder.removeClass('joe-field-error');
|
|
5222
|
+
return { ok:true, parsed:reparsed };
|
|
5223
|
+
}catch(_fixErr){
|
|
5224
|
+
$holder.addClass('joe-field-error');
|
|
5225
|
+
if(opts.showMessage && parent.showMessage){
|
|
5226
|
+
parent.showMessage("Field '"+fieldName+"' must be valid JSON (object).");
|
|
5227
|
+
}
|
|
5228
|
+
return { ok:false, error:e };
|
|
5229
|
+
}
|
|
5230
|
+
}
|
|
5231
|
+
}
|
|
5232
|
+
encapsulateFieldType('json',self.renderJsonField,{
|
|
5233
|
+
ready:function(){
|
|
5234
|
+
// Attach blur handlers to normalize/validate json fields when panel shows
|
|
5235
|
+
var parent = getJoe(self.joe_index);
|
|
5236
|
+
parent.overlay.find('.joe-ace-holder[name]').each(function(){
|
|
5237
|
+
var name = $(this).attr('name');
|
|
5238
|
+
var field = self.getField(name);
|
|
5239
|
+
if(!field){ return true; }
|
|
5240
|
+
var ftype = (self.propAsFuncOrValue(field.type)||'').toLowerCase();
|
|
5241
|
+
if(ftype != 'json'){ return true; }
|
|
5242
|
+
var editorId = $(this).data('ace_id');
|
|
5243
|
+
var editor = _joe.ace_editors[editorId];
|
|
5244
|
+
if(!editor){ return true; }
|
|
5245
|
+
editor.on('blur',function(){
|
|
5246
|
+
_normalizeJsonField(name,{showMessage:false});
|
|
5247
|
+
});
|
|
5248
|
+
});
|
|
5249
|
+
},
|
|
5250
|
+
normalize:_normalizeJsonField
|
|
5251
|
+
});
|
|
5116
5252
|
/*----------------------------->
|
|
5117
5253
|
Q.2 | QR Field
|
|
5118
5254
|
<-----------------------------*/
|
|
@@ -7563,6 +7699,11 @@ Field Rendering Helpers
|
|
|
7563
7699
|
//ready objectlist
|
|
7564
7700
|
self.Fields.objectlist.ready();
|
|
7565
7701
|
|
|
7702
|
+
//ready json (Ace-based) fields
|
|
7703
|
+
if(self.Fields.json && self.Fields.json.ready){
|
|
7704
|
+
self.Fields.json.ready();
|
|
7705
|
+
}
|
|
7706
|
+
|
|
7566
7707
|
|
|
7567
7708
|
//sidebars
|
|
7568
7709
|
if(self.current.sidebars){
|
|
@@ -7688,10 +7829,26 @@ Field Rendering Helpers
|
|
|
7688
7829
|
var f,test_info;
|
|
7689
7830
|
for(var c in changes){
|
|
7690
7831
|
f = self.getField(c);
|
|
7691
|
-
|
|
7692
|
-
|
|
7693
7832
|
if(c[0] != '$' && c != 'joeUpdated' && f && f.type !='content' && !parseBoolean(f.passthrough)){
|
|
7694
|
-
|
|
7833
|
+
// Special handling for json fields: compare parsed objects so
|
|
7834
|
+
// whitespace/formatting-only changes are ignored.
|
|
7835
|
+
var ftype = (self.propAsFuncOrValue(f.type)||'').toLowerCase();
|
|
7836
|
+
if(ftype == 'json'){
|
|
7837
|
+
var orig = _joe.current.object[c];
|
|
7838
|
+
var rawNew = cc_construct[c];
|
|
7839
|
+
var sameJson = false;
|
|
7840
|
+
try{
|
|
7841
|
+
var parsedOrig = (typeof orig == "string") ? JSON.parse(orig) : orig;
|
|
7842
|
+
var parsedNew = (typeof rawNew == "string") ? JSON.parse(rawNew) : rawNew;
|
|
7843
|
+
sameJson = (JSON.stringify(parsedOrig) == JSON.stringify(parsedNew));
|
|
7844
|
+
}catch(_e){
|
|
7845
|
+
// parse failure means it is definitely a change that needs attention
|
|
7846
|
+
sameJson = false;
|
|
7847
|
+
}
|
|
7848
|
+
if(sameJson){
|
|
7849
|
+
continue;
|
|
7850
|
+
}
|
|
7851
|
+
}else if(JSON.stringify(_joe.current.object[c]) == JSON.stringify(cc_construct[c])){
|
|
7695
7852
|
continue;
|
|
7696
7853
|
}
|
|
7697
7854
|
if(['qrcode'].indexOf(f.type) != -1){
|
|
@@ -7994,6 +8151,27 @@ Field Rendering Helpers
|
|
|
7994
8151
|
}
|
|
7995
8152
|
var callback = callback || self.current.callback || (self.current.schema && self.current.schema.callback) || defaultCallback; //logit;
|
|
7996
8153
|
var newObj = self.constructObjectFromFields(self.joe_index);
|
|
8154
|
+
// Normalize json fields: parse to objects and block save on invalid JSON.
|
|
8155
|
+
if(_joe && _joe.current && _joe.current.fields){
|
|
8156
|
+
var jsonField, ftype, normResult;
|
|
8157
|
+
for(var i=0, tot=_joe.current.fields.length; i<tot; i++){
|
|
8158
|
+
jsonField = _joe.current.fields[i];
|
|
8159
|
+
ftype = (self.propAsFuncOrValue(jsonField.type)||'').toLowerCase();
|
|
8160
|
+
if(ftype != 'json'){ continue; }
|
|
8161
|
+
// Ensure editor content is normalized and valid
|
|
8162
|
+
normResult = self.Fields.json && self.Fields.json.normalize
|
|
8163
|
+
? self.Fields.json.normalize(jsonField.name,{showMessage:true})
|
|
8164
|
+
: { ok:true };
|
|
8165
|
+
if(!normResult.ok){
|
|
8166
|
+
// invalid JSON – do not proceed with save
|
|
8167
|
+
return false;
|
|
8168
|
+
}
|
|
8169
|
+
// Use parsed object if available; default to {} when missing
|
|
8170
|
+
var parsed = (normResult.parsed || (newObj[jsonField.name] && typeof newObj[jsonField.name] == "object"
|
|
8171
|
+
? newObj[jsonField.name] : {}));
|
|
8172
|
+
newObj[jsonField.name] = parsed;
|
|
8173
|
+
}
|
|
8174
|
+
}
|
|
7997
8175
|
newObj.joeUpdated = new Date();
|
|
7998
8176
|
overwrites = overwrites || {};
|
|
7999
8177
|
var obj = $.extend(newObj,overwrites);
|
|
@@ -10685,7 +10863,9 @@ logit(intent)
|
|
|
10685
10863
|
/*-------------------------------------------------------------------->
|
|
10686
10864
|
//Colors
|
|
10687
10865
|
<--------------------------------------------------------------------*/
|
|
10688
|
-
this.Colors={
|
|
10866
|
+
this.Colors={
|
|
10867
|
+
"ai":"#0D9488"
|
|
10868
|
+
}
|
|
10689
10869
|
this.Colors.priority = {
|
|
10690
10870
|
1:'#cc4500',
|
|
10691
10871
|
2:'#FFee33',
|