json-object-editor 0.10.610 → 0.10.623
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 +8 -0
- package/_www/mcp-nav.js +1 -0
- package/app.js +26 -2
- package/css/joe-styles.css +1 -0
- package/css/joe.css +2 -1
- package/css/joe.min.css +1 -1
- package/js/JsonObjectEditor.jquery.craydent.js +27 -53
- package/js/joe-ai.js +399 -0
- package/js/joe.js +28 -54
- package/js/joe.min.js +1 -1
- package/package.json +2 -2
- package/readme.md +663 -526
- package/server/app-config.js +2 -1
- package/server/fields/core.js +35 -17
- package/server/modules/Server.js +50 -0
- package/server/modules/Storage.js +7 -1
- package/server/modules/Utils.js +2 -1
- package/server/plugins/awsConnect.js +32 -6
- package/server/plugins/chatgpt-assistants.js +3 -3
- package/server/plugins/chatgpt-responses.js +45 -0
- package/server/plugins/chatgpt.js +729 -0
- package/server/schemas/ai_assistant.js +255 -0
- package/server/schemas/ai_conversation.js +34 -0
- package/server/schemas/ai_prompt.js +323 -0
- package/server/schemas/ai_response.js +217 -0
- package/server/schemas/ai_tool.js +30 -0
- package/server/schemas/ai_widget_conversation.js +110 -0
- package/server/schemas/task.js +783 -778
- package/server/webconfig.js +3 -1
package/js/joe-ai.js
CHANGED
|
@@ -408,6 +408,288 @@
|
|
|
408
408
|
}
|
|
409
409
|
customElements.define('joe-object', JoeObject);
|
|
410
410
|
|
|
411
|
+
// ---------- Joe AI Widget: embeddable chat for any site ----------
|
|
412
|
+
class JoeAIWidget extends HTMLElement {
|
|
413
|
+
constructor() {
|
|
414
|
+
super();
|
|
415
|
+
this.attachShadow({ mode: 'open' });
|
|
416
|
+
this.endpoint = this.getAttribute('endpoint') || ''; // base URL to JOE; default same origin
|
|
417
|
+
this.conversation_id = this.getAttribute('conversation_id') || null;
|
|
418
|
+
this.assistant_id = this.getAttribute('assistant_id') || null;
|
|
419
|
+
this.ai_assistant_id = this.getAttribute('ai_assistant_id') || null;
|
|
420
|
+
this.model = this.getAttribute('model') || null;
|
|
421
|
+
this.messages = [];
|
|
422
|
+
this._ui = {};
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
connectedCallback() {
|
|
426
|
+
this.renderShell();
|
|
427
|
+
if (this.conversation_id) {
|
|
428
|
+
this.loadHistory();
|
|
429
|
+
} else {
|
|
430
|
+
this.startConversation();
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
get apiBase() {
|
|
435
|
+
return this.endpoint || '';
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
renderShell() {
|
|
439
|
+
const style = document.createElement('style');
|
|
440
|
+
style.textContent = `
|
|
441
|
+
:host {
|
|
442
|
+
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
443
|
+
display: block;
|
|
444
|
+
max-width: 420px;
|
|
445
|
+
border: 1px solid #ddd;
|
|
446
|
+
border-radius: 8px;
|
|
447
|
+
box-shadow: 0 2px 6px rgba(0,0,0,0.08);
|
|
448
|
+
overflow: hidden;
|
|
449
|
+
background: #fff;
|
|
450
|
+
}
|
|
451
|
+
.wrapper {
|
|
452
|
+
display: flex;
|
|
453
|
+
flex-direction: column;
|
|
454
|
+
height: 100%;
|
|
455
|
+
}
|
|
456
|
+
.header {
|
|
457
|
+
padding: 8px 12px;
|
|
458
|
+
background: #1f2933;
|
|
459
|
+
color: #f9fafb;
|
|
460
|
+
font-size: 13px;
|
|
461
|
+
display: flex;
|
|
462
|
+
align-items: center;
|
|
463
|
+
justify-content: space-between;
|
|
464
|
+
}
|
|
465
|
+
.title {
|
|
466
|
+
font-weight: 600;
|
|
467
|
+
}
|
|
468
|
+
.status {
|
|
469
|
+
font-size: 11px;
|
|
470
|
+
opacity: 0.8;
|
|
471
|
+
}
|
|
472
|
+
.messages {
|
|
473
|
+
padding: 10px;
|
|
474
|
+
height: 260px;
|
|
475
|
+
overflow-y: auto;
|
|
476
|
+
background: #f5f7fa;
|
|
477
|
+
font-size: 13px;
|
|
478
|
+
}
|
|
479
|
+
.msg {
|
|
480
|
+
margin-bottom: 8px;
|
|
481
|
+
max-width: 90%;
|
|
482
|
+
clear: both;
|
|
483
|
+
}
|
|
484
|
+
.msg.user {
|
|
485
|
+
text-align: right;
|
|
486
|
+
margin-left: auto;
|
|
487
|
+
}
|
|
488
|
+
.bubble {
|
|
489
|
+
display: inline-block;
|
|
490
|
+
padding: 6px 8px;
|
|
491
|
+
border-radius: 10px;
|
|
492
|
+
line-height: 1.4;
|
|
493
|
+
}
|
|
494
|
+
.user .bubble {
|
|
495
|
+
background: #2563eb;
|
|
496
|
+
color: #fff;
|
|
497
|
+
}
|
|
498
|
+
.assistant .bubble {
|
|
499
|
+
background: #e5e7eb;
|
|
500
|
+
color: #111827;
|
|
501
|
+
}
|
|
502
|
+
.footer {
|
|
503
|
+
border-top: 1px solid #e5e7eb;
|
|
504
|
+
padding: 6px;
|
|
505
|
+
display: flex;
|
|
506
|
+
gap: 6px;
|
|
507
|
+
align-items: center;
|
|
508
|
+
}
|
|
509
|
+
textarea {
|
|
510
|
+
flex: 1;
|
|
511
|
+
resize: none;
|
|
512
|
+
border-radius: 6px;
|
|
513
|
+
border: 1px solid #d1d5db;
|
|
514
|
+
padding: 6px 8px;
|
|
515
|
+
font-size: 13px;
|
|
516
|
+
min-height: 34px;
|
|
517
|
+
max-height: 80px;
|
|
518
|
+
}
|
|
519
|
+
button {
|
|
520
|
+
border-radius: 6px;
|
|
521
|
+
border: none;
|
|
522
|
+
background: #2563eb;
|
|
523
|
+
color: #fff;
|
|
524
|
+
padding: 6px 10px;
|
|
525
|
+
font-size: 13px;
|
|
526
|
+
cursor: pointer;
|
|
527
|
+
white-space: nowrap;
|
|
528
|
+
}
|
|
529
|
+
button:disabled {
|
|
530
|
+
opacity: 0.6;
|
|
531
|
+
cursor: default;
|
|
532
|
+
}
|
|
533
|
+
`;
|
|
534
|
+
|
|
535
|
+
const wrapper = document.createElement('div');
|
|
536
|
+
wrapper.className = 'wrapper';
|
|
537
|
+
wrapper.innerHTML = `
|
|
538
|
+
<div class="header">
|
|
539
|
+
<div class="title">${this.getAttribute('title') || 'AI Assistant'}</div>
|
|
540
|
+
<div class="status" id="status">connecting…</div>
|
|
541
|
+
</div>
|
|
542
|
+
<div class="messages" id="messages"></div>
|
|
543
|
+
<div class="footer">
|
|
544
|
+
<textarea id="input" placeholder="${this.getAttribute('placeholder') || 'Ask me anything…'}"></textarea>
|
|
545
|
+
<button id="send">Send</button>
|
|
546
|
+
</div>
|
|
547
|
+
`;
|
|
548
|
+
|
|
549
|
+
this.shadowRoot.innerHTML = '';
|
|
550
|
+
this.shadowRoot.appendChild(style);
|
|
551
|
+
this.shadowRoot.appendChild(wrapper);
|
|
552
|
+
|
|
553
|
+
this._ui.messages = this.shadowRoot.getElementById('messages');
|
|
554
|
+
this._ui.status = this.shadowRoot.getElementById('status');
|
|
555
|
+
this._ui.input = this.shadowRoot.getElementById('input');
|
|
556
|
+
this._ui.send = this.shadowRoot.getElementById('send');
|
|
557
|
+
|
|
558
|
+
this._ui.send.addEventListener('click', () => this.sendMessage());
|
|
559
|
+
this._ui.input.addEventListener('keydown', (e) => {
|
|
560
|
+
if (e.key === 'Enter' && !e.shiftKey) {
|
|
561
|
+
e.preventDefault();
|
|
562
|
+
this.sendMessage();
|
|
563
|
+
}
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
setStatus(text) {
|
|
568
|
+
if (this._ui.status) this._ui.status.textContent = text;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
renderMessages() {
|
|
572
|
+
if (!this._ui.messages) return;
|
|
573
|
+
this._ui.messages.innerHTML = (this.messages || []).map(m => {
|
|
574
|
+
const role = m.role || 'assistant';
|
|
575
|
+
const safe = (m.content || '').replace(/</g, '<').replace(/>/g, '>');
|
|
576
|
+
return `<div class="msg ${role}"><div class="bubble">${safe}</div></div>`;
|
|
577
|
+
}).join('');
|
|
578
|
+
this._ui.messages.scrollTop = this._ui.messages.scrollHeight;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
async startConversation() {
|
|
582
|
+
try {
|
|
583
|
+
this.setStatus('connecting…');
|
|
584
|
+
const payload = {
|
|
585
|
+
model: this.model || undefined,
|
|
586
|
+
ai_assistant_id: this.getAttribute('ai_assistant_id') || undefined,
|
|
587
|
+
source: this.getAttribute('source') || 'widget'
|
|
588
|
+
};
|
|
589
|
+
const resp = await fetch(this.apiBase + '/API/plugin/chatgpt/widgetStart', {
|
|
590
|
+
method: 'POST',
|
|
591
|
+
headers: { 'Content-Type': 'application/json' },
|
|
592
|
+
body: JSON.stringify(payload)
|
|
593
|
+
}).then(r => r.json());
|
|
594
|
+
|
|
595
|
+
if (!resp || resp.success !== true) {
|
|
596
|
+
const msg = (resp && resp.error) || 'Failed to start conversation';
|
|
597
|
+
this.setStatus('error: ' + msg);
|
|
598
|
+
this.messages.push({ role:'assistant', content:'[Error starting conversation: '+msg+']', created_at:new Date().toISOString() });
|
|
599
|
+
this.renderMessages();
|
|
600
|
+
console.error('widgetStart error', resp);
|
|
601
|
+
return;
|
|
602
|
+
}
|
|
603
|
+
this.conversation_id = resp.conversation_id;
|
|
604
|
+
this.setAttribute('conversation_id', this.conversation_id);
|
|
605
|
+
this.assistant_id = resp.assistant_id || this.assistant_id;
|
|
606
|
+
this.model = resp.model || this.model;
|
|
607
|
+
this.messages = [];
|
|
608
|
+
this.renderMessages();
|
|
609
|
+
this.setStatus('online');
|
|
610
|
+
} catch (e) {
|
|
611
|
+
console.error('widgetStart exception', e);
|
|
612
|
+
this.setStatus('error');
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
async loadHistory() {
|
|
617
|
+
try {
|
|
618
|
+
this.setStatus('loading…');
|
|
619
|
+
const resp = await fetch(this.apiBase + '/API/plugin/chatgpt/widgetHistory?conversation_id=' + encodeURIComponent(this.conversation_id))
|
|
620
|
+
.then(r => r.json());
|
|
621
|
+
if (!resp || resp.success !== true) {
|
|
622
|
+
this.setStatus('online');
|
|
623
|
+
return;
|
|
624
|
+
}
|
|
625
|
+
this.assistant_id = resp.assistant_id || this.assistant_id;
|
|
626
|
+
this.model = resp.model || this.model;
|
|
627
|
+
this.messages = resp.messages || [];
|
|
628
|
+
this.renderMessages();
|
|
629
|
+
this.setStatus('online');
|
|
630
|
+
} catch (e) {
|
|
631
|
+
console.error('widgetHistory exception', e);
|
|
632
|
+
this.setStatus('online');
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
async sendMessage() {
|
|
637
|
+
const input = this._ui.input;
|
|
638
|
+
if (!input) return;
|
|
639
|
+
const text = input.value.trim();
|
|
640
|
+
if (!text) return;
|
|
641
|
+
if (!this.conversation_id) {
|
|
642
|
+
await this.startConversation();
|
|
643
|
+
if (!this.conversation_id) return;
|
|
644
|
+
}
|
|
645
|
+
input.value = '';
|
|
646
|
+
this._ui.send.disabled = true;
|
|
647
|
+
|
|
648
|
+
const userMsg = { role: 'user', content: text, created_at: new Date().toISOString() };
|
|
649
|
+
this.messages.push(userMsg);
|
|
650
|
+
this.renderMessages();
|
|
651
|
+
this.setStatus('thinking…');
|
|
652
|
+
|
|
653
|
+
try {
|
|
654
|
+
const payload = {
|
|
655
|
+
conversation_id: this.conversation_id,
|
|
656
|
+
content: text,
|
|
657
|
+
role: 'user',
|
|
658
|
+
assistant_id: this.assistant_id || undefined,
|
|
659
|
+
model: this.model || undefined
|
|
660
|
+
};
|
|
661
|
+
const resp = await fetch(this.apiBase + '/API/plugin/chatgpt/widgetMessage', {
|
|
662
|
+
method: 'POST',
|
|
663
|
+
headers: { 'Content-Type': 'application/json' },
|
|
664
|
+
body: JSON.stringify(payload)
|
|
665
|
+
}).then(r => r.json());
|
|
666
|
+
|
|
667
|
+
if (!resp || resp.success !== true) {
|
|
668
|
+
const msg = (resp && resp.error) || 'Failed to send message';
|
|
669
|
+
console.error('widgetMessage error', resp);
|
|
670
|
+
this.messages.push({ role:'assistant', content:'[Error: '+msg+']', created_at:new Date().toISOString() });
|
|
671
|
+
this.renderMessages();
|
|
672
|
+
this.setStatus('error: ' + msg);
|
|
673
|
+
} else {
|
|
674
|
+
this.assistant_id = resp.assistant_id || this.assistant_id;
|
|
675
|
+
this.model = resp.model || this.model;
|
|
676
|
+
this.messages = resp.messages || this.messages;
|
|
677
|
+
this.renderMessages();
|
|
678
|
+
this.setStatus('online');
|
|
679
|
+
}
|
|
680
|
+
} catch (e) {
|
|
681
|
+
console.error('widgetMessage exception', e);
|
|
682
|
+
this.setStatus('error');
|
|
683
|
+
} finally {
|
|
684
|
+
this._ui.send.disabled = false;
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
if (!customElements.get('joe-ai-widget')) {
|
|
690
|
+
customElements.define('joe-ai-widget', JoeAIWidget);
|
|
691
|
+
}
|
|
692
|
+
|
|
411
693
|
|
|
412
694
|
//**YES**
|
|
413
695
|
Ai.spawnChatHelper = async function(object_id,user_id=_joe.User._id,conversation_id) {
|
|
@@ -620,6 +902,123 @@
|
|
|
620
902
|
console.error("❌ injectSystemMessage failed:", err);
|
|
621
903
|
}
|
|
622
904
|
};
|
|
905
|
+
|
|
906
|
+
// ---------- Autofill (Completions) ----------
|
|
907
|
+
// Usage in schema button: onclick: "_joe.Ai.populateField(this, { prompt: 'Write a short summary', saveHistory: true })"
|
|
908
|
+
Ai.populateField = async function(dom, options = {}){
|
|
909
|
+
try{
|
|
910
|
+
const obj = _joe.current && _joe.current.object;
|
|
911
|
+
const schema = _joe.current && _joe.current.schema && _joe.current.schema.__schemaname;
|
|
912
|
+
if(!obj || !schema){ return alert('No current object/schema found'); }
|
|
913
|
+
|
|
914
|
+
const parentField = $(dom).parents('.joe-object-field');
|
|
915
|
+
const inferredField = parentField.data('name');
|
|
916
|
+
const fields = (options.fields && options.fields.length) ? options.fields : (inferredField ? [inferredField] : []);
|
|
917
|
+
if(!fields.length){ return alert('No target field detected. Pass options.fields or place the button inside a field.'); }
|
|
918
|
+
|
|
919
|
+
// UI feedback
|
|
920
|
+
const originalHtml = dom.innerHTML;
|
|
921
|
+
dom.disabled = true;
|
|
922
|
+
dom.innerHTML = (options.loadingLabel || 'Thinking...');
|
|
923
|
+
|
|
924
|
+
const payload = {
|
|
925
|
+
object_id: obj._id,
|
|
926
|
+
schema: schema,
|
|
927
|
+
fields: fields,
|
|
928
|
+
prompt: options.prompt || '',
|
|
929
|
+
assistant_id: options.assistant_id || undefined,
|
|
930
|
+
allow_web: !!options.allowWeb,
|
|
931
|
+
save_history: !!options.saveHistory,
|
|
932
|
+
save_itemtype: options.saveItemtype || undefined,
|
|
933
|
+
model: options.model || undefined
|
|
934
|
+
};
|
|
935
|
+
|
|
936
|
+
const resp = await fetch('/API/plugin/chatgpt/autofill', {
|
|
937
|
+
method: 'POST',
|
|
938
|
+
headers: { 'Content-Type': 'application/json' },
|
|
939
|
+
body: JSON.stringify(payload)
|
|
940
|
+
}).then(r => r.json());
|
|
941
|
+
|
|
942
|
+
if(!resp || resp.success !== true){
|
|
943
|
+
console.error('AI autofill error:', resp && resp.error);
|
|
944
|
+
alert('AI autofill failed' + (resp && resp.error ? (': ' + resp.error) : ''));
|
|
945
|
+
}else{
|
|
946
|
+
const patch = resp.patch || {};
|
|
947
|
+
Ai.applyAutofillPatch(patch);
|
|
948
|
+
if(options.autoSave === true){
|
|
949
|
+
_joe.updateObject(null, null, true, null, options.skipValidation === true);
|
|
950
|
+
}
|
|
951
|
+
if(options.openChatAfter === true){
|
|
952
|
+
_joe.Ai.spawnChatHelper(obj._id);
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
dom.disabled = false;
|
|
957
|
+
dom.innerHTML = originalHtml;
|
|
958
|
+
}catch(e){
|
|
959
|
+
console.error('populateField error', e);
|
|
960
|
+
alert('Error running AI autofill');
|
|
961
|
+
try{ dom.disabled = false; }catch(_e){}
|
|
962
|
+
}
|
|
963
|
+
};
|
|
964
|
+
|
|
965
|
+
Ai.applyAutofillPatch = function(patch = {}){
|
|
966
|
+
Object.keys(patch).forEach(function(fname){
|
|
967
|
+
Ai._setFieldValue(fname, patch[fname]);
|
|
968
|
+
});
|
|
969
|
+
};
|
|
970
|
+
|
|
971
|
+
Ai._setFieldValue = function(fieldName, value){
|
|
972
|
+
const $container = $(`.joe-object-field[data-name="${fieldName}"]`);
|
|
973
|
+
if(!$container.length){ return false; }
|
|
974
|
+
const $el = $container.find('.joe-field').eq(0);
|
|
975
|
+
if(!$el.length){ return false; }
|
|
976
|
+
|
|
977
|
+
const ftype = $el.data('ftype');
|
|
978
|
+
try{
|
|
979
|
+
switch(ftype){
|
|
980
|
+
case 'tinymce': {
|
|
981
|
+
const editorId = $el.data('texteditor_id');
|
|
982
|
+
const ed = window.tinymce && editorId ? window.tinymce.get(editorId) : null;
|
|
983
|
+
if(ed){ ed.setContent(value || ''); }
|
|
984
|
+
else { $el.val(value || ''); }
|
|
985
|
+
break;
|
|
986
|
+
}
|
|
987
|
+
case 'ckeditor': {
|
|
988
|
+
const editorId = $el.data('ckeditor_id');
|
|
989
|
+
const ed = (window.CKEDITOR && CKEDITOR.instances) ? CKEDITOR.instances[editorId] : null;
|
|
990
|
+
if(ed){ ed.setData(value || ''); }
|
|
991
|
+
else { $el.val(value || ''); }
|
|
992
|
+
break;
|
|
993
|
+
}
|
|
994
|
+
case 'ace': {
|
|
995
|
+
const aceId = $el.data('ace_id');
|
|
996
|
+
const ed = (_joe && _joe.ace_editors) ? _joe.ace_editors[aceId] : null;
|
|
997
|
+
if(ed){ ed.setValue(value || '', -1); }
|
|
998
|
+
else { $el.val(value || ''); }
|
|
999
|
+
break;
|
|
1000
|
+
}
|
|
1001
|
+
default: {
|
|
1002
|
+
if($el.is('select')){
|
|
1003
|
+
$el.val(value);
|
|
1004
|
+
}else if($el.is('input,textarea')){
|
|
1005
|
+
$el.val(value);
|
|
1006
|
+
}else{
|
|
1007
|
+
// Fallback: try innerText/innerHTML for custom components
|
|
1008
|
+
$el.text(typeof value === 'string' ? value : JSON.stringify(value));
|
|
1009
|
+
}
|
|
1010
|
+
$el.trigger('input');
|
|
1011
|
+
$el.trigger('change');
|
|
1012
|
+
break;
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
$container.addClass('changed');
|
|
1016
|
+
return true;
|
|
1017
|
+
}catch(e){
|
|
1018
|
+
console.warn('Failed to set field', fieldName, e);
|
|
1019
|
+
return false;
|
|
1020
|
+
}
|
|
1021
|
+
};
|
|
623
1022
|
|
|
624
1023
|
|
|
625
1024
|
// Attach AI to _joe
|
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.623
|
|
4
4
|
* Created by: Corey Hadden
|
|
5
5
|
*
|
|
6
6
|
* -------------------------------------------------------- */
|
|
@@ -9702,10 +9702,11 @@ logit(intent)
|
|
|
9702
9702
|
var field = data.field;
|
|
9703
9703
|
var bucket = field.bucketname || (_joe.Data.setting.where({name:'AWS_BUCKETNAME'})[0] || {value:''}).value;
|
|
9704
9704
|
if(!bucket){
|
|
9705
|
-
|
|
9705
|
+
var errMsg = 'AWS bucket not configured';
|
|
9706
|
+
callback && callback(errMsg);
|
|
9706
9707
|
return;
|
|
9707
9708
|
}
|
|
9708
|
-
var filename = file.
|
|
9709
|
+
var filename = file.name;
|
|
9709
9710
|
var directory = _joe.current.object._id;
|
|
9710
9711
|
var url = (field && self.propAsFuncOrValue(field.server_url)) ||
|
|
9711
9712
|
(location.port && '//'+__jsc.hostname+':'+__jsc.port+'/API/plugin/awsConnect/') ||
|
|
@@ -9720,72 +9721,45 @@ logit(intent)
|
|
|
9720
9721
|
Key:Key,
|
|
9721
9722
|
base64:file.base64,
|
|
9722
9723
|
extension:file.extension,
|
|
9723
|
-
|
|
9724
|
+
contentType:file.type,
|
|
9725
|
+
ACL:(field.hasOwnProperty('ACL') ? field.ACL : 'public-read')
|
|
9724
9726
|
},
|
|
9725
9727
|
success:function(response){
|
|
9726
9728
|
var url,filename;
|
|
9727
9729
|
if(!response.error){
|
|
9728
9730
|
logit(response);
|
|
9729
|
-
var
|
|
9730
|
-
|
|
9731
|
-
|
|
9732
|
-
|
|
9733
|
-
|
|
9734
|
-
|
|
9731
|
+
var url = response.url;
|
|
9732
|
+
if(!url){
|
|
9733
|
+
var bucket = response.bucket || (_joe.Data.setting.where({name:'AWS_BUCKETNAME'})[0] || {value:''}).value;
|
|
9734
|
+
var region = (_joe.Utils.Settings('AWS_S3CONFIG') ||{}).region;
|
|
9735
|
+
var prefix = (_joe.Data.setting.where({name:'AWS_S3PREFIX'})[0] || {value:''}).value || 'https://'+bucket+'.s3.'+((region)||'')+'.amazonaws.com/';
|
|
9736
|
+
url = prefix+response.Key;
|
|
9737
|
+
}
|
|
9735
9738
|
var filename = response.Key.replace(self.current.object._id+'/','');
|
|
9736
|
-
//TODO: change file status in list.
|
|
9737
|
-
|
|
9738
|
-
|
|
9739
|
-
}
|
|
9740
|
-
|
|
9741
|
-
callback(response.error,url,filename);
|
|
9742
|
-
}
|
|
9743
|
-
})
|
|
9744
|
-
},
|
|
9745
|
-
awsConnect:function(data,callback){
|
|
9746
|
-
var bucket = data.field.bucketname || (_joe.Data.setting.where({name:'AWS_BUCKETNAME'})[0] || {value:''}).value;
|
|
9747
|
-
if(!bucket){
|
|
9748
|
-
callback(err,data.base64);
|
|
9749
|
-
return;
|
|
9750
|
-
}
|
|
9751
|
-
var filename = _joe.current.object._id+data.extension;
|
|
9752
|
-
var directory = _joe.current.object.itemtype;
|
|
9753
|
-
var url = (field && self.propAsFuncOrValue(field.server_url)) ||
|
|
9754
|
-
(location.port && '//'+__jsc.hostname+':'+__jsc.port+'/API/plugin/awsConnect/') ||
|
|
9755
|
-
'//'+__jsc.hostname+'/API/plugin/awsConnect/';
|
|
9756
|
-
var Key = directory+'/'+filename;
|
|
9757
|
-
var field = data.field;
|
|
9758
|
-
$.ajax({
|
|
9759
|
-
url:url,
|
|
9760
|
-
type:'POST',
|
|
9761
|
-
data:{
|
|
9762
|
-
Key:Key,
|
|
9763
|
-
base64:data.base64,
|
|
9764
|
-
extension:data.extension,
|
|
9765
|
-
ACL:'public-read'
|
|
9766
|
-
},
|
|
9767
|
-
success:function(data){
|
|
9768
|
-
if(!data.error){
|
|
9769
|
-
logit(data);
|
|
9770
|
-
var bucket = data.bucket || (_joe.Data.setting.where({name:'AWS_BUCKETNAME'})[0] || {value:''}).value;
|
|
9771
|
-
|
|
9772
|
-
//var prefix = 'https://s3.amazonaws.com/'+bucket+'/';
|
|
9773
|
-
var prefix = 'https://'+bucket+'.s3.amazonaws.com/';
|
|
9774
|
-
|
|
9775
|
-
var url = prefix+data.Key;
|
|
9776
9739
|
if(field.url_field){
|
|
9777
9740
|
var nprop = {};
|
|
9778
9741
|
_joe.current.object[field.url_field] = url;
|
|
9779
9742
|
nprop[field.url_field] = url;
|
|
9780
|
-
/*$('.joe-field[name="'+field.url_field+'"]').val(url)*/
|
|
9781
9743
|
_joe.Fields.rerender(field.url_field,nprop);
|
|
9782
9744
|
}
|
|
9783
|
-
|
|
9784
|
-
|
|
9785
|
-
callback(data.error);
|
|
9745
|
+
|
|
9746
|
+
|
|
9786
9747
|
}
|
|
9748
|
+
|
|
9749
|
+
callback(response.error,url,filename);
|
|
9750
|
+
},
|
|
9751
|
+
error:function(xhr,status,err){
|
|
9752
|
+
var message = (xhr && (xhr.responseJSON && (xhr.responseJSON.error || xhr.responseJSON.code) || xhr.responseText)) || err || status || 'Upload failed';
|
|
9753
|
+
callback && callback(message);
|
|
9787
9754
|
}
|
|
9788
9755
|
})
|
|
9756
|
+
},
|
|
9757
|
+
awsConnect:function(data,callback){
|
|
9758
|
+
// Backward-compat wrapper: delegate to awsFileUpload
|
|
9759
|
+
return _joe.SERVER.Plugins.awsFileUpload({
|
|
9760
|
+
file: { base64:data.base64, extension:data.extension, type:data.contentType, name: (_joe.current.object._id+data.extension) },
|
|
9761
|
+
field: data.field
|
|
9762
|
+
}, callback);
|
|
9789
9763
|
}
|
|
9790
9764
|
},
|
|
9791
9765
|
ready:{
|