From 411613088af1884f769a64e25ec33d40dd3981b2 Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Sat, 6 Jan 2018 14:56:19 +0000 Subject: [PATCH] Add JSON tree view in addition to source preview --- app/components/file-preview/component.js | 67 +++++++- app/components/file-preview/template.hbs | 10 +- app/controllers/inspect.js | 2 +- app/styles/app.scss | 2 + app/styles/vendor/_json-tree-view.scss | 149 ++++++++++++++++++ app/templates/inspect.hbs | 7 +- package-lock.json | 4 +- package.json | 2 +- .../components/file-preview/component-test.js | 39 ++--- 9 files changed, 244 insertions(+), 38 deletions(-) create mode 100644 app/styles/vendor/_json-tree-view.scss diff --git a/app/components/file-preview/component.js b/app/components/file-preview/component.js index 8ce3c68..d94a7bd 100644 --- a/app/components/file-preview/component.js +++ b/app/components/file-preview/component.js @@ -1,6 +1,9 @@ import Component from '@ember/component'; import { inject as service } from '@ember/service'; +import { observer } from '@ember/object'; import { alias } from '@ember/object/computed'; +import { scheduleOnce } from '@ember/runloop'; +import JSONTreeView from 'npm:json-tree-view'; export default Component.extend({ @@ -12,13 +15,12 @@ export default Component.extend({ fileContent: null, objectURL: null, metaData: null, - jsonView: null, + isJSON: null, type: alias('metaData.type'), isBinary: alias('metaData.isBinary'), isImage: function() { - return this.get('type').match(/^image\/.+$/); - }.property('type'), + return this.get('type').match(/^image\/.+$/); }.property('type'), isText: function() { return !this.get('isBinary'); @@ -37,8 +39,65 @@ export default Component.extend({ } else { this.set('fileContent', file.data); } + this.set('fileLoaded', true); }); - }.on('init') + }.on('didInsertElement'), + + onFileLoaded: observer('fileLoaded', function(){ + if (this.get('fileLoaded') && this.get('isJSON') && this.get('jsonShowTree')) { + scheduleOnce('afterRender', this, 'renderJsonTree'); + } + }), + + onJsonViewChanged: observer('jsonShowTree', function(){ + if (this.get('fileLoaded') && this.get('isJSON') && this.get('jsonShowTree')) { + scheduleOnce('afterRender', this, 'renderJsonTree'); + } + }), + + renderJsonTree () { + let value = JSON.parse(this.get('fileContent')); + + let view = new JSONTreeView('content', value); + + // Listen for change events + view.on('change', function(self, key, oldValue, newValue){ + console.log('change', key, oldValue, '=>', newValue); + }); + view.on('rename', function(self, key, oldName, newName) { + console.log('rename', key, oldName, '=>', newName); + }); + view.on('delete', function(self, key) { + console.log('delete', key); + }); + view.on('append', function(self, key, nameOrValue, newValue) { + console.log('append', key, nameOrValue, '=>', newValue); + }); + view.on('click', function(self, key, value) { + console.log('click', key, '=', value); + }); + view.on('expand', function(self, key, value) { + console.log('expand', key, '=', value); + }); + view.on('collapse', function(self, key, value) { + console.log('collapse', key, '=', value); + }); + view.on('refresh', function(self, key, value) { + console.log('refresh', key, '=', value); + }); + + document.getElementById('json-tree-view') + .appendChild(view.dom); + + window.jsonview = view; + + view.expand(true); + + view.withRootName = false; + view.readonly = true; + + this.set('jsonTreeView', view); + } }); diff --git a/app/components/file-preview/template.hbs b/app/components/file-preview/template.hbs index 29dba52..1bd9acd 100644 --- a/app/components/file-preview/template.hbs +++ b/app/components/file-preview/template.hbs @@ -8,6 +8,14 @@ {{/if}} {{#if isText}} - {{fileContent}} + {{#if isJSON}} + {{#if jsonShowTree}} +
+ {{else}} + {{fileContent}} + {{/if}} + {{else}} + {{fileContent}} + {{/if}} {{/if}} {{/if}} \ No newline at end of file diff --git a/app/controllers/inspect.js b/app/controllers/inspect.js index b7c11e9..3e9681e 100644 --- a/app/controllers/inspect.js +++ b/app/controllers/inspect.js @@ -20,7 +20,7 @@ export default Controller.extend({ return !!this.get('model.documentMetaData.type').match(/application\/json/i); }), - jsonView: 'source', + jsonView: 'tree', jsonShowTree: computed.equal('jsonView', 'tree'), jsonShowSource: computed.equal('jsonView', 'source'), diff --git a/app/styles/app.scss b/app/styles/app.scss index 44e7a98..32460cc 100644 --- a/app/styles/app.scss +++ b/app/styles/app.scss @@ -24,3 +24,5 @@ body { @import "components/directory-listing"; @import "components/file-preview"; @import "components/item-icon"; + +@import "vendor/json-tree-view"; diff --git a/app/styles/vendor/_json-tree-view.scss b/app/styles/vendor/_json-tree-view.scss new file mode 100644 index 0000000..d72fb77 --- /dev/null +++ b/app/styles/vendor/_json-tree-view.scss @@ -0,0 +1,149 @@ +.jsonView{ + margin-left: 20px; + font-family: Consolas, "Lucida Console", Menlo, "dejavu sans mono", monospace; + font-size: 16px; + line-height: 16px; + padding: 2px; + cursor: default; + color: rgb(66, 66, 66); + white-space: nowrap; + -webkit-user-select: none; +} + +.jsonView>div{ + display: inline-block; +} + +.jsonView.hidden{ + display: none; +} + +.jsonView>.children, .jsonView.insert{ + display: block; +} + +.jsonView>.name{ + color: rgb(136, 19, 145); +} + +.jsonView>.separator:before{ + content: ":"; +} + +.jsonView>.separator{ + padding-right: 5px; +} + +.jsonView>.spacing{ + display:inline-block; + width:15px; +} +.jsonView>.spacing::before{ + content: '1'; + visibility:hidden; +} + +.jsonView>.value.null, .jsonView>.value.undefined{ + color: rgb(128, 128, 128); +} + +.jsonView>.value.boolean, .jsonView>.value.number{ + color: rgb(28, 0, 207); +} + +.jsonView>.value.string:not(.edit):before, .jsonView>.value.string:not(.edit):after{ + content: "\""; +} + +.jsonView>.value.string { + color: rgb(196, 26, 22); +} + +.jsonView>.name:hover, .jsonView>.value:hover{ + background-color: rgba(56, 121, 217, 0.1); +} + +.jsonView>.expand, .jsonView>.collapse{ + min-width: 20px; + margin-left: -20px; + cursor: pointer; +} + +.jsonView>.expand:before{ + content: '\25B6'; +} + +.jsonView>.collapse:before{ + content: '\25BC'; +} + +.jsonView>.edit{ + padding: 0px 5px 0px 5px; + white-space: nowrap; + overflow: hidden; + background-color: transparent; +} + +.jsonView>.edit br{ + display: none; +} + +.jsonView>.edit *{ + display: inline; + white-space: nowrap; +} + +.jsonView>.value.edit{ + color: rgb(0, 0, 0); +} + +.jsonView>.delete:before{ + content: '+'; + transform: rotate(45deg); + -webkit-transform: rotate(45deg); + -o-transform: rotate(45deg); + -ms-transform: rotate(45deg); + display: inline-block; +} + +.jsonView>.delete{ + opacity: 0; + display: inline; + padding: 3px; + cursor: pointer; + color: rgb(150, 150, 150); +} + +.jsonView>.item:hover~.delete{ + opacity: 1; + color: rgb(150, 150, 150); +} +.jsonView>.delete:hover{ + opacity: 1; + color: rgb(0, 0, 0); + background: rgb(220, 220, 220); +} + +.jsonView.readonly>.insert,.jsonView.readonly>.delete{ + display: none !important; +} +.jsonView>.insert:before{ + content: '+'; +} + +.jsonView>.insert{ + display: none; + color: rgb(150, 150, 150); + cursor: pointer; +} + +.jsonView.expanded>.insert, .jsonView.expanded>.insert{ + display: inline-block; + margin-left: 20px; + padding: 3px; +} + +.jsonView>.insert:hover{ + color: rgb(0, 0, 0); + background: rgb(220, 220, 220); +} \ No newline at end of file diff --git a/app/templates/inspect.hbs b/app/templates/inspect.hbs index 3965205..b6bd452 100644 --- a/app/templates/inspect.hbs +++ b/app/templates/inspect.hbs @@ -14,10 +14,9 @@
{{file-preview metaData=model.documentMetaData - documentIsJSON=documentIsJSON - jsonView=jsonView - showJsonTree=showJsonTree - showJsonSource=showJsonSource}} + isJSON=documentIsJSON + jsonShowTree=jsonShowTree + jsonShowSource=jsonShowSource}}
diff --git a/package-lock.json b/package-lock.json index 60614e9..2da8be4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8012,9 +8012,7 @@ "dev": true }, "json-tree-view": { - "version": "0.4.9", - "resolved": "https://registry.npmjs.org/json-tree-view/-/json-tree-view-0.4.9.tgz", - "integrity": "sha1-JzZZxFlkd/LrG0i/AuISsM5Yx1w=", + "version": "github:skddc/json-tree-view#55cb3b866083bf99e1895481fb73cf9186154c5e", "dev": true }, "json3": { diff --git a/package.json b/package.json index 0479ffd..a66e52b 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "ember-load-initializers": "^1.0.0", "ember-resolver": "^4.0.0", "ember-source": "~2.16.0", - "json-tree-view": "^0.4.9", + "json-tree-view": "github:skddc/json-tree-view#bugfix/setters", "loader.js": "^4.2.3", "remotestorage-widget": "^1.2.0", "remotestoragejs": "^1.0.0" diff --git a/tests/integration/components/file-preview/component-test.js b/tests/integration/components/file-preview/component-test.js index c708a83..ed9001d 100644 --- a/tests/integration/components/file-preview/component-test.js +++ b/tests/integration/components/file-preview/component-test.js @@ -1,24 +1,15 @@ -// import { moduleForComponent, test } from 'ember-qunit'; -// import hbs from 'htmlbars-inline-precompile'; -// -// moduleForComponent('file-preview', 'Integration | Component | file preview', { -// integration: true -// }); -// -// test('it renders', function(assert) { -// // Set any properties with this.set('myProperty', 'value'); -// // Handle any actions with this.on('myAction', function(val) { ... }); -// -// this.render(hbs`{{file-preview}}`); -// -// assert.equal(this.$().text().trim(), ''); -// -// // Template block usage: -// this.render(hbs` -// {{#file-preview}} -// template block text -// {{/file-preview}} -// `); -// -// assert.equal(this.$().text().trim(), 'template block text'); -// }); +import { moduleForComponent, test } from 'ember-qunit'; +import hbs from 'htmlbars-inline-precompile'; + +moduleForComponent('file-preview', 'Integration | Component | file preview', { + integration: true +}); + +test('it renders', function(assert) { + // Set any properties with this.set('myProperty', 'value'); + // Handle any actions with this.on('myAction', function(val) { ... }); + + this.render(hbs`{{file-preview}}`); + + assert.equal(this.$().text().trim(), ''); +});