<!DOCTYPE html> <html> <head> <title><%= title %></title> <link rel='stylesheet' href='/stylesheets/style.css' /> <script src="https://unpkg.com/vue"></script> </head> <body> <h1><%= title %></h1> <div id="files"></div> <script src="https://unpkg.com/axios/dist/axios.min.js"></script> <!-- Vue app element --> <div id="app" > {{ changed }} <h1><a v-bind:href="'?path=' + files.up + '&dataset_path=' + dataset_path">.. </a></h1> <template v-if="context && context.entities"> <template v-for="(item, id) in context.entities"> <template v-if="item.properties.type && !item.properties.type[0].value.includes('PropertyValue')"> <h2 v-bind:id="id"> <form v-on:submit.prevent="removeItem(id)"> <button type="submit">-</button> {{ id }} </form> <form v-if="id === context.root" v-on:submit.prevent="crate(item)"> <button type="submit" title="Make / Update a DataCrate here (generate CATALOG.json and CATALOG.html)">[crate]</button> <a v-if="item.crate_href" v-bind:href="item.crate_href">View CATALOG.html</a> </form> </h2> <img width="60%" v-bind:src='item._img'> <show-props v-bind:item="item" v-bind:schema="schema" v-bind:context="context" v-bind:type="type" v-bind:methods="methods" v-bind:changed="changed"></show-props> <form v-on:submit.prevent="addContextProp(item)"> <select v-model="prop_name" > <template v-for="(prop, prop_name) in schema.properties"> <option v-if="!item.properties[prop_name]">{{prop_name}}</option> </template> </select> <button type="submit">+</button> </form> <br><br> </template> </template> <form v-on:submit.prevent="addContext(context)"> <select v-model="type" > <option v-for="type_name in Object.getOwnPropertyNames(schema.types).filter(type => {return schema.types[type].create})" v-bind:value="type_name"> {{ type_name }} </option> </select> <button type="submit">Add contextual item</button> </form> </template> <h1> <a v-bind:href="'/?path=' + display_path + '&dataset_path=' + display_path"> <template v-if="files.existing_describo"> Edit existing data package </template> <template v-else> Package a dataset here </template> </a> </h1> <table> <tr> <tr> <th>Directories</th> <th>Files</th> </tr> <tr> <td> <div id="dirlist"> <ul v-for="dir in files.dirs"> <li><a v-bind:href="'?path=' + dir.absolute + '&dataset_path=' + dataset_path">{{ dir.name }}</a> <form v-if="context.entities" v-on:submit.prevent="addDir(dir)" style="display:inline;"> <button type="submit" title="Add directory to package">+</button> </form></li> </ul> </div> </td> <td> <div id="filelist"> <div v-for="(file, path) in files.files"> <template v-if="context && !(context.entities[file.id])"> <h4>{{ file.filename }} <form v-if="context.entities" v-on:submit.prevent="addFile(file)" style="display:inline;"> <button type="submit" title="Add file to package">+</button></h4> <img width="50%" v-bind:src='file._img'> </form> </template> <h4v v-else> {{ file.filename }} </h4> </div> </div> </td> </div> </tr> </table> </div> <!-- end Vue app element --> <script> var vue; var files = {}; var context = {}; var schema = {}; document.addEventListener("DOMContentLoaded", function(event) { const urlParams = new URLSearchParams(window.location.search); const display_path = urlParams.get('path'); const dataset_path = urlParams.get('dataset_path'); const addRootDir = function addRootDir(context) { if (!context.entities[dataset_path]) { var new_item = JSON.parse(JSON.stringify(schema.types.Dataset.template)); new_item.properties.name[0].value = "Untitled"; new_item.properties.hasPart = []; context.entities[dataset_path] = new_item; } } axios.get('/files?path=' + display_path) .then(function (response) { files = response.data; var params = dataset_path ? '?dataset_path=' + dataset_path : ""; axios.get("/schema").then(function(response){ schema = response.data; axios.get("/context_entities" + params).then(function(response){ var context = response.data; if (context.root) { if (context.root != dataset_path) { context.entities[dataset_path] = JSON.parse(JSON.stringify(context.entities[context.root])); delete context.entities[context.root]; context.root = dataset_path; } } else { context.root = dataset_path; addRootDir(context); } Vue.component('show-entity-name' , { props: ['name', 'item', 'methods', 'changed'], template: ` <span> <form v-on:submit.prevent="methods.removeProp(item, name)" style='display:inline;' v-bind:data="changed"> <button type="submit">-</button> </form> {{ name }} </span> ` }); Vue.component('paginate-values', { props: ['name', 'item', 'methods', 'changed', 'context', 'values', 'schema', 'page'], template: ` <div> <template v-if="values.length > 20 && values.length > (page) * 20" > <details> <summary> {{context.entities[values[page * 20].id].properties.name[0].value}} ... </summary> <div v-for="i_index in 20"> <show-value v-if="i_index + page * 20 < values.length" v-bind:name="name" v-bind:item="item" v-bind:methods="methods" v-bind:changed="changed" v-bind:context="context" v-bind:values="values" v-bind:schema="schema" v-bind:val="values[i_index + page * 20]" v-bind:i_index="i_index" > </show-value> </div> </details> <paginate-values v-bind:name="name" v-bind:item="item" v-bind:methods="methods" v-bind:changed="changed" v-bind:context="context" v-bind:values="values" v-bind:schema="schema" v-bind:page="page + 1"> </paginate-values> </template> <template v-else-if="page === 0"> <div v-for="(val, i_index) in values"> <show-value v-bind:name="name" v-bind:item="item" v-bind:methods="methods" v-bind:changed="changed" v-bind:context="context" v-bind:values="values" v-bind:schema="schema" v-bind:val="val" v-bind:i_index="i_index"> </show-value> </div> </template> </div> ` }); Vue.component('show-value', { props: ['name', 'item', 'methods', 'changed', 'context', 'values', 'schema', 'i_index','val'], template: ` <div> <form v-on:submit.prevent="methods.removeValue(values, i_index)" style='display:inline;'> <button type="submit" title="Delete this property">-</button> </form> <!-- Input form --> <template v-if="schema.properties[name] && schema.properties[name].input === 'text'"> <input v-model="val.value" type="text" size="45" v-on:keyup="methods.trigger_change_on_enter"/> </template> <!-- UNLINK button for linked props --> <template v-else-if="val && val.id && context.entities[val.id] && context.entities[val.id].properties.name"> <a v-bind:href="'#' + val.id">{{ context.entities[val.id].properties.name[0].value }}</b></a> <form v-on:submit.prevent="methods.unlinkProp(val)" style='display:inline;'> <button type="submit">unlink</button> </form> </template> <!-- FALLBACK - DISPLAY --> <b v-else> <input v-model="val.value" type="text" size="45" v-on:keyup="methods.trigger_change_on_enter"/> </b> <template v-if="schema.properties[name] && schema.properties[name].input === 'link' " > <form v-on:submit.prevent="methods.linkProp(val)" style='display:inline;' v-if="!val.id"> <button type="submit"> -> </button> <select v-model="val.selection"> <template v-for="(link_item, link_id) in context.entities"> {{link_id}} <template v-for="other_name in link_item.properties.name"> <option v-if="(!val.id || link_id != val.id) && schema.properties[name] && link_item.properties.type && schema.properties[name].type.includes(link_item.properties.type[0].value)" v-bind:value="link_id">{{ other_name.value }}</option> </template> </template> </select> </form> <form v-on:submit.prevent="methods.linkToNew(val)" style='display:inline;' v-if="!val.id && schema.properties[name] && schema.properties[name].type && schema.properties[name].type.filter(t => {return (schema.types[t] && schema.types[t].create)}).length > 0"> ... or ... <button type="submit" text="Link to a new contextual item"> -> New -> </button> <select v-model="val.new_type" v-for="type in schema.properties[name].type.filter(type => {return (schema.types[type] && schema.types[type].create)})"> <option> {{ type }} </option> </select> </form> </template> </div> ` }); Vue.component('show-props', { props: ['item', 'schema', 'context', 'type', 'methods', 'changed'], template: ` <table width="100%"> <tr v-for="(values, name) in item.properties" v-bind:data="changed"> <td> <show-entity-name v-bind:name="name" v-bind:item="item" v-bind:methods="methods" v-bind:changed="changed"></show-entity-name> </td> <td> <form v-on:submit.prevent="methods.addProp(item, name)" style='display:inline;'> <button type="submit">+</button> </form> </td> <td> <!-- Put in summary here / Paginate--> <paginate-values v-bind:name="name" v-bind:item="item" v-bind:methods="methods" v-bind:changed="changed" v-bind:context="context" v-bind:values="values" v-bind:schema="schema" v-bind:page="0"> </paginate-values> </td> </tr> </table> ` }); const methods = { "save_context": function save_context() { var params = '?dataset_path=' + dataset_path; axios.post('/context_entities' + params, context).then( function () { } ) }, "crate": function crate(item) { var params = '?dataset_path=' + dataset_path; var href = "/preview?path=" + dataset_path + "/CATALOG.html" var save = this.save_context; axios.get('/crate' + params).then( function () { item.crate_href = href; save(); } ) }, "addContextProp": function addContextProp(item){ // Warning! Repetition! var prop_name = this.prop_name; if (item.properties[prop_name]) { item.properties[prop_name].push({"value": "", "id": ""}); } else { item.properties[prop_name] = [{"value": "", "id": ""}]; } this.changed += 1; this.save_context(); }, "addProp": function addProp(item, prop_name){ if (item.properties[prop_name]) { item.properties[prop_name].push({"value": "", "id": ""}); } else { item.properties[prop_name] = [{"value": "", "id": ""}]; } data.changed += 1; methods.save_context(); }, "removeValue": function removeValue(values,i) { values.splice(i,1) data.changed += 1; methods.save_context(); }, "removeProp": function removeProp(item, prop_name){ delete item.properties[prop_name]; data.changed += 1; methods.save_context(); }, "trigger_change_on_enter": function(e) { if (e.keyCode === 13) { data.changed += 1; methods.save_context(); } }, "linkProp": function linkProp(val) { val.value = context.entities[val.selection].properties.name[0].value; val.id = val.selection; this.changed += 1; this.save_context(); }, "unlinkProp": function unlinkProp(val) { val.value = ""; val.id = ""; data.changed += 1; methods.save_context(); }, "directory_path" : function directory(file) { var container_dir_array = file.id.split("/"); container_dir_array.pop(); var container_dir = container_dir_array.join("/"); var dir_name = container_dir_array.pop(); return({"dir_name": dir_name, dir_path: container_dir }) }, "addParentDataset": function addParentDataset(file) { var dir_details = this.directory_path(file); var diff = dir_details.dir_path.replace(context.root, ""); // Don't make dirs outside of the package if (diff != dir_details.dir_path && !context.entities[dir_details.dir_path]) { var dir = {"id": dir_details.dir_path, "name": dir_details.dir_name}; this.addDir(dir); context.entities[dir_details.dir_path].properties.hasPart = []; } context.entities[dir_details.dir_path].properties.hasPart.push({"id": file.id}); this.changed += 1; this.save_context(); }, "addFile": function addFile(file) { if (!context.entities[file.id]) { var new_item = JSON.parse(JSON.stringify(schema.types.File.template)); new_item.properties.name[0].value = file.name; new_item._img = file._img; context.entities[file.id] = new_item; this.addParentDataset(file); } }, "addRootDir": addRootDir, "addDir": function addDir(file) { if (!context.entities[file.id]) { var new_item = JSON.parse(JSON.stringify(schema.types.Dataset.template)); new_item.properties.name[0].value = file.name; new_item.properties.hasPart = []; context.entities[file.id] = new_item; this.addParentDataset(file); this.changed += 1; this.save_context(); } else { alert("Already got that directory"); //Should never fire but you never know } }, "removeItem": function remove_item(id) { delete context.entities[id]; this.changed += 1; this.save_context(); }, "linkToNew" : function linkToNew(val) { this.type = val.new_type; val.id = this.addContext(context); this.save_context(); }, "addContext": function addContext(context){ while (context.entities[data.latest_id.toString()]) { data.latest_id += 1; } var id = data.latest_id.toString(); context.entities[id] = JSON.parse(JSON.stringify(schema.types[this.type].template)); context.entities[id].properties.name=[{"value": this.type + "(" + id + ")"}] data.changed += 1; this.save_context(); return(id); } }; const data = { files: files, context: context, schema: schema, prop: {"name":"nom", "value": "val"}, type: "Person", prop_name: "", link_to_id: {}, link_id: "", changed: 0, latest_id: 0, display_path: display_path, dataset_path: dataset_path, methods: methods }; vue = new Vue({ el: "#app", data: data, methods: methods }); //document.getElementById("files").innerHTML = response['data'].model; }) .catch(function (error) { // handle error console.log(error); }) .then(function () { console.log("done") // always executed }); })})}); </script> </body> </html>