json-object-editor
Version:
JOE the Json Object Editor | Platform Edition
1,314 lines (1,180 loc) • 455 kB
JavaScript
/*/---------------------------------------------------------
Craydent LLC
Copyright 2014 (http://craydent.com/joe)
Dual licensed under the MIT or GPL Version 2 licenses.
(http://craydent.com/license)
---------------------------------------------------------/*/
//render field - self.renderObjectPropFieldUI
//render list item - self.renderListItems()
//single field list item -renderFieldListItem()
if($c.isMobile()){
document.getElementsByTagName('html')[0].className +=' touch joesmall-size';
}else{
document.getElementsByTagName('html')[0].className +=' no-touch joelarge-size';
}
window._joeEditingHash = false;
var _webworkers = false;
var _joeworker;
if (!!window.Worker) {
_webworkers = true
}
var joe_web_dir = '//' + location.hostname + ':' +
(location.port||((location.protocol=="https:")?443:80)) + "/JsonObjectEditor/";
if(location && location.origin == 'file://'){
joe_web_dir = location.href.slice(0,location.href.lastIndexOf('/')+1);
}
__docWriter =function(src,type,cancelWrite){
var type=type || 'js';
var html = '';
switch(type.toLowerCase()){
case 'js':
case 'javascript':
html +='<script type="text/javascript" src="'+src+'"></script>';
break;
case 'css':
case 'stylesheet':
html +='<link href="'+src+'" rel="stylesheet" type="text/css">';
break;
}
if(!cancelWrite){
document.write(html);
}
return html;
};
__loadAdditionalFiles = function(){
var bonuses ='';
if (typeof jQuery == 'undefined') {
//console.log('loading jquery');
/* bonuses+=
__docWriter(joe_web_dir+"js/libs/jquery-1.11.3.min.js",'js')+
__docWriter(joe_web_dir+"js/libs/jquery-ui.min.js");*/
__docWriter(joe_web_dir+"js/libs/jquery-1.11.3.min.js",'js')+
__docWriter(joe_web_dir+"js/libs/jquery-ui.min.js");
}
bonuses +=
__docWriter(joe_web_dir+"js/libs/jquery.ui.touch-punch.min.js");
if (typeof Craydent == 'undefined' || (!Craydent.VERSION || Craydent.VERSION < '1.7.37')) {
bonuses+= __docWriter(joe_web_dir+"js/libs/craydent-1.8.1.js",'js',true);
}
/*
bonuses+=
__docWriter(joe_web_dir+'css/joe.css','css','css',true)
+__docWriter(joe_web_dir+'js/ace/ace.js','js',true)
+__docWriter(joe_web_dir+'js/plugins/tinymce.min.js','js',true);
*/
document.write(bonuses);
};
function __require(file,callback){
var head=document.getElementsByTagName("head")[0];
var script=document.createElement('script');
script.src=file;
script.type='text/javascript';
//real browsers
script.onload=callback;
//Internet explorer
script.onreadystatechange = function() {
if (this.readyState == 'complete') {
callback();
}
}
head.appendChild(script);
}
/*var __joeFieldTypes = [
'text',
'select',
'code',
'rendering',
'date',
'boolean',
'geo',
'image',
'url',
'objectList',
'objectReference',
'group',
'content'
];*/
//__loadAdditionalFiles();
function JsonObjectEditor(specs){
var self = this;
var htmlRef = document.getElementsByTagName('html')[0];
self.initialDocumentTitle = document.title;
$c.TEMPLATE_VARS.push(
{variable:'/textarea',value:'</textarea>'},
{variable:'textarea',value:'<textarea>'},
{variable:'SERVER',value:'//'+$c.SERVER}
);
var initialized = false;
var colCount = 1;
var listMode = false;
var gridMode = false;
var tableMode = false,tableSpecs;
var multiEdit = false;
this.VERSION = '1.0.1';
window._joes = window._joes || [];
this.joe_index = window._joes.length;
if(!window._joes.length){window._joe = this;}
this.Error = {
log:[],
add:function(message,error,data){
var payload = {
caller: arguments.callee.caller,
callerargs:
arguments.callee.caller.arguments,
message:message,
error:error,
stack:new Error(error).stack,
data:data,
timestamp:(new Date()).toISOString(),
_id:cuid()
};
self.Error.log.push(payload);
logit('[error]: '+message);
},
show:function(){
self.show(self.Error.log,{schema:{
title:'${message}',
idprop:'_id',
listView:{
title: '<joe-title>${message}</joe-title><joe-subtitle>${timestamp}</joe-subtitle>',
listWindowTitle: 'Errors'
},
fields:[
'error:code',
'message',
'stack:code',
{name:'data',type:'content',run:function(data,obj){
return '<div><pre>'+tryEval(data)+'</pre></div>';
}},
'callerargs:code',
'timestamp:guid',
'_id'
]
}});
}
};
window._joes.push(this);
this.Cache = {
static:{},
list:[],
lookup:{},
clear:function(){
self.Cache.lookup = {};
self.Cache.list = [];
},
remove:function(id){
//self.cache.
},
get:function(id,specs){
var cacheitem = self.Cache.lookup[id];
if(cacheitem && typeof cacheitem.value == "function" && cacheitem.type =="callback"){
return cacheitem.value(cacheitem.data,cacheitem.id);
}
if(!cacheitem){
//if(autoadd){
var obj = self.search(id)[0]||false;
if(obj){
self.Cache.add(obj,{id:id})
return obj;
}
//}
return false;
}
return cacheitem.value;
},
callback:function(id){
var cacheitem = self.Cache.lookup[id];
if(typeof cacheitem.value == "function"){
return cacheitem.value(cacheitem.data,cacheitem.id);
}
else {logit('cache item is not a function');}
},
add:function(value,specs){
var specs = specs || {};
var obj = $.extend({
id:specs.id||cuid(),
value:value,
parent:self.joe_index
},specs);
self.Cache.list.push(obj.id);
self.Cache.lookup[obj.id] =obj;
return obj;
}
};
this.Cache.set = this.Cache.add;
this.history = [];
/*-------------------------------------------------------------------->
0 | CONFIG
<--------------------------------------------------------------------*/
var defaults = {
localStorage:false,
container:'body',
joeprofile:{
lockedFields:['joeUpdated'],
hiddenFields:[]
},
profiles:{},
fields:{},
schemas:{
'rendering': {
title:'HTML Rendering',
callback:function(){alert('yo');}
//fields:['id','name','thingType','legs','species','weight','color','gender'],
//_listID:'id',
//_listTitle:'${name} ${species}'
}},
compact:false,
useControlEnter:true,//to save
useEscapeKey:false,//to close window
autoInit:false,
autosave:10000,
dynamicDisplay:($(window).height() < 800 && $c.isMobile())?12:20,
sans:false,
listSubMenu:true,
documentTitle:false,//tmplate to set document title
style:{
inset:true,
cards:false
},
speechRecognition:false
};
this.specs = $.extend({},defaults,specs||{});
if(this.specs.localStorage && typeof(Storage) === "undefined"){
alert('no local storage');
this.specs.LocalStorage = false;
}
this.Indexes ={
_add:function(idprop,dataitem){
self.Indexes[idprop] = self.Indexes[idprop] || {};
self.Indexes[idprop][dataitem[idprop]] = dataitem;
},
_usage:0
};
this.Printer = {
init:function(){
if(!document.querySelector('print-joe')){
document.body.appendChild(document.createElement("print-joe"));
}
},
print:function(){
self.Printer.init();
var elmnt = document.getElementsByTagName("joe-panel-content")[0];
var cln = elmnt.cloneNode(true);
document.querySelector('print-joe').innerHTML ='';
document.querySelector('print-joe').appendChild(cln);
var panelContent = document.querySelector('print-joe joe-panel-content')
panelContent.className = 'joe-panel-content';
var activeNodes = document.querySelectorAll('print-joe joe-panel-content .joe-content-section.active');
if(activeNodes.length){
panelContent.innerHTML ='';
for (var i = 0; i < activeNodes.length; i++) {
panelContent.appendChild(activeNodes[i]);
}
}
window.print();
document.querySelector('print-joe').innerHTML ='';
}
}
this.Data = {};
this.Render = {
schema_icon: function (schema, classes) {
var icon = (self.schemas[schema] && self.schemas[schema].menuicon) || '';
icon && (icon = `<joe-icon class="${classes || ''}">${icon}</joe-icon>`);
return icon;
},
ref_chip: function (things, specs) {
specs = typeof specs === 'string' ? { cssclass: specs } : (specs || {});
const items = Array.isArray(things) ? things : things?.tags || [];
if (!items.length) return '';
const labelProp = specs.labelProp || 'name';
const tooltipProp = specs.tooltipProp === false ? null : (specs.tooltipProp || 'info');
let html = `<joe-chips class="${specs.cssclass || ''}">`;
items.forEach(ref => {
const obj = typeof ref === 'object' ? ref : $J.get(ref);
if (!obj) return;
const label = obj[labelProp] || '';
const title = tooltipProp && obj[tooltipProp] ? ` title="${obj[tooltipProp]}"` : '';
let style = '';
if (specs.useStatusColor && obj.status) {
const statusObj = _joe.Cache.get(obj.status);
if (statusObj?.color) {
style = ` style="border-left:4px solid ${statusObj.color}"`;
}
} else if (obj.color) {
style = ` style="background:${obj.color}"`;
}
html += `<joe-chip data-id="${obj._id}"${title}${style}>${label}</joe-chip>`;
});
html += '</joe-chips>';
return html;
}
};
//TODO: make current.clear a function
//TODO: check for class/id selector
this.container = $(this.specs.container);
this.fields = this.specs.fields;
this.Fields = {
reset:function(propname){
var field = self.Fields.get(propname);
self.current.object[propname] = field.reset;
self.Fields.rerender(propname);
},
onPanelShow:function(cur){
var cur = cur || _jco();
var currentFields= self.current.fields;
//get all fields
logit('current fields',currentFields);
currentFields.map(f=>{
if(f.onPanelShow){
f.onPanelShow(cur);
}
})
//run onshow functions
}
};
//configure schemas
this.schemas = this.specs.schemas;
/*
this.schemas._function = {
idprop:'name'
};*/
for(var s in _joe.schemas){
_joe.schemas[s].__schemaname = _joe.schemas[s].name = s;
_joe.schemas[s]._id = cuid();
}
this.current = {};
//filters:{},
this.current.clear= function(){
/*|{
featured:true,
description:'cleans up variables that currently exist between a single JOE showings.',
tags:'cleanup, reset',
category:'core'
}|*/
self.current.list = null;
self.current.subsets = null;
self.current.subset = null;
self.current.filters = {};
self.current.fields = [];
self.current.schema = null;
self.current.object = null;
self.current.reset = {};
self.current.cache = {};
self.current.title = null;
self.current.keyword = '';
if(_joes.length == 1){
document.title = self.initialDocumentTitle;
}
};
//profile
this.defaultProfile = this.specs.defaultProfile || this.specs.joeprofile;
this.current.profile = this.defaultProfile;
this.ace_editors = {};
this.Render.stripeColor=function(opt,colorfunc){
var color = self.propAsFuncOrValue((colorfunc||opt.stripecolor),opt,null,_jco());
var title = '';
if(color && $c.isObject(color)){
title = ' title="'+color.title+'" ';
color = color.color;
}
var h = '<joe-stripe-color '+title+(color && 'style="background-color:'+color+';"' || '')+'></joe-stripe-color>';
return h;
};
this.Render.bgColor = function(opt,colorfunc){
var color = self.propAsFuncOrValue((colorfunc||opt.bgcolor),opt,null,_jco());
if(color && $c.isObject(color)){
color = color.color;
}
var h = '<joe-bg-color '+(color && 'style="background-color:'+color+';"' || '')+'></joe-bg-color>';
return h;
};
this.Render.itemCheckbox = function(listItem,schema,specs){
/*|{
description:'renders a checkbox for a lsititem',
specs:,expander,gotoButton,itemMenu,schemaprop,nonclickable,bgcolor,stripecolor,action
tags:'render, field list item, checkbox',
}|*/
var specs = specs ||{};
var checkbox = self.propAsFuncOrValue(self.getCascadingProp('checkbox',schema),listItem);
var idprop = specs.idprop || self.getIDProp();
if(checkbox){
var cbox_prop = checkbox;
var cbox_percentage = null;
var cbox_title = '';
if($.type(checkbox) == "object"){
cbox_prop = checkbox.prop;
cbox_title = checkbox.title||cbox_prop;
cbox_percentage = self.propAsFuncOrValue(checkbox.percentage,listItem);
}
var cb_label = self.propAsFuncOrValue(checkbox.label,listItem);
var checked = [true,'true'].contains(listItem[cbox_prop])?'checked':'';
checkbox = '<joe-checkbox title="'+cbox_title+'" ' +
'class="'+checked+'"' +
'onclick="_joe.checkItem(\''+listItem[idprop]+'\',\''+cbox_prop+'\',null,this)">' +
((cbox_percentage !== false && checkbox.hasOwnProperty('percentage'))?
'<joe-checkbox-percentage>'+Math.round(cbox_percentage*100)+'%</joe-checkbox-percentage>':'')+
((cb_label && '<joe-checkbox-label>'+cb_label+'</joe-checkbox-label>')||'')+
'</joe-checkbox>';
}else{
checkbox = '';
}
return checkbox;
}
/*-------------------------------------------------------------------->
1 | INIT
<--------------------------------------------------------------------*/
this.init = function(callback) {
/*|{
featured:true,
description:'primary entry point into JOE, sets up the UI necessary',
tags:'init, framework',
category:'core'
}|*/
if(initialized){return false;}
beginLogGroup('JOE init');
self.current.clear();
var html = self.renderFramework(
self.renderEditorHeader() +
self.renderEditorContent() +
self.renderEditorFooter()
);
self.container.append(html);
self.overlay = $('.joe-overlay[data-joeindex=' + self.joe_index + ']');
self.panel = self.overlay.find('.joe-overlay-panel');
self.initKeyHandlers();
self.Speech.init();
//self.Autosave.init();
self.readHashLink();
window.addEventListener("hashchange", function(newH,oldH){
var useHash = $GET('!') || location.hash;
if (!useHash || self.joe_index != 0 || !specs.useHashlink) {
return false;
}
if(!window._joeEditingHash){
self.readHashLink();
}
}, false);
var respond_timeout;
$(window).on('resize',function(){
if(self.resizeOk()){
clearTimeout(respond_timeout);
respond_timeout = setTimeout(self.respond,200);
}
});
self.initButtons();
initialized = true;
self.respond();
endLogGroup();
self.Components.init();
callback && callback();
};
this.initButtons = function(){
// 🧩 Joe Button Universal Click Handler
$(document).on('click', 'joe-button', function(e) {
e.preventDefault();
var $btn = $(this);
var actionName = $btn.attr('action');
if (!actionName) {
console.warn('No action defined for joe-button');
return;
}
var currentObject = _joe.current ? _joe.current.object : null;
var currentSchema = _joe.current && _joe.current.schema;
var currentSchemaMethods = currentSchema ? currentSchema.methods : null;
// Priority 1: Backend async
if (JOE.async && typeof JOE.async[actionName] === 'function') {
JOE.async[actionName](currentObject, e);
return;
}
// Priority 2: Schema-defined client methods
if (currentSchemaMethods && typeof currentSchemaMethods[actionName] === 'function') {
currentSchemaMethods[actionName](currentObject, e);
return;
}
console.warn('No method found for joe-button action:', actionName);
});
}
this.resizeOk = function(){
if(!$c.isMobile()){
return true;
}
if(document.activeElement.tagName == "INPUT"){
return false;
}
return true;
}
/*-------------------------------------------------------------------->
INIT KEY HANDLERS
<--------------------------------------------------------------------*/
this.initKeyHandlers = function(){
if (self.specs.useBackButton) {
window.onkeydown = function (e) {
var code = e.keyCode
var nonBackElements = ['input','select','textarea'];
var isInputElement = nonBackElements.indexOf(e.target.tagName.toLowerCase()) != -1;
var isEditable = e.target.isContentEditable || $(e.target).closest('joe-ai-chatbox').length;
if (code == 8) {//BACKBUTTON PRESSED
if(isInputElement || isEditable){
return; // allow natural Backspace behavior
}
else{
self.goBack();
return false;
}
}else if([37,39,38,40,13,16,17,27].indexOf(code) == -1){//set focus for alphanumeric keys
if(e.altKey){//alt control
switch (code) {
case 70://QUICKFIND
self.quickFind();
if (e.stopPropagation) e.stopPropagation();
if (e.preventDefault) e.preventDefault();
break;
case 78://QUICKADD
self.quickAdd();
if (e.stopPropagation) e.stopPropagation();
if (e.preventDefault) e.preventDefault();
break;
case 80://PRINT
self.Printer.print();
if (e.stopPropagation) e.stopPropagation();
if (e.preventDefault) e.preventDefault();
break;
}
}else{
if(listMode) {
var inSearchfield = false;
if ($(document.activeElement) && $(document.activeElement)[0] != $('.joe-submenu-search-field')[0]) {
self.overlay.find('.joe-submenu-search-field').focus();
inSearchfield = true;
$('.joe-panel-content-option.keyboard-selected').removeClass('keyboard-selected');
}
}else{//NOT LIST MODE, DETAILS MODE
//is control key down
if(e.ctrlKey || e.metaKey) {
switch (code) {
case 83://look for control save
if(self.container.find('.joe-button.joe-quicksave-button').length) {
self.updateObject(null, null, true);
if (e.stopPropagation) e.stopPropagation();
if (e.preventDefault) e.preventDefault();
}
break;
}
}
}
}
}else{
//38 up, 40 dn,13 enter,37 left, 39 right
var autocompleteField = $('.joe-text-autocomplete.active').length;
if(autocompleteField){
var sel = '.joe-text-autocomplete-option.visible'+'.keyboard-selected';
//$('.joe-text-autocomplete-option.visible').length();
var keyboardSelected = $(sel)[0];
var keyboardSelectedIndex = ($(sel).length)? $(sel).index():-1;
switch(code){
case 38://up
keyboardSelectedIndex--;
if(keyboardSelectedIndex > -1) {
keyboardSelectOption('.joe-text-autocomplete-option.visible');
}
break;
case 40://down
keyboardSelectedIndex++;
if(keyboardSelectedIndex < $('.joe-text-autocomplete-option.visible').length) {
keyboardSelectOption('.joe-text-autocomplete-option.visible');
}
break;
case 13://enter
if(keyboardSelectedIndex != -1){
keyboardSelected.click();
}
break;
}
}
if(listMode){
if(e.altKey){//alt control
//get current index and add 1
if(self.current.subsets){
var subindex = self.current.subsets.indexOf(self.current.subset)+1;//$('joe-subset-option.active').index()+1;
switch(code) {
case 38://up
$('joe-subset-option').eq(subindex-1).click();
break;
case 40://down
$('joe-subset-option').eq(subindex+1).click();
break;
}
}
}else{
var keyboardSelectedIndex = ($('.joe-panel-content-option.keyboard-selected').length)?
$('.joe-panel-content-option.keyboard-selected').index():-1;
//logit(keyboardSelectedIndex);
switch(code) {
case 38://up
keyboardSelectedIndex--;
if (keyboardSelectedIndex > -1) {
keyboardSelectOption('.joe-panel-content-option', top);
}
break;
case 40://down
keyboardSelectedIndex++;
if (keyboardSelectedIndex < currentListItems.length) {
keyboardSelectOption('.joe-panel-content-option', top);
}
break;
case 13://enter
if (keyboardSelectedIndex != -1) {
$('.joe-panel-content-option.keyboard-selected').find('.joe-panel-content-option-content').click();
}
break;
}
}
}else{//DETAILS MODE
if(e.altKey) {
switch(code) {
case 219://left
case 221://right
var sside = (code ==219)?'left':'right';
if(self.current.sidebars[sside].content && !self.current.sidebars[sside].hidden){
self.toggleSidebar(sside)
}
break;
}
}else if(e.ctrlKey) {
switch(code) {
case 37://left
self.previous();
break;
case 39://right
self.next();
break;
}
}else if(code == 13){//add another row on enter click
var ae = $(document.activeElement);
if(ae && ae.is('input')){
var fieldobj = ae.parents('.joe-object-field');
if(fieldobj.length){
try{
fieldobj.find('.joe-plus-button').click();
}catch(e){
self.Error.add('adding new row to objectlist',e);
}
}
}
}
}
function keyboardSelectOption(selector,top){
$(selector+'.keyboard-selected').toggleClass('keyboard-selected');
var el = $(selector).eq(keyboardSelectedIndex);
el.addClass('keyboard-selected');
self.overlay.find('.joe-submenu-search-field').blur();
// $('.joe-panel-content').scrollTop($('.joe-panel-content-option.keyboard-selected').offset().top);
el[0].scrollIntoView(top);
//var panel_content = self.overlay.find('.joe-panel-content');
//panel_content.animate({ scrollTop: panel_content.scrollTop()-10 });
//panel_content.scrollTop(panel_content.scrollTop()-10);
}
}
}
}
};
/*-------------------------------------------------------------------->
2 | FRAMEWORK START
<--------------------------------------------------------------------*/
this.getMode = function(){
if(listMode){
if(self.current.list){
return 'list';
}
}
if(self.current.object){
return 'details';
}
if(self.current.list){
return 'list';
}
else{
return false;
}
/*
if(listMode){return 'list';}
return 'details';*/
};
this.renderFramework = function(content){
var style = 'style-variant1';
var html =
'<joe-overlay class="joe-overlay sans cols-'+colCount+' '+style+' '
+((self.specs.compact && ' compact ') || '')
+((self.specs.sans && ' sans ') || '')
+'" data-joeindex="'+this.joe_index+'">'+
'<joe-panel class="joe-overlay-panel">'+
(content || '')+
'</joe-panel>'+
//mini
'<div class="joe-mini-panel">'+
'</div>'+
'</joe-overlay>';
return html;
};
this.populateFramework = function(data,setts){
/*|{
featured:true,
description:'primary function for populating and rendering JOE, called by goJoe and joe.show',
tags:'populate, framework, core'
}|*/
self.current.cache = {};
self.overlay.removeClass('multi-edit');
var joePopulateBenchmarker = new Benchmarker();
self.current.reset = self.current.reset || {};
beginLogGroup('JOE population');
//logit('------Beginning joe population');
var specs = setts || {};
self.current.specs = setts;
self.current.data = data;
//clean copy for later;
self.current.userSpecs = $.extend({},setts);
gridMode = (self.current.specs.viewMode == 'grid')?true:false;
tableMode = (self.current.specs.viewMode == 'table')?true:false;
//update history 1/2
if(!self.current.specs.noHistory){
self.history.push({
/* _joeHistoryTitle:self.overlay.find('.joe-panel-title').html(),
*/ specs:self.current.userSpecs,
data:self.current.data
});
}
var schema = setts.schema || '';
var profile = setts.profile || null;
var callback = setts.callback || null;
var datatype = setts.datatype || '';
var title = setts.title || '';
//callback
if(callback){self.current.callback = callback;}
else{self.current.callback = null;}
/*-------------------------
String data
-------------------------*/
if($.type(data) == 'string' && datatype != "string" && self.getDataset(data,{boolean:true})){
if(!specs.schema && self.schemas[data]){
schema = data; }
data = self.getDataset(data);
}
/*setup schema*/
specs.schema = this.setSchema(schema);
/*-------------------------
Column Count
-------------------------*/
colCount = self.current.specs.colCount || (specs.schema && specs.schema.colCount) /*|| colCount*/ || 1;
if(self.sizeClass == "small-size"){
colCount = 1;
}
/*-------------------------
Preformat Functions
-------------------------*/
specs.preformat =
(specs.schema && specs.schema.preformat) ||
specs.preformat ||
function(d){return d;};
data = specs.preformat(data);
/*-------------------------
Object
-------------------------*/
//when object passed in
if($.type(data) == 'object' || datatype =='object'){
specs.object = data;
specs.menu = specs.menu || (specs.schema && specs.schema.menu) || self.specs.menu || (specs.multiedit && __defaultMultiButtons) || __defaultObjectButtons;
specs.mode="object";
self.current.object = data;
}
/*-------------------------
MultiEdit (Arrays)
-------------------------*/
self.toggleMultiEditMode(specs,data);
/*-------------------------
Lists (Arrays)
-------------------------*/
//when array passed in
listMode = false;
if($.type(data) == 'array' || datatype =='array'){
listMode = true;
specs.list = data;
specs.menu = specs.listMenu || (specs.schema && specs.schema.listMenu )|| __defaultButtons;//__defaultMultiButtons;
specs.mode="list";
//TODO: filter list items here.
self.current.list = data;
/*-------------------------
Subsets
-------------------------*/
var currentSubsets;
//setup subsets
currentSubsets = setts.subsets || (specs.schema && specs.schema.subsets)||null;
if(typeof currentSubsets == 'function'){
currentSubsets = currentSubsets();
}
//a current subset selected
if(self.current.specs.subset && currentSubsets && currentSubsets
.where({$or:[{name:specs.subset},{id:specs.subset},{group_start:specs.subset}]}).length){
self.current.subset = currentSubsets
.where({$or:[{name:specs.subset}, {id:specs.subset},{group_start:specs.subset}]})[0]||false;
}else{
//all selected
if(self.current.specs.subset == "All"){
self.current.subset = {name:"All",filter:{}}
}else {
//select default subset if it exists
self.current.subset =
(currentSubsets && currentSubsets.where({'default': true})[0]) || null;
}
}
self.current.subsets = currentSubsets;
/*-------------------------
Sorting
-------------------------*/
//setup sorting
self.current.sorter = setts.sorter || (self.current.subset && self.current.subset.sorter)||(specs.schema && specs.schema.sorter)|| 'name';
if($.type(self.current.sorter) == 'string'){self.current.sorter = [self.current.sorter];}
//self.current.object = null;
}
/*-------------------------
Submenu
-------------------------*/
if(specs.mode == 'list') {
self.current.submenu =
self.current.specs.listsubmenu ||
self.current.specs.submenu ||
(specs.schema && specs.schema.listSubMenu) ||
self.specs.listSubMenu;
}else{
self.current.submenu =
self.current.specs.submenu ||
(specs.schema && specs.schema.subMenu) ||
self.specs.subMenu;
}
if(self.current.submenu == 'none'){
self.current.submenu = null;
}
/*-------------------------
Rendering
-------------------------*/
//when rendering passed in
if($.type(data) == 'string' && datatype == 'rendering'){
specs.rendering = data;
specs.menu = [__replaceBtn__];
specs.mode="rendering";
self.current.rendering = specs.rendering;
//specs.schema
}
/*-------------------------
String
-------------------------*/
//when string passed in
else if($.type(data) == 'string' || datatype == 'string'){
specs.text = data;
specs.menu = __defaultButtons;
//specs.menu = [{name:'save',label:'Save Object',action:'_joe.updateObject()'}];
specs.mode="text";
self.current.text = specs.text;
}
//setup window title
//specs.title = title || (specs.schema)? specs.schema._title : "Viewing "+specs.mode.capitalize();
specs.listWindowTitle = (
specs.list
&& (
specs._listMenuTitle ||
//specs.listWindowTitle ||
specs._listWindowTitle ||
self.getCascadingProp('listWindowTitle')||
getProperty('specs.list.windowTitle')
|| (specs.schema &&
(specs.schema._listMenuTitle || specs.schema._listWindowTitle)
))
)||false;
specs.title =(
specs.listWindowTitle
||title
|| (specs.schema && (specs.schema.title||specs.schema._title))
|| "Viewing "+((self.current.schema && self.current.schema.__schemaname)
||(typeof self.current.userSpecs.schema == 'string' && self.current.userSpecs.schema)
|| specs.mode).capitalize());
//setup profile
specs.profile = (profile)?
(self.specs.profiles[profile]||self.specs.joeprofile):
self.specs.joeprofile;
self.current.profile = specs.profile;
//cleanup variables
self.cleanUp();
/*-------------------------------------------------------------------->
Set global view mode specs
<--------------------------------------------------------------------*/
if(self.current.schema &&(self.current.schema.table||self.current.schema.tableView)){
tableSpecs = $.extend({cols:['name',self.getIDProp()]},
(self.current.schema
&&(self.current.schema.table||self.current.schema.tableView)
// &&(self.current.schema.table||self.current.schema.tableView).cols
) ||{});
}else{
tableSpecs = null;
}
/*-------------------------------------------------------------------->
Framework Rendering
<--------------------------------------------------------------------*/
var contentBM = new Benchmarker();
beginLogGroup('Content');
var content = self.renderEditorContent(specs);
endLogGroup();
_bmResponse(contentBM,'JOE [Content]');
var chromeBM = new Benchmarker();
var html =
self.renderEditorHeader(specs)+
self.renderEditorSubmenu(specs)+
content+
self.renderEditorFooter(specs)+
self.renderMessageContainer();
_bmResponse(chromeBM,'JOE [overlay-chrome]');
self.overlay.find('.joe-overlay-panel').html(html);
//$('.joe-overlay-panel').html(html);
//update history 2/2 - add title
if(!self.current.specs.noHistory && self.history.length){
$.extend(self.history[self.history.length-1],
{_joeHistoryTitle:self.overlay.find('.joe-panel-title').html()}
);
}
//clear ace_editors
/* for (var p in _joe.ace_editors){
_joe.ace_editors[p].destroy();
}
_joe.ace_editors = {};*/
//update hashlink
self.updateHashLink();
//logit('Joe Populated in '+joePopulateBenchmarker.stop()+' seconds');
_bmResponse(joePopulateBenchmarker,'----Joe Populated');
endLogGroup();
return html;
};
/*-------------------------------------------------------------------->
2e | FRAMEWORK END
<--------------------------------------------------------------------*/
this.toggleMultiEditMode = function(specs, data){
multiEdit =(self.current.userSpecs && self.current.userSpecs.multiedit)|| false;
};
/*----------------------------->
A | Header
<-----------------------------*/
function createTitleObject(specs){
var specs = specs || {};
var titleObj = $.extend({},self.current.object);
var list = specs.list || self.current.list;
if(list){
var lcount = list.length;
if(self.current.subset){
lcount = list.where(self.current.subset.filter).length;
}
titleObj._listCount =(lcount||'0');
titleObj._subsetName = self.current.subset && self.current.subset.name+' ' ||'';
}
self.current.title = specs.title || self.getCascadingProp('title') || (self.current.schema && "new "+self.current.schema.__schemaname)||'Json Object Editor';
self.current.subtitle = specs.subtitle || self.getCascadingProp('subtitle');
var title = fillTemplate(self.propAsFuncOrValue(self.current.title),titleObj);
var subtitle = fillTemplate(self.propAsFuncOrValue(self.current.subtitle),titleObj);
titleObj.docTitle = title;
titleObj.subTitle = subtitle
return titleObj;
}
this.Header = {}
this.toggleHelpMenu = function(show,target){
}
this.listUnsavedChanges = function(){
}
this.Header.Render = this.renderEditorHeader = function(specs){
var BM = new Benchmarker();
var specs = specs || {};
var titleObj = createTitleObject(specs);
var title = titleObj.docTitle || (self.current.schema && "new "+self.current.schema.__schemaname);
var subtitle = titleObj.subTitle;
//show doctitle
if(self.specs.documentTitle){
var doctitle = (self.specs.documentTitle === true)?
self.current.title:self.propAsFuncOrValue(self.specs.documentTitle,self.current.title);
document.title = fillTemplate(self.propAsFuncOrValue(doctitle),titleObj);
}
var close_action = specs.close_action||'onclick="getJoe('+self.joe_index+').closeButtonAction()"';
var reload_action = specs.reload_action||'onclick="getJoe('+self.joe_index+').reload()"';
function renderHeaderBackButton(){
var html = '';
if(self.history.length > 1 /*&& specs.useHeaderBackBtn*/){
html+= '<div class="jif-header-back-btn jif-panel-header-button standard-button" onclick="window.history.back()" title="back">'
+self.SVG.icon.left
//+'<span class="jif-arrow-left"></span>'
+'</div>';
}
return html;
}
function renderHelpButton(){
var html = '';
if(specs.minimode){
return '';
}
html+= '<div class="jif-panel-header-button joe-panel-help" onclick="_joe.toggleHelpMenu()" title="help">'+self.SVG.icon.help+'</div>';
return html;
}
var help_button = renderHelpButton();
function renderUnsavedIcon(){
var html = '';
if(specs.minimode){
return '';
}
html+= '<div class="jif-panel-header-button joe-panel-unsaved" onclick="_joe.updateObject(this,null,true);" title="unsaved changes">'+self.SVG.icon.unsaved+'</div>';
return html;
}
var unsaved_icon = renderUnsavedIcon();
var speech_action = specs.speech_action||'onclick="getJoe('+self.joe_index+').Speech()"';
var reload_button = (specs.minimode)?'':
'<div class="jif-panel-header-button joe-panel-reload" title="reload" '+reload_action+'><span class="jif-reload"></span></div>';
var mic_button = (!self.specs.speechRecognition||specs.minimode)?'':
'<div class="jif-panel-header-button joe-panel-speech" title="speech" id="speech-button-'+self.joe_index+'">M</div>';
var close_button = '<div class="jif-panel-header-button joe-panel-close" title="close" '+close_action+'>'
+self.SVG.icon.close
//+'<span class="jif-close"></span>'+
+'</div>';
// var schema_button = (!specs.minimode && (self.current.schema && self.current.schema.menuicon &&
// '<joe-schema-icon class="clickable" title="'+self.current.schema.__schemaname+'" onclick="goJoe(_joe.getDataset(\''+self.current.schema.__schemaname+'\'),{schema:\''+self.current.schema.__schemaname+'\'})">'+self.current.schema.menuicon+'</joe-schema-icon>')||'');
var schema_button = (!specs.minimode && (self.current.schema && self.current.schema.menuicon &&
'<joe-schema-icon class="clickable" title="'+self.current.schema.__schemaname+'" onclick="goJoe(\''+self.current.schema.__schemaname+'\')">'+self.current.schema.menuicon+'</joe-schema-icon>')||'');
var back_button = (!specs.minimode && renderHeaderBackButton() || '')
var left_buttons = [
back_button,
schema_button
];
var right_buttons = [
close_button,
mic_button,
reload_button,
//help_button, TODO: add help button.
unsaved_icon
];
var html =
//'<div class="joe-panel-header">'+
'<joe-panel-header >'+
((specs.schema && specs.schema.subsets && self.renderSubsetselector(specs.schema)) || (specs.subsets && self.renderSubsetselector(specs)) || '')+
//'<joe-panel-header-buttons class="left-side">'+
left_buttons.join(' ')+
//'</joe-panel-header>'+
'<div class="joe-vcenter joe-panel-title-holder"><span class="joe-panel-title">'+
(('<div>'+title+'</div>').toDomElement().innerText || title || 'Json Object Editor')+
'</span></div>'+
//'<div class="joe-panel-reload joe-panel-header-button" title="reload" '+reload_action+'></div>'+
'<joe-panel-header-buttons class="right-side">'+
right_buttons.join(' ')+
'<div class="clear"></div>'+
'</joe-panel-header-buttons>'+
'<div class="clear"></div>'+
'</joe-panel-header>';
_bmResponse(BM,'[Header] rendered');
return html;
};
//What happens when the user clicks the close button.
this.closeButtonAction = function(prechecked){
if(!this.checkChanges()){
return;
}
self.history = [];
self.panel.addClass('centerscreen-collapse');
self.hide(500);
self.current.clear();
$(self.container).trigger({
type: "hideJoe",
index:self.joe_index/*,
schema: self.current.specs.schema,
subset: self.current.specs.subset*/
});
self.updateHashLink();
var closeAction = self.getCascadingProp('onPanelHide');
if(closeAction){ closeAction(self.getState())}
self.Autosave.deactivate();
};
var goingBackFromID;
var goingBackQuery;
this.goBack = function(obj){
if(!this.checkChanges()){
return;
}
//go back to last item and highlight
if(self.current.object) {
var gobackItem = self.current.object[self.getIDProp()];
if (gobackItem) {
goingBackFromID = gobackItem;
// logit(goingBackFromID);
}
}
//clearTimeout(self.searchTimeout );
self.history.pop();
var joespecs = self.history.pop();
if(!joespecs){
self.closeButtonAction(true);
return;
}else{
if(obj && $c.isArray(joespecs.data)){
var objid = obj[self.getIDProp()];
if(objid){
var query = {};
query[self.getIDProp()] = objid;
var found = joespecs.data.where(query);
found.length && $.extend(found[0],obj);
}
}
if(joespecs.keyword){
goingBackQuery = joespecs.keyword;
}
}
var specs = $.extend({},joespecs.specs);
specs.filters = joespecs.filters;
self.show(joespecs.data,specs);
};
/* this.clearAuxiliaryData = function(){
/!*|{
featured:true,
description:'cleans up variables that currently exist between a single JOE showings.',
tags:'cleanup, reset',
category:'core'
}|*!/
self.current.list = null;
self.current.subsets = null;
self.current.subset = null;
self.current.filters = {};
self.current.fields = [];
self.current.schema = null;
self.current.object = null;
self.current.reset = {};
};*/
//this.current.clear = this.clearAuxiliaryData;
this.cleanUp = function(){
/*|{
featured:true,
description:'cleans up variables that currently exist between a single JOE showings.',
tags:'cleanup, reset',
category:'core'
}|*/
/* if(!self._reloading){
self.current.reset = {};
}*/
self.current.fields = [];
self.shiftSelecting = false;
self.allSelected = false;
/* for (var p in _joe.ace_editors){
_joe.ace_editors[p].destroy();
}
_joe.ace_editors = {};*/
if(self.current.userSpecs && self.current.userSpecs.multiedit){
self.overlay.addClass('multi-edit');
}else{
self.overlay.removeClass('multi-edit');
}
};
/*----------------------------->
B | SubMenu
<-----------------------------*/
function renderSubmenuButtons(buttons){
var html = '';//<div class="joe-submenu-buttons">';
var buttons = self.propAsFuncOrValue(buttons
|| (listMode && self.getCascadingProp('headerListMenu'))
|| (!listMode && self.ge