diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 00000000..91e5c898 --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,24 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 00000000..79ee123c --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 00000000..c6cc8c81 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/changelog.md b/changelog.md index 6af61b5d..842ff533 100644 --- a/changelog.md +++ b/changelog.md @@ -6,6 +6,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] +## [v3.2.0] - 2018-02-27 + +### Added +- Added tree view to calculator selection overlay with calculators sorted by category, closes #162. + +### Fixed +- Fixed TravisCI build error, where error was 'npm ERR! enoent ENOENT: no such file or directory, chmod '/home/travis/build/mbedded-ninja/NinjaCalc/node_modules/topojson/node_modules/topojson-server/bin/geo2topo''. This was fixed by removing topojson as a dependency and just using topojson-client, topojson-server and topojson-simplify individually (they are still dependencies). + ## [v3.1.0] - 2018-02-18 ### Added diff --git a/package-lock.json b/package-lock.json index 83cef770..e6133394 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6943,6 +6943,9 @@ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, + "phantomjs-polyfill-find": { + "version": "github:ptim/phantomjs-polyfill-find#026b69dcabe743265f5214775e42f8d1e8aabedc" + }, "phantomjs-prebuilt": { "version": "2.1.16", "resolved": "https://registry.npmjs.org/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.16.tgz", @@ -8860,43 +8863,6 @@ "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=" }, - "topojson": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/topojson/-/topojson-3.0.2.tgz", - "integrity": "sha512-u3zeuL6WEVL0dmsRn7uHZKc4Ao4gpW3sORUv+N3ezLTvY3JdCuyg0hvpWiIfFw8p/JwVN++SvAsFgcFEeR15rQ==", - "requires": { - "topojson-client": "3.0.0", - "topojson-server": "3.0.0", - "topojson-simplify": "3.0.2" - }, - "dependencies": { - "topojson-client": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/topojson-client/-/topojson-client-3.0.0.tgz", - "integrity": "sha1-H5kpOnfvQqRI0DKoGqmCtz82DS8=", - "requires": { - "commander": "2.14.1" - } - }, - "topojson-server": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/topojson-server/-/topojson-server-3.0.0.tgz", - "integrity": "sha1-N4546Hw5cqe1vixdYENptrrmnF4=", - "requires": { - "commander": "2.14.1" - } - }, - "topojson-simplify": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/topojson-simplify/-/topojson-simplify-3.0.2.tgz", - "integrity": "sha512-gyYSVRt4jO/0RJXKZQPzTDQRWV+D/nOfiljNUv0HBXslFLtq3yxRHrl7jbrjdbda5Ytdr7M8BZUI4OxU7tnbRQ==", - "requires": { - "commander": "2.14.1", - "topojson-client": "3.0.0" - } - } - } - }, "topojson-client": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/topojson-client/-/topojson-client-3.0.0.tgz", diff --git a/package.json b/package.json index af230816..419f7ba5 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,6 @@ "semver": "^5.3.0", "sinon": "^1.17.7", "sinon-chai": "^2.8.0", - "topojson": "^3.0.2", "topojson-client": "^3.0.0", "topojson-server": "^3.0.0", "topojson-simplify": "^3.0.2", diff --git a/src/components/CalculatorSelectionOverlay/CalculatorSelectionOverlay.vue b/src/components/CalculatorSelectionOverlay/CalculatorSelectionOverlay.vue index ed020bd9..5df390ed 100644 --- a/src/components/CalculatorSelectionOverlay/CalculatorSelectionOverlay.vue +++ b/src/components/CalculatorSelectionOverlay/CalculatorSelectionOverlay.vue @@ -5,15 +5,28 @@ - @@ -39,19 +53,73 @@ CalcPreview }, data: function () { - return {} + return { + } }, computed: { searchText: { get () { - return this.$store.state.searchText + return this.$store.state.core.searchText }, set (value) { this.$store.dispatch('setSearchText', value) } + }, + treeData () { + var output = { + 'name': 'root', + 'selected': false, + 'children': [] + } + + console.log(this.$store) + var self = this + this.$store.state.core.availableCalcs.map(function (calc) { + // console.log('calc =') + // console.log(calc) + self.addCategoriesToTree(calc.category, output) + // console.log('After adding category elements for 1 calculator, output =') + // console.log(output) + }) + return output } }, methods: { + addCategoriesToTree (categories, treeNode) { + // console.log('addCategoriesToTree() called with categories =') + console.log(categories) + + // Copy array, we are going to modify it, and we don't want to touch + // the original! + categories = categories.slice() + // console.log(', treeNode =') + // console.log(treeNode) + + var inTree = false + treeNode.children.map(function (childNode) { + if (childNode.name === categories[0]) { + inTree = true + } + }) + + // Add first category element if it doesn't already exist + if (!inTree) { + console.log('Category ' + categories[0] + ' not found in tree.') + var newTreeNode = { + 'name': categories[0], + 'selected': false, + 'children': [] + } + treeNode.children.push(newTreeNode) + } + + // Remove first category element + categories.splice(0, 1) + + if (categories.length > 0) { + this.addCategoriesToTree(categories, treeNode.children[treeNode.children.length - 1]) + } + }, borderClicked (event) { this.$store.commit('showCalculatorSelectionOverlay', { trueFalse: false @@ -60,10 +128,21 @@ overlayClicked (event) { // Do nothing, this handler exists purely to swallow event // (event does not bubble because of .stop modifier in HTML) + }, + itemClick (node) { + console.log(node.model.text + ' clicked !') + }, + categoryClicked (category) { + console.log('categoryClicked() called. category =') + console.log(category) + this.$store.dispatch('setSelCategory', category) } }, watch: {}, mounted () { + if (!this.$store.state.core.calcsFilteredByCategoryAndSearch) { + throw Error('this.$store.state.core.calcsFilteredByCategoryAndSearch was null.') + } } } diff --git a/src/components/Calculators/Geospatial/TwoCoordinateGeodesics/MainView.vue b/src/components/Calculators/Geospatial/TwoCoordinateGeodesics/MainView.vue index a9321bc4..34a93668 100644 --- a/src/components/Calculators/Geospatial/TwoCoordinateGeodesics/MainView.vue +++ b/src/components/Calculators/Geospatial/TwoCoordinateGeodesics/MainView.vue @@ -81,7 +81,7 @@ /* eslint-disable */ import * as d3 from 'd3' - import * as topojson from 'topojson' + import feature from 'topojson-client/src/feature' import versor from 'versor'; import { Coordinate, CoordinateUnits, Geospatial } from 'src/misc/Geospatial/Geospatial' @@ -374,8 +374,9 @@ this.graticule = d3.geoGraticule10() this.path = d3.geoPath(this.projection).context(this.context) - this.land = topojson.feature(world110m, world110m.objects.land) - this.countries = topojson.feature(world110m, world110m.objects.countries) + // feature() is from the topojson-client library (DO NOT ADD topojson AS A DEPENDENCY) + this.land = feature(world110m, world110m.objects.land) + this.countries = feature(world110m, world110m.objects.countries) // this.countryList = cList this.scale() diff --git a/src/main.js b/src/main.js index 2fd025a7..24538f7d 100644 --- a/src/main.js +++ b/src/main.js @@ -30,6 +30,9 @@ import ElementUI from 'element-ui' import 'element-ui/lib/theme-default/index.css' Vue.use(ElementUI) +// import VJstree from 'vue-jstree' +// Vue.component('v-jstree', VJstree) + import './style/style.css' // =========================================== // @@ -48,6 +51,15 @@ Vue.component('calc-var-checkbox', CalcVarCheckbox) import VariableRowVerbose from 'src/misc/CalculatorEngineV2/view/VariableRowVerbose.vue' Vue.component('variable-row-verbose', VariableRowVerbose) +// =========================================== // +// ===== TREE VIEW COMPONENT REGISTRATION ==== // +// =========================================== // +import TreeView from 'misc/TreeView/TreeView' +Vue.component('tree-view', TreeView) + +import TreeItem from 'misc/TreeView/TreeItem' +Vue.component('tree-item', TreeItem) + // =========================================== // // ============= IMPORT VUEX STORE =========== // // =========================================== // diff --git a/src/misc/TreeView/TreeItem.vue b/src/misc/TreeView/TreeItem.vue new file mode 100644 index 00000000..b3e65702 --- /dev/null +++ b/src/misc/TreeView/TreeItem.vue @@ -0,0 +1,76 @@ + + + + + + + diff --git a/src/misc/TreeView/TreeView.vue b/src/misc/TreeView/TreeView.vue new file mode 100644 index 00000000..e7273984 --- /dev/null +++ b/src/misc/TreeView/TreeView.vue @@ -0,0 +1,68 @@ + + + + + + + diff --git a/src/store/index.js b/src/store/index.js index 1332d14a..cd64c1bb 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -9,8 +9,7 @@ export default new Vuex.Store({ count: 0, showLeftSideBar: false, showCalculatorSelectionOverlay: false, - activeTabId: '', - searchText: '' + activeTabId: '' }, mutations: { showLeftSideBar (state, payload) { @@ -57,18 +56,7 @@ export default new Vuex.Store({ state.activeTabId = state.core.openCalcs[state.core.openCalcs.length - 1].uniqueId } }, - actions: { - /** - * This will set the search text, and also update the filteredAvailableCalcs variable, - * depending on the search text. - * @param context - * @param value - */ - setSearchText (context, value) { - context.commit('setSearchText', value) - context.commit('updateFilteredAvailableCalcs', context.state.searchText) - } - }, + actions: {}, modules: { core } diff --git a/src/store/modules/core.js b/src/store/modules/core.js index b9a6ee19..3cf45b17 100644 --- a/src/store/modules/core.js +++ b/src/store/modules/core.js @@ -5,8 +5,15 @@ const state = { // These are presented to the user, but filtered first. availableCalcs: [], - // This is updated whenever the search text is changed. - filteredAvailableCalcs: [], + selCategory: [], + + // This is updated whenever the selected category is changed. + calcsFilteredByCategory: [], + + searchText: '', + + // This is updated whenever the category or search text is changed. + calcsFilteredByCategoryAndSearch: [], openCalcs: [] } @@ -16,16 +23,22 @@ const mutations = { registerCalc (state, payload) { state.availableCalcs.push(payload) }, - updateFilteredAvailableCalcs (state, searchText) { + setSearchText (state, searchText) { + state.searchText = searchText + }, + updateFilteredCalcsOnSearchText (state) { + // console.log('updateFilteredAvailableCalcs() called.') // Update the filtered available calculators. If the search text is '' (i.e. // empty), return all the calculators. - if (searchText === '') { - state.filteredAvailableCalcs = state.availableCalcs + if (state.searchText === '') { + state.calcsFilteredByCategoryAndSearch = state.calcsFilteredByCategory + // console.log('state.calcsFilteredByCategoryAndSearch = ') + // console.log(state.calcsFilteredByCategoryAndSearch) return } - state.filteredAvailableCalcs = state.availableCalcs.filter(calc => { + state.calcsFilteredByCategoryAndSearch = state.calcsFilteredByCategory.filter(calc => { // Create regex pattern from search text - var regex = new RegExp(searchText, 'gi') + var regex = new RegExp(state.searchText, 'gi') // Search in calculator title (display name) if (calc.displayName.match(regex)) return true // Search through the tags @@ -34,6 +47,9 @@ const mutations = { } }) }, + setSelCategory (state, category) { + state.selCategory = category + }, openCalc (state, payload) { // Find a unique ID to use var maxId = 0 @@ -58,6 +74,30 @@ const mutations = { // Unique ID is used as a unique tab ID uniqueId: newUniqueId }) + }, + updateFilteredCalcsOnCategory (state) { + // console.log('$state.core.mutations.updateFilteredCalcsOnCategory() called.') + + state.calcsFilteredByCategory = state.availableCalcs.filter(calc => { + // console.log('calc =') + // console.log(calc) + if (state.selCategory.length > calc.category.length) { + // console.log('Selected category more specific than calc category, excluding...') + return false + } + for (var i = 0; i < state.selCategory.length; i++) { + if (state.selCategory[i] !== calc.category[i]) { + // console.log('Selected category does not mactch calc category, excluding...') + return false + } + } + + // console.log('Selected category matches calculator category.') + return true + }) + + // console.log('calcsFilteredByCategory =') + // console.log(state.calcsFilteredByCategory) } } @@ -71,12 +111,23 @@ const actions = { registerCalc ({state, commit, rootState}, value) { Vue.component(value.mainView.name, value.mainView) commit('registerCalc', value) - commit('updateFilteredAvailableCalcs', rootState.searchText) + commit('updateFilteredCalcsOnCategory') + commit('updateFilteredCalcsOnSearchText') }, openCalc ({state, commit, rootState}, value) { console.log('core.actions.openCalc() called.') commit('openCalc', value) commit('setLastCalcAsActive') + }, + setSearchText ({state, commit, rootState}, value) { + commit('setSearchText', value) + commit('updateFilteredCalcsOnSearchText') + }, + setSelCategory ({state, commit, rootState}, value) { + console.log('core.actions.setCategory() called.') + commit('setSelCategory', value) + commit('updateFilteredCalcsOnCategory') + commit('updateFilteredCalcsOnSearchText') } }