diff --git a/.babelrc b/.babelrc index d0a1609..0339d5d 100644 --- a/.babelrc +++ b/.babelrc @@ -1,6 +1,3 @@ { - "presets": ["env"], - "plugins": [ - "transform-async-to-generator" - ] + "presets": ["env"] } diff --git a/.eslintignore b/.eslintignore index ca1283f..f7b7e43 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,2 +1,5 @@ src/router/navigo.js +node_modules +website/node_modules +website/static build diff --git a/.eslintrc b/.eslintrc index d0bf294..9250ea2 100644 --- a/.eslintrc +++ b/.eslintrc @@ -26,4 +26,4 @@ globals: describe: true expect: true beforeEach: true - it: true + test: true diff --git a/.gitignore b/.gitignore index d72dfc6..d66b450 100644 --- a/.gitignore +++ b/.gitignore @@ -3,10 +3,15 @@ node_modules /build /dist /site +/website/static # files +*.log +nav.json .DS_Store -router/navigo.js +src/router/navigo.js +src/icons/icons.json # IDEs +.idea *.sublime-workspace diff --git a/.npmignore b/.npmignore index 28801ee..e2720b6 100644 --- a/.npmignore +++ b/.npmignore @@ -3,6 +3,7 @@ .ci *.log *.lock +nav.json rollup.config.js .eslintrc .gitignore diff --git a/LICENSE b/LICENSE index 5277ff5..be74e74 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ BSD 3-Clause License -Copyright (c) 2017, Quantmind +Copyright (c) 2017-2018, Quantmind All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/d3-view-components.sublime-project b/d3-view-components.sublime-project deleted file mode 100644 index e027561..0000000 --- a/d3-view-components.sublime-project +++ /dev/null @@ -1,46 +0,0 @@ -{ - "build_systems": - [ - { - "file_regex": "^[ ]*File \"(...*?)\", line ([0-9]*)", - "name": "Anaconda Python Builder", - "selector": "source.python", - "shell_cmd": "\"fluidily.cloud/venv/source/bin/python\" -u \"$file\"" - } - ], - "folders": - [ - { - "path": "." - }, - { - "path": "/Users/lsbardel/workspace/d3-view" - }, - { - "path": "/Users/lsbardel/workspace/d3-visualize" - }, - { - "path": "/Users/lsbardel/workspace/dev-tools" - }, - { - "path": "/Users/lsbardel/workspace/d3-let" - } - ], - "settings": - { - "anaconda_linter_phantoms": false, - "anaconda_linting": true, - "anaconda_linting_behaviour": "always", - "index_exclude_patterns": - [ - "node_modules/*", - "venv/*", - "../d3-view/node_modules/*", - "../d3-visualize/node_modules/*", - "../d3-fluid/node_modules/*" - ], - "python_interpreter": "./venv/bin/python", - "test_command": "python setup.py test", - "validate_imports": true - } -} diff --git a/dev/jest-empty.js b/dev/jest-empty.js new file mode 100644 index 0000000..9dc5fc1 --- /dev/null +++ b/dev/jest-empty.js @@ -0,0 +1 @@ +module.exports = ''; diff --git a/dev/jest.config.json b/dev/jest.config.json new file mode 100644 index 0000000..f849fa6 --- /dev/null +++ b/dev/jest.config.json @@ -0,0 +1,39 @@ +{ + "rootDir": "../", + "roots": [ + "" + ], + "collectCoverage": true, + "coverageDirectory": "/build/coverage", + "coverageReporters": [ + "json", + "html", + "lcov", + "text", + "text-summary" + ], + "collectCoverageFrom": [ + "src/**/*.js" + ], + "testMatch": [ + "/src/**/test.js" + ], + "coveragePathIgnorePatterns": [ + ], + "testEnvironment": "node", + "moduleNameMapper": { + "\\.(css|scss)$": "/dev/jest-empty.js" + }, + "transform": { + "^.+\\.js$": "babel-jest", + "^.+\\.html$": "/dev/string" + }, + "coverageThreshold": { + "global": { + "branches": 5, + "functions": 5, + "lines": 10, + "statements": 10 + } + } +} diff --git a/dev/karma.base.js b/dev/karma.base.js deleted file mode 100644 index f11184c..0000000 --- a/dev/karma.base.js +++ /dev/null @@ -1,30 +0,0 @@ - -module.exports = { - - basePath: '../', - singleRun: false, - frameworks: ['jasmine', 'browserify'], - reporters: ['progress'], - - files: [ - './node_modules/babel-polyfill/dist/polyfill.js', - './node_modules/whatwg-fetch/fetch.js', - './src/**/test.js' - ], - - preprocessors: { - 'src/**/*.js': ['browserify'], - }, - - browserify: { - debug: true, - transform: ['babelify'] - }, - - customLaunchers: { - ChromeNoSandbox: { - base: 'Chrome', - flags: ['--no-sandbox'] - } - } -}; diff --git a/dev/karma.cover.js b/dev/karma.cover.js deleted file mode 100644 index 6cf2a2a..0000000 --- a/dev/karma.cover.js +++ /dev/null @@ -1,45 +0,0 @@ -var assign = require('object-assign'); -var base = require('./karma.base.js'); - - -module.exports = function (config) { - - var options = assign(base, { - singleRun: true, - - browsers: ['Chrome'], - - reporters: ['progress', 'coverage'], - - coverageReporter: { - dir : 'build/coverage/', - reporters: [ - { - type: 'lcov', - subdir: '.' - }, - { - type : 'html', - subdir: '.' - }, - { - type : 'text', - subdir: '.' - } - ] - }, - - browserify: { - debug: true, - transform: [ - ['babelify', {plugins: 'istanbul'}] - ] - } - }); - - if(process.env.TRAVIS || process.env.CIRCLECI) { - options.browsers = ['ChromeNoSandbox']; - } - - config.set(options); -}; diff --git a/dev/karma.debug.firefox.js b/dev/karma.debug.firefox.js deleted file mode 100644 index 057da52..0000000 --- a/dev/karma.debug.firefox.js +++ /dev/null @@ -1,12 +0,0 @@ -var assign = require('object-assign'); -var base = require('./karma.base.js'); - - -module.exports = function (config) { - - var options = assign(base, { - browsers: ['Firefox'] - }); - - config.set(options); -}; diff --git a/dev/karma.debug.js b/dev/karma.debug.js deleted file mode 100644 index 5a2e2e3..0000000 --- a/dev/karma.debug.js +++ /dev/null @@ -1,12 +0,0 @@ -var assign = require('object-assign'); -var base = require('./karma.base.js'); - - -module.exports = function (config) { - - var options = assign(base, { - browsers: ['Chrome'] - }); - - config.set(options); -}; diff --git a/dev/karma.unit.js b/dev/karma.unit.js deleted file mode 100644 index 16accc4..0000000 --- a/dev/karma.unit.js +++ /dev/null @@ -1,27 +0,0 @@ -var os = require('os'); -var assign = require('object-assign'); -var base = require('./karma.base.js'); - - -function browsers (b) { - if (os.platform() === 'darwin') b.push('Safari'); - return b; -} - - -module.exports = function (config) { - - var options = assign(base, { - singleRun: true, - phantomjsLauncher: { - exitOnResourceError: true - }, - browsers: browsers(['Chrome', 'Firefox']) - }); - - if(process.env.TRAVIS || process.env.CIRCLECI) { - options.browsers = browsers(['ChromeNoSandbox', 'Firefox']); - } - - config.set(options); -}; diff --git a/dev/rollup.config.dev.js b/dev/rollup.config.dev.js deleted file mode 100644 index 83f9ae3..0000000 --- a/dev/rollup.config.dev.js +++ /dev/null @@ -1,5 +0,0 @@ -const config = require('./rollup.config'); - -config.output.sourcemap = 'inline'; - -module.exports = config; diff --git a/dev/rollup.config.js b/dev/rollup.config.js index 1f7c7f9..45cda00 100644 --- a/dev/rollup.config.js +++ b/dev/rollup.config.js @@ -1,12 +1,11 @@ const json = require('rollup-plugin-json'); -const babel = require('rollup-plugin-babel'); const string = require('rollup-plugin-string'); const sourcemaps = require('rollup-plugin-sourcemaps'); const pkg = require('../package.json'), - d3External = Object.keys(pkg.dependencies).filter(name => name.substring(0, 3) === 'd3-'), + d3External = Object.keys(pkg.dependencies).concat(Object.keys(pkg.peerDependencies)).filter(name => name.substring(0, 3) === 'd3-'), external = d3External.concat(['handlebars']), globals = d3External.reduce((g, name) => {g[name] = 'd3'; return g;}, {handlebars: 'handlebars'}); @@ -27,11 +26,6 @@ module.exports = { string({ include: 'src/**/*.html' }), - babel({ - babelrc: false, - plugins: ['external-helpers'], - presets: ['es2015-rollup'] - }), sourcemaps() ] }; diff --git a/dev/string.js b/dev/string.js new file mode 100644 index 0000000..9de62e8 --- /dev/null +++ b/dev/string.js @@ -0,0 +1,8 @@ +module.exports = { + process (src) { + return `module.exports = ${JSON.stringify(src)};`; + }, + + //getCacheKey () { + //} +}; diff --git a/dev/utils.js b/dev/utils.js deleted file mode 100644 index a6d49f4..0000000 --- a/dev/utils.js +++ /dev/null @@ -1,32 +0,0 @@ -// Test utilities -import {viewProviders, viewDebounce} from 'd3-view'; - - -// -// Make sure d3-view-components point to the local origin for templates -viewProviders.require.libs.set('d3-view-components', { - origin: '/base' -}); - - -export function testAsync (runAsync) { - return (done) => { - runAsync().then(done, done.fail); - }; -} - -export function test (name, runAsync) { - return it(name, testAsync(runAsync)); -} - -export const nextTick = viewDebounce(); - -// -// Return an object with a promise and the resolve function for the promise -export function getWaiter () { - var waiter = {}; - waiter.promise = new Promise(function (resolve) { - waiter.resolve = resolve; - }); - return waiter; -} diff --git a/index.js b/index.js index 9229e8b..77ba4ad 100644 --- a/index.js +++ b/index.js @@ -5,7 +5,8 @@ export {default as viewAutocomplete} from './src/autocomplete/index'; export {default as viewCard} from './src/card/index'; export {default as viewCollapse} from './src/collapse/index'; export {default as viewFlatpickr} from './src/flatpickr/index'; -export {default as viewMarked} from './src/marked/index'; +export {default as viewIcons} from './src/icons/index'; +export {default as viewMarked} from './src/markdown/index'; export {default as viewModal} from './src/modal/index'; export {default as viewSidebar} from './src/sidebar/index'; export {default as viewTabs} from './src/tabs/index'; diff --git a/index.scss b/index.scss index f226bc9..86a6f35 100644 --- a/index.scss +++ b/index.scss @@ -1,3 +1,4 @@ @import 'src/autocomplete/main'; -@import 'src/marked/main'; +@import 'src/icons/index'; +@import 'src/markdown/main'; @import 'src/sidebar/main'; diff --git a/package.json b/package.json index c5dfe29..54f0def 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "version": "0.2.1", + "version": "0.3.0", "name": "d3-view-components", "title": "d3-view components", "description": "Reusable d3-view components", @@ -25,69 +25,49 @@ "jsnext:main": "index", "dependencies": { "awesomplete": "1.1", - "d3-dispatch": "1.0", - "d3-ease": "1.0", - "d3-let": "0.4", - "d3-selection": "1.2", "d3-transition": "1.1", - "d3-view": "1.2", - "handlebars": "4.0" + "d3-view": "^1.3.3", + "handlebars": "4.0", + "highlightjs": "9.10", + "marked": "~0.3.9" + }, + "peerDependencies": { + "d3-dispatch": "1.x", + "d3-ease": "1.x", + "d3-let": "0.4.x" }, "devDependencies": { "babel-core": "6.26", "babel-eslint": "8.2", - "babel-plugin-external-helpers": "6.22", - "babel-plugin-istanbul": "4.1", - "babel-polyfill": "6.26", "babel-preset-env": "1.6", - "babel-preset-es2015-rollup": "3.0", - "babelify": "8.0", - "bootstrap": "4.0.0-beta.2", - "browserify-istanbul": "3.0", - "eslint": "4.15", + "bootstrap": "4.0", + "d3-view-test": "0.3", + "eslint": "4.18", + "feather-icons": "4.5", + "flatpickr": "4.3", "fs-extra": "5.0", - "jasmine-core": "2.8", - "karma": "2.0", - "karma-browserify": "5.1", - "karma-chrome-launcher": "2.2", - "karma-coverage": "1.1", - "karma-firefox-launcher": "1.1", - "karma-html2js-preprocessor": "1.1", - "karma-jasmine": "1.1", - "karma-junit-reporter": "1.2", - "karma-phantomjs-launcher": "1.0", - "karma-safari-launcher": "1.0", - "navigo": "7.0", + "jest": "22", + "navigo": "7.1", "node-sass": "4.7", "package-preamble": "0.1", - "phantomjs-prebuilt": "2.1", "publish": "0.6", - "rollup": "0.54", + "rollup": "0.56", "rollup-plugin-babel": "3.0", "rollup-plugin-json": "2.3", "rollup-plugin-node-resolve": "3.0", "rollup-plugin-sourcemaps": "0.4", "rollup-plugin-string": "2.0", "rollup-watch": "4.3", - "uglify-js": "3.3", - "watchify": "3.9", - "whatwg-fetch": "2.0" + "sass-lint": "1.12" }, "scripts": { - "lint": "eslint .", + "lint": "eslint . && sass-lint *.scss src/**/*.scss", "cleanup": "rm -rf build", - "test": "npm run-script lint && npm run-script unit", - "rollup": "cp ./node_modules/navigo/src/index.js src/router/navigo.js && rollup -c dev/rollup.config.js --banner \"$(preamble)\"", - "dev": "rollup -c dev/rollup.config.dev.js -w", - "css": "node-sass index.scss build/d3-view-components.css --include-path node_modules --output-style compressed", - "build": "npm run-script rollup && uglifyjs --preamble \"$(preamble)\" build/d3-view-components.js -c -m -o build/d3-view-components.min.js && npm run-script css", - "unit": "karma start dev/karma.unit.js", - "cover": "karma start dev/karma.cover.js", - "debug": "karma start dev/karma.debug.js", + "test": "npm run-script lint && npm run-script test:unit", + "test:unit": "jest -c dev/jest.config.json --no-cache", + "watch": "rollup -c dev/rollup.config.js -w", "debug:firefox": "karma start dev/karma.debug.firefox.js", - "docs": "rollup -c _ci/rollup.config.js && view-require -c _ci/require.config.js -s && uglifyjs build/docs.js -c -m -o build/docs.min.js && _ci/build-docs.js && node-sass _ci/docs.scss build/docs.css --include-path node_modules --output-style compressed", - "serve": "http-server build/", - "prepare": "npm run-script build", + "prepare": "cp ./node_modules/navigo/lib/navigo.es.js src/router/navigo.js && cp ./node_modules/feather-icons/dist/icons.json src/icons/icons.json && rollup -c dev/rollup.config.js --banner \"$(preamble)\"", "postpublish": "VERSION=`node -e 'console.log(require(\"./package.json\").version)'`; git push && git tag -am \"Release $VERSION.\" v${VERSION} && git push --tags", "release": "publish" } diff --git a/src/active/index.js b/src/active/index.js index 0c96de5..dfa7bc2 100644 --- a/src/active/index.js +++ b/src/active/index.js @@ -38,7 +38,7 @@ export default { }; // -// Make sure the currentUrl attribute is reactive -viewEvents.on('component-created', vm => { - if (!vm.parent) vm.model.currentUrl = vm.providers.location.href; +// Make sure the currentUrl attribute is a reactive attribute +viewEvents.on('component-mount.currentUrl', vm => { + if (!vm.parent) vm.model.currentUrl = vm.ownerDocument.location.href; }); diff --git a/src/active/test.js b/src/active/test.js index 679b4d0..760a06a 100644 --- a/src/active/test.js +++ b/src/active/test.js @@ -1,10 +1,10 @@ import {view} from 'd3-view'; +import {render, getWaiter} from 'd3-view-test'; -import {test, getWaiter} from '../../dev/utils.js'; import {viewActive} from '../../build/d3-view-components'; -describe('viewActive -', () => { +describe('viewActive', () => { let vm, waiter; @@ -24,11 +24,8 @@ describe('viewActive -', () => { test ('currentUrl', async () => { expect(vm).toBeTruthy(); - var el = vm.select('body').append('div').html('foo link'); - await vm.mount(el); - vm.sel.remove(); - var dir = await waiter.promise; - expect(dir.name).toBe('d3-active'); + const d = await render('', vm); + expect(d.view).toBe(vm); }); }); diff --git a/src/alert/index.js b/src/alert/index.js index 4d46162..9f635be 100644 --- a/src/alert/index.js +++ b/src/alert/index.js @@ -9,6 +9,9 @@ const levels = { }; +const messageKey = msg => `${msg.level}::${msg.message}`; + + // component render function export default { @@ -40,7 +43,7 @@ export default { }; }, - render (props) { + render () { var model = this.model, messages = model.messages.splice(0), @@ -70,11 +73,6 @@ export default { } } - return this.viewElement(tpl, props); + return tpl; } }; - - -function messageKey (msg) { - return `${msg.level}::${msg.message}`; -} diff --git a/src/alert/readme.md b/src/alert/readme.md index 6809162..fae3f55 100644 --- a/src/alert/readme.md +++ b/src/alert/readme.md @@ -11,13 +11,13 @@ Same messages with same level are not repeated, instead a counter is added.
- +


-This example is created with the below markup and the [/alert/form-example.json](/alert/form-example.json) form schema. +This example is created with the below markup and the [form-example.json](alert/form-example.json) form schema. ```html
@@ -25,7 +25,7 @@ This example is created with the below markup and the [/alert/form-example.json]
- +
@@ -40,7 +40,7 @@ import {viewAlert} from 'd3-view-components'; var vm = view({ components: { - alerts: viewAlert + alerts: viewAlert, ... } }); @@ -69,11 +69,11 @@ model.$emit('alertMessage', 'Hi!'); To display messages with different levels: ```javascript model.$emit('alertMessage', { - message: 'Warning!> This is a wrning message' + message: 'Warning! This is a wrning message' level: 'warning' }); model.$emit('alertMessage', { - message: 'Danger!> Something very wrong' + message: 'Danger! Something very wrong' level: 'danger' }); diff --git a/src/alert/template.html b/src/alert/template.html index f04138c..f0696b6 100644 --- a/src/alert/template.html +++ b/src/alert/template.html @@ -1,16 +1,9 @@
-
- - - - -
+
+ + + +
diff --git a/src/alert/test.js b/src/alert/test.js index 1b13904..42d59a4 100644 --- a/src/alert/test.js +++ b/src/alert/test.js @@ -1,8 +1,10 @@ import {view} from 'd3-view'; import {isFunction} from 'd3-let'; +import {render, validateHTML} from 'd3-view-test'; -import {test, nextTick} from '../../dev/utils.js'; -import {viewAlert} from '../../build/d3-view-components'; +import {viewAlert} from '../../index'; + +import tpl from './template.html'; describe('Alert -', () => { @@ -17,15 +19,19 @@ describe('Alert -', () => { }); }); + test('template', () => { + expect(validateHTML(tpl)).toBe(true); + }); + test ('simple', async () => { - await vm.mount(vm.viewElement('
')); - expect(isFunction(vm.model.$alertMessage)).toBe(true); + const d = await render('', vm); + expect(isFunction(d.view.model.$alertMessage)).toBe(true); var alerts = vm.sel.select('.alert-messages').model(); expect(alerts.messages.length).toBe(0); vm.model.$alertMessage('Hi!'); // expect(alerts.messages.length).toBe(1); - await nextTick(); + await d.nextTick(); // var elements = vm.sel.selectAll('.alert'); expect(elements.size()).toBe(1); @@ -33,9 +39,30 @@ describe('Alert -', () => { // elements = vm.sel.selectAll('.alert'); expect(elements.size()).toBe(1); - await nextTick(); + expect(elements.directives()).toBeTruthy(); + await d.nextTick(); elements = vm.sel.selectAll('.alert'); expect(elements.size()).toBe(2); }); + test ('close', async () => { + const d = await render('', vm); + d.view.model.$alertMessage('Hi!'); + var alerts = vm.sel.select('.alert-messages').model(); + expect(alerts.messages.length).toBe(1); + let elements = d.selectAll('.alert'); + expect(elements.size()).toBe(0); + await d.nextTick(); + elements = d.selectAll('.alert'); + expect(elements.size()).toBe(1); + // + // close it + const btn = d.select('button.close'); + expect(btn.size()).toBe(1); + // const uid = btn.directives().all[0].uid; + // const events = btn.on(`click.${uid}`); + // d.click('button.close'); + // elements = d.selectAll('.alert'); + // expect(elements.size()).toBe(0); + }); }); diff --git a/src/collapse/test.js b/src/collapse/test.js index 881c2b3..3c5e9fb 100644 --- a/src/collapse/test.js +++ b/src/collapse/test.js @@ -1,5 +1,4 @@ -import {test} from '../../dev/utils.js'; -import {viewCollapse} from '../../build/d3-view-components'; +import {viewCollapse} from '../../index'; describe('Collapse -', () => { diff --git a/src/flatpickr/index.js b/src/flatpickr/index.js index 4b302a7..777b228 100644 --- a/src/flatpickr/index.js +++ b/src/flatpickr/index.js @@ -4,7 +4,7 @@ export default { var self = this, opts = options && options.$data ? options.$data() : {}; - this.providers.require('flatpickr').then(flatpickr => { + this.require('flatpickr').then(flatpickr => { if (self.fp) self.fp.destroy(); self.sel.on('input', null); self.sel.on('change', null); diff --git a/src/flatpickr/test.js b/src/flatpickr/test.js index 50eb98e..6de95d5 100644 --- a/src/flatpickr/test.js +++ b/src/flatpickr/test.js @@ -1,10 +1,10 @@ import {view} from 'd3-view'; +import {render, getWaiter} from 'd3-view-test'; -import {test, getWaiter} from '../../dev/utils.js'; -import {viewFlatpickr} from '../../build/d3-view-components'; +import {viewFlatpickr} from '../../index'; -describe('Flatpickr -', () => { +describe('Flatpickr', () => { let vm, waiter; @@ -26,17 +26,16 @@ describe('Flatpickr -', () => { }); test ('simple', async () => { - var el = vm.select('body').append('div').html(''); - await vm.mount(el); + const d = await render('', vm); var opts = await waiter.promise; expect(opts).toEqual({}); - var dir = vm.sel.select('input').directives().all[0]; + var dir = d.select('input').directives().all[0]; expect(dir.fp).toBeTruthy(); - waiter = getWaiter(); - vm.sel.remove(); - var dir2 = await waiter.promise; - expect(dir2).toBe(dir); - expect(dir2.fp).toBe(null); + //waiter = getWaiter(); + //vm.sel.remove(); + //var dir2 = await waiter.promise; + //expect(dir2).toBe(dir); + //expect(dir2.fp).toBe(null); }); }); diff --git a/src/icons/_index.scss b/src/icons/_index.scss new file mode 100644 index 0000000..adfb6a8 --- /dev/null +++ b/src/icons/_index.scss @@ -0,0 +1,5 @@ + + +.view-icon { + display: "inline-block"; +} diff --git a/src/icons/index.js b/src/icons/index.js index e69de29..4db75f3 100644 --- a/src/icons/index.js +++ b/src/icons/index.js @@ -0,0 +1,66 @@ +import feather from './icons.json'; + + +const icons = { + // map icon name to svg src + // by default use feather icons + default: 'droplet', + svg: feather, + width: 24, + height: 24, + + src (name) { + return `https://unpkg.com/feather-icons/dist/icons/${name}.svg`; + }, + + install (vm) { + vm.addComponent('icon', icon); + } +}; + + +// +// Icon component +export const icon = { + + props: { + width: null, + height: null, + name: null, + fill: 'none', + stroke: 'currentColor', + strokeWidth: 2, + linecup: "round", + linejoin: "round", + src: null + }, + + render () { + const props = this.props; + if (props.src) + return this.createElement('img').attr('alt', props.name || '').attr('src', props.src); + + const width = props.width || icons.width, + height = props.height || icons.height, + name = props.name || icons.default; + if (!name) return ''; + const svg = icons.svg[name]; + if (!svg) return ''; + return this.createElement('div') + .append('svg') + .attr('height', height) + .attr('width', width) + .attr('fill', props.fill) + .attr('stroke', props.stroke) + .attr('stroke-width', props.strokeWidth) + .attr('stroke-linecup', props.linecup) + .attr('stroke-linejoin', props.linejoin) + .attr('version', '1.1') + .attr('viewBox', `0 0 ${width} ${height}`) + .classed('view-icon', true) + .html(svg); + } +}; + + +export default icons; diff --git a/src/icons/readme.md b/src/icons/readme.md new file mode 100644 index 0000000..0c3a30b --- /dev/null +++ b/src/icons/readme.md @@ -0,0 +1,11 @@ +## Svg Icons + +Add support for ``svg`` icons: +```html + +``` +By defaults it renders svg icons from [feather][]. + + + +[feather]: https://feathericons.com/ diff --git a/src/icons/test.js b/src/icons/test.js new file mode 100644 index 0000000..92176e6 --- /dev/null +++ b/src/icons/test.js @@ -0,0 +1,21 @@ +import {render} from 'd3-view-test'; +import {view} from 'd3-view'; + +import {viewIcons} from '../../index'; + + +describe('viewMarked -', () => { + + test ('simple', async () => { + const vm = view().use(viewIcons); + const d = await render('', vm); + expect(d.view).toBe(vm); + }); + + test ('empty', async () => { + const vm = view().use(viewIcons); + const d = await render('', vm); + expect(d.view).toBe(vm); + }); + +}); diff --git a/src/markdown/_main.scss b/src/markdown/_main.scss new file mode 100644 index 0000000..13b8274 --- /dev/null +++ b/src/markdown/_main.scss @@ -0,0 +1,27 @@ +@import 'variables'; + +markdown { + visibility: hidden; +} + +.anchor { + text-decoration: none; + float: left; + padding-right: 4px; + margin-left: -20px; + line-height: 1; + + .view-icon { + vertical-align: middle; + visibility: hidden; + } +} + + +h1,h2,h3,h4,h5,h6 { + &:hover { + .anchor svg { + visibility: visible; + } + } +} diff --git a/src/marked/_variables.scss b/src/markdown/_variables.scss similarity index 53% rename from src/marked/_variables.scss rename to src/markdown/_variables.scss index 5f10a37..d2a2a4c 100644 --- a/src/marked/_variables.scss +++ b/src/markdown/_variables.scss @@ -1 +1,2 @@ $marked-heading-icon-size: 20px !default; +$anchor-img-color: #91969a !default; diff --git a/src/markdown/index.js b/src/markdown/index.js new file mode 100644 index 0000000..d579b28 --- /dev/null +++ b/src/markdown/index.js @@ -0,0 +1,63 @@ +import {viewSlugify} from 'd3-view'; + +import {icon} from '../icons/index'; + + +export default { + components: {icon}, + + props: { + source: null, + anchorIcon: 'link' + }, + + render (props, attrs, el) { + let marked, hl, markedOptions; + + const + classes = attrs.class || 'markdown', + compile = source => { + source = source ? marked(source, markedOptions) : ''; + return this.createElement('div').attr('class', classes).html(source); + }; + + return Promise.all([this.require('marked'), this.require('highlightjs')]).then(libs => { + [marked, hl] = libs; + markedOptions = this.markedOptions(props, marked, hl); + if (props.source) + return this.fetchText(props.source).then(response => compile(response.data)); + else + return compile(this.select(el).html()); + }); + }, + + markedOptions (props, marked, hl) { + var renderer = new marked.Renderer(), + icon = props.anchorIcon; + + renderer.heading = heading; + + return { + renderer, + highlight, + langPrefix: "hljs " + }; + + function heading (text, level) { + var id = viewSlugify(text); + return (` + + ${text} + + `); + } + + function highlight (code, lang) { + lang = hl.getLanguage(lang) ? [lang] : undefined; + return hl.highlightAuto(code, lang).value; + } + } + +}; diff --git a/src/marked/readme.md b/src/markdown/readme.md similarity index 59% rename from src/marked/readme.md rename to src/markdown/readme.md index 54e2397..77f5de1 100644 --- a/src/marked/readme.md +++ b/src/markdown/readme.md @@ -1,19 +1,19 @@ -## Marked Directive +## Markdown Component -The ``viewMarked`` directive can be used to render markdown into the hosting element. -The directive asynchrnously requires two libraries: +The ``viewMarked`` component can be used to render markdown into the hosting element. +The component asynchrnously requires two libraries: * [marked][] for rendering markdown * [highlightjs][] for syntax highlighting -To use the directive, make sure it is included in the view constructor: +To use the component, make sure it is included in the view constructor: ```javascript import {view} from 'd3-view'; import {viewMarked} from 'd3-view-components'; var vm = view({ - directives: { - marked: viewMarked + components: { + markdown: viewMarked } }); ``` @@ -22,7 +22,11 @@ The directive is used throughout this site to render markdown form the [d3-view- Simple usage: ```html -
+ +## Markdown component + +This is the markdown component! + ``` diff --git a/src/marked/test.js b/src/markdown/test.js similarity index 71% rename from src/marked/test.js rename to src/markdown/test.js index 8229d39..d844995 100644 --- a/src/marked/test.js +++ b/src/markdown/test.js @@ -1,23 +1,20 @@ +import {render} from 'd3-view-test'; import {view} from 'd3-view'; -import {test} from '../../dev/utils.js'; -import {viewMarked} from '../../build/d3-view-components'; +import {viewMarked} from '../../index'; describe('viewMarked -', () => { - let vm; - - beforeEach(() => { - vm = view({ + test ('simple', async () => { + const vm = view({ components: { markdown: viewMarked } }); - }); - - test ('simple', async () => { expect(vm).toBeTruthy(); + const d = await render('', vm); + expect(d.view).toBe(vm); //await vm.mount(vm.viewElement('
# A Test
')); //var sel = vm.sel.select('.markdown'); //expect(sel.size()).toBe(1); diff --git a/src/marked/_main.scss b/src/marked/_main.scss deleted file mode 100644 index 4862a04..0000000 --- a/src/marked/_main.scss +++ /dev/null @@ -1,30 +0,0 @@ -@import 'variables'; - -.markdown { - visibility: hidden; -} - -.markdown-body { - - .anchor { - float: left; - padding-right: 4px; - margin-left: -20px; - line-height: 1; - - i { - vertical-align: middle; - visibility: hidden; - font-size: $marked-heading-icon-size; - font-family: monospace; - } - } - - h1,h2,h3,h4,h5,h6 { - &:hover { - .anchor i { - visibility: visible; - } - } - } -} diff --git a/src/marked/index.js b/src/marked/index.js deleted file mode 100644 index ad894a6..0000000 --- a/src/marked/index.js +++ /dev/null @@ -1,64 +0,0 @@ -import {viewSlugify} from 'd3-view'; - - -export default { - - props: { - source: null, - anchorIcon: 'ion-ios-grid-view-outline' - }, - - render (props, attrs, el) { - const - self = this, - r = this.providers.require, - classes = attrs.class || 'markdown'; - - let marked, hl; - - - return Promise.all([r('marked'), r('highlightjs')]).then(libs => { - [marked, hl] = libs; - - if (!self._markedOptions) - self._markedOptions = self.markedOptions(props, marked, hl); - - if (props.source) - return this.fetchText(props.source).then(response => build(response.data)); - else - return build(this.select(el).text()); - - }); - - - function build (source) { - source = source ? marked(source, self._markedOptions) : ''; - return self.createElement('div').attr('class', classes).html(source); - } - }, - - markedOptions (props, marked, hl) { - if (this._markedOptions) return self._markedOptions; - var renderer = new marked.Renderer(), - icon = props.anchorIcon; - - renderer.heading = heading; - - return { - renderer, - highlight, - langPrefix: "hljs " - }; - - function heading (text, level) { - var id = viewSlugify(text); - return ` ${text}`; - } - - function highlight (code, lang) { - lang = hl.getLanguage(lang) ? [lang] : undefined; - return hl.highlightAuto(code, lang).value; - } - } - -}; diff --git a/src/modal/index.js b/src/modal/index.js index ae79bfe..78698a3 100644 --- a/src/modal/index.js +++ b/src/modal/index.js @@ -1,13 +1,9 @@ import {easeExpOut} from 'd3-ease'; import {isString} from 'd3-let'; -import {viewWarn, viewBase} from 'd3-view'; import tpl from './template.html'; -const select = viewBase.select; - - const modalComponent = { props: { transitionDuration: 300 @@ -82,45 +78,48 @@ const modalDirective = { }; -export default { +// function for opening a modal +// inject this method to the root model +const modalOpen = (vm) => { + + return options => { + if (isString(options)) options = optionsFromTarget(vm, options); + var modal = vm.select('#d3-view-modal'); + if (!modal.size()) + vm.select('body').append('modal').mount(options).then(cm => cm.model.$showModal()); + else + modal.model().$update(options).$showModal(); + }; +}; + + +const viewModal = { modalComponent, modalDirective, modalOpen, install (vm) { - vm.addComponent('modal', modalComponent); - vm.addDirective('modal', modalDirective); - vm.model.$openModal = modalOpen; + vm.addComponent('modal', viewModal.modalComponent); + vm.addDirective('modal', viewModal.modalDirective); + vm.model.$openModal = viewModal.modalOpen; } }; -// function for opening a modal -// inject this method to the root model -function modalOpen (options) { - if (isString(options)) options = optionsFromTarget(options); - var modal = select('#d3-view-modal'); - if (!modal.size()) - select('body').append('modal').mount(options, vm => vm.model.$showModal()); - else - modal.model().$update(options).$showModal(); -} - - -function optionsFromTarget (selector) { - var sel = select(selector); +export default viewModal; + + +const optionsFromTarget = (vm, selector) => { + var sel = vm.select(selector); if (sel.size() === 1) { return { modalTitle: textFromTarget(sel.select('modal-title')), modalBody: textFromTarget(sel.select('modal-body')) }; } else { - viewWarn(`Could not obtain target from selector "${selector}"`); + vm.logWarn(`Could not obtain target from selector "${selector}"`); return {}; } -} +}; -function textFromTarget (sel) { - if (sel.size()) return sel.html(); - return ''; -} +const textFromTarget = sel => sel.size() ? sel.html() : ''; diff --git a/src/modal/test.js b/src/modal/test.js index 7e66d81..2c420a5 100644 --- a/src/modal/test.js +++ b/src/modal/test.js @@ -1,11 +1,11 @@ import {view} from 'd3-view'; import {isFunction} from 'd3-let'; +import {render, nextTick} from 'd3-view-test'; -import {test, nextTick} from '../../dev/utils.js'; -import {viewModal} from '../../build/d3-view-components'; +import {viewModal} from '../../index'; -describe('viewMarked -', () => { +describe('viewModal', () => { let vm; @@ -16,8 +16,8 @@ describe('viewMarked -', () => { test ('simple', async () => { expect(isFunction(vm.model.$openModal)).toBe(true); expect(vm.model.$openModal).toBe(viewModal.modalOpen); - await vm.mount(vm.createElement('div')); - expect(vm.model.$openModal).toBe(viewModal.modalOpen); + const d = await render('
', vm); + expect(d.view.model.$openModal).toBe(viewModal.modalOpen); vm.model.$openModal({ title: "test", body: "this is a test for the modal" diff --git a/src/readme.md b/src/readme.md new file mode 100644 index 0000000..7d8b3af --- /dev/null +++ b/src/readme.md @@ -0,0 +1 @@ +# Documentation \ No newline at end of file diff --git a/src/router/index.js b/src/router/index.js index dc9c46b..1832567 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -42,13 +42,13 @@ export default { }); // Add router to all components which are part of the vm view - viewEvents.on('component-mount', cm => { + viewEvents.on('component-mount.router', cm => { if (cm.root === vm) cm.router = router; }); // auto resolve if (config.autoResolve !== false) - vm.events.on('mounted', () => { + vm.events.on('mounted.router', () => { vm.logDebug('Resolve route with router'); vm.router.resolve(); }); diff --git a/src/router/link.js b/src/router/link.js index 777b755..42aa14a 100644 --- a/src/router/link.js +++ b/src/router/link.js @@ -1,6 +1,7 @@ import {isAbsoluteUrl} from 'd3-view'; - +// +// Directive for navigating export default { mount (model) { diff --git a/src/router/navigo.js b/src/router/navigo.js index 59570e7..6e20c96 100644 --- a/src/router/navigo.js +++ b/src/router/navigo.js @@ -1,9 +1,7 @@ +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + function isPushStateAvailable() { - return !!( - typeof window !== 'undefined' && - window.history && - window.history.pushState - ); + return !!(typeof window !== 'undefined' && window.history && window.history.pushState); } function Navigo(r, useHash, hash) { @@ -39,30 +37,26 @@ function clean(s) { function regExpResultToParams(match, names) { if (names.length === 0) return null; if (!match) return null; - return match - .slice(1, match.length) - .reduce((params, value, index) => { - if (params === null) params = {}; - params[names[index]] = decodeURIComponent(value); - return params; - }, null); + return match.slice(1, match.length).reduce(function (params, value, index) { + if (params === null) params = {}; + params[names[index]] = decodeURIComponent(value); + return params; + }, null); } function replaceDynamicURLParts(route) { - var paramNames = [], regexp; + var paramNames = [], + regexp; if (route instanceof RegExp) { regexp = route; } else { - regexp = new RegExp( - route.replace(Navigo.PARAMETER_REGEXP, function (full, dots, name) { - paramNames.push(name); - return Navigo.REPLACE_VARIABLE_REGEXP; - }) - .replace(Navigo.WILDCARD_REGEXP, Navigo.REPLACE_WILDCARD) + Navigo.FOLLOWED_BY_SLASH_REGEXP - , Navigo.MATCH_REGEXP_FLAGS); + regexp = new RegExp(route.replace(Navigo.PARAMETER_REGEXP, function (full, dots, name) { + paramNames.push(name); + return Navigo.REPLACE_VARIABLE_REGEXP; + }).replace(Navigo.WILDCARD_REGEXP, Navigo.REPLACE_WILDCARD) + Navigo.FOLLOWED_BY_SLASH_REGEXP, Navigo.MATCH_REGEXP_FLAGS); } - return { regexp, paramNames }; + return { regexp: regexp, paramNames: paramNames }; } function getUrlDepth(url) { @@ -73,16 +67,21 @@ function compareUrlDepth(urlA, urlB) { return getUrlDepth(urlB) - getUrlDepth(urlA); } -function findMatchedRoutes(url, routes = []) { - return routes - .map(route => { - var { regexp, paramNames } = replaceDynamicURLParts(clean(route.route)); - var match = url.replace(/^\/+/, '/').match(regexp); - var params = regExpResultToParams(match, paramNames); +function findMatchedRoutes(url) { + var routes = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; + + return routes.map(function (route) { + var _replaceDynamicURLPar = replaceDynamicURLParts(clean(route.route)), + regexp = _replaceDynamicURLPar.regexp, + paramNames = _replaceDynamicURLPar.paramNames; + + var match = url.replace(/^\/+/, '/').match(regexp); + var params = regExpResultToParams(match, paramNames); - return match ? { match, route, params } : false; - }) - .filter(m => m); + return match ? { match: match, route: route, params: params } : false; + }).filter(function (m) { + return m; + }); } function match(url, routes) { @@ -90,13 +89,13 @@ function match(url, routes) { } function root(url, routes) { - var matched = routes.map( - route => route.route === '' || route.route === '*' ? url : url.split(new RegExp(route.route + '($|\/)'))[0] - ); + var matched = routes.map(function (route) { + return route.route === '' || route.route === '*' ? url : url.split(new RegExp(route.route + '($|\/)'))[0]; + }); var fallbackURL = clean(url); if (matched.length > 1) { - return matched.reduce((result, url) => { + return matched.reduce(function (result, url) { if (result.length > url.length) result = url; return result; }, matched[0]); @@ -107,10 +106,7 @@ function root(url, routes) { } function isHashChangeAPIAvailable() { - return !!( - typeof window !== 'undefined' && - 'onhashchange' in window - ); + return typeof window !== 'undefined' && 'onhashchange' in window; } function extractGETParameters(url) { @@ -118,8 +114,11 @@ function extractGETParameters(url) { } function getOnlyURL(url, useHash, hash) { - var onlyURL = url, split; - var cleanGETParam = str => str.split(/\?(.*)?$/)[0]; + var onlyURL = url, + split; + var cleanGETParam = function cleanGETParam(str) { + return str.split(/\?(.*)?$/)[0]; + }; if (typeof hash === 'undefined') { // To preserve BC @@ -137,9 +136,11 @@ function getOnlyURL(url, useHash, hash) { } function manageHooks(handler, hooks, params) { - if (hooks && typeof hooks === 'object') { + if (hooks && (typeof hooks === 'undefined' ? 'undefined' : _typeof(hooks)) === 'object') { if (hooks.before) { - hooks.before((shouldRoute = true) => { + hooks.before(function () { + var shouldRoute = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; + if (!shouldRoute) return; handler(); hooks.after && hooks.after(params); @@ -152,7 +153,7 @@ function manageHooks(handler, hooks, params) { } } handler(); -}; +} function isHashedRoot(url, useHash, hash) { if (isPushStateAvailable() && !useHash) { @@ -163,23 +164,19 @@ function isHashedRoot(url, useHash, hash) { return false; } - let split = url.split(hash); + var split = url.split(hash); - if (split.length < 2 || split[1] === '') { - return true; - } - - return false; -}; + return split.length < 2 || split[1] === ''; +} Navigo.prototype = { helpers: { - match, - root, - clean, - getOnlyURL + match: match, + root: root, + clean: clean, + getOnlyURL: getOnlyURL }, - navigate: function (path, absolute) { + navigate: function navigate(path, absolute) { var to; path = path || ''; @@ -190,21 +187,24 @@ Navigo.prototype = { this.resolve(); } else if (typeof window !== 'undefined') { path = path.replace(new RegExp('^' + this._hash), ''); - window.location.href = - window.location.href - .replace(/#$/, '') - .replace(new RegExp(this._hash + '.*$'), '') + this._hash + path; + window.location.href = window.location.href.replace(/#$/, '').replace(new RegExp(this._hash + '.*$'), '') + this._hash + path; } return this; }, - on: function (...args) { + on: function on() { + var _this = this; + + for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + if (typeof args[0] === 'function') { this._defaultHandler = { handler: args[0], hooks: args[1] }; } else if (args.length >= 2) { if (args[0] === '/') { - let func = args[1]; + var func = args[1]; - if (typeof args[1] === 'object') { + if (_typeof(args[1]) === 'object') { func = args[1].uses; } @@ -212,32 +212,34 @@ Navigo.prototype = { } else { this._add(args[0], args[1], args[2]); } - } else if (typeof args[0] === 'object') { - let orderedRoutes = Object.keys(args[0]).sort(compareUrlDepth); + } else if (_typeof(args[0]) === 'object') { + var orderedRoutes = Object.keys(args[0]).sort(compareUrlDepth); - orderedRoutes.forEach(route => { - this.on(route, args[0][route]); + orderedRoutes.forEach(function (route) { + _this.on(route, args[0][route]); }); } return this; }, - off: function (handler) { + off: function off(handler) { if (this._defaultHandler !== null && handler === this._defaultHandler.handler) { this._defaultHandler = null; } else if (this._notFoundHandler !== null && handler === this._notFoundHandler.handler) { this._notFoundHandler = null; } - this._routes = this._routes.reduce((result, r) => { + this._routes = this._routes.reduce(function (result, r) { if (r.handler !== handler) result.push(r); return result; }, []); return this; }, - notFound: function (handler, hooks) { - this._notFoundHandler = { handler, hooks: hooks }; + notFound: function notFound(handler, hooks) { + this._notFoundHandler = { handler: handler, hooks: hooks }; return this; }, - resolve: function (current) { + resolve: function resolve(current) { + var _this2 = this; + var handler, m; var url = (current || this._cLoc()).replace(this._getRoot(), ''); @@ -245,16 +247,12 @@ Navigo.prototype = { url = url.replace(new RegExp('^\/' + this._hash), '/'); } - let GETParameters = extractGETParameters(current || this._cLoc()); - let onlyURL = getOnlyURL(url, this._useHash, this._hash); + var GETParameters = extractGETParameters(current || this._cLoc()); + var onlyURL = getOnlyURL(url, this._useHash, this._hash); if (this._paused) return false; - if ( - this._lastRouteResolved && - onlyURL === this._lastRouteResolved.url && - GETParameters === this._lastRouteResolved.query - ) { + if (this._lastRouteResolved && onlyURL === this._lastRouteResolved.url && GETParameters === this._lastRouteResolved.query) { if (this._lastRouteResolved.hooks && this._lastRouteResolved.hooks.already) { this._lastRouteResolved.hooks.already(this._lastRouteResolved.params); } @@ -273,40 +271,33 @@ Navigo.prototype = { name: m.route.name }; handler = m.route.handler; - manageHooks(() => { - manageHooks(() => { - m.route.route instanceof RegExp ? - handler(...(m.match.slice(1, m.match.length))) : - handler(m.params, GETParameters); - }, m.route.hooks, m.params, this._genericHooks); + manageHooks(function () { + manageHooks(function () { + m.route.route instanceof RegExp ? handler.apply(undefined, m.match.slice(1, m.match.length)) : handler(m.params, GETParameters); + }, m.route.hooks, m.params, _this2._genericHooks); }, this._genericHooks, m.params); return m; - } else if (this._defaultHandler && ( - onlyURL === '' || - onlyURL === '/' || - onlyURL === this._hash || - isHashedRoot(onlyURL, this._useHash, this._hash) - )) { - manageHooks(() => { - manageHooks(() => { - this._callLeave(); - this._lastRouteResolved = { url: onlyURL, query: GETParameters, hooks: this._defaultHandler.hooks }; - this._defaultHandler.handler(GETParameters); - }, this._defaultHandler.hooks); + } else if (this._defaultHandler && (onlyURL === '' || onlyURL === '/' || onlyURL === this._hash || isHashedRoot(onlyURL, this._useHash, this._hash))) { + manageHooks(function () { + manageHooks(function () { + _this2._callLeave(); + _this2._lastRouteResolved = { url: onlyURL, query: GETParameters, hooks: _this2._defaultHandler.hooks }; + _this2._defaultHandler.handler(GETParameters); + }, _this2._defaultHandler.hooks); }, this._genericHooks); return true; } else if (this._notFoundHandler) { - manageHooks(() => { - manageHooks(() => { - this._callLeave(); - this._lastRouteResolved = { url: onlyURL, query: GETParameters, hooks: this._notFoundHandler.hooks }; - this._notFoundHandler.handler(GETParameters); - }, this._notFoundHandler.hooks); + manageHooks(function () { + manageHooks(function () { + _this2._callLeave(); + _this2._lastRouteResolved = { url: onlyURL, query: GETParameters, hooks: _this2._notFoundHandler.hooks }; + _this2._notFoundHandler.handler(GETParameters); + }, _this2._notFoundHandler.hooks); }, this._genericHooks); } return false; }, - destroy: function () { + destroy: function destroy() { this._routes = []; this._destroyed = true; this._lastRouteResolved = null; @@ -317,12 +308,12 @@ Navigo.prototype = { window.removeEventListener('hashchange', this._onLocationChange); } }, - updatePageLinks: function () { + updatePageLinks: function updatePageLinks() { var self = this; if (typeof document === 'undefined') return; - this._findLinks().forEach(link => { + this._findLinks().forEach(function (link) { if (!link.hasListenerAttached) { link.addEventListener('click', function (e) { var location = self.getLinkPath(link); @@ -336,8 +327,10 @@ Navigo.prototype = { } }); }, - generate: function (name, data = {}) { - var result = this._routes.reduce((result, route) => { + generate: function generate(name) { + var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + var result = this._routes.reduce(function (result, route) { var key; if (route.name === name) { @@ -351,10 +344,12 @@ Navigo.prototype = { return this._useHash ? this._hash + result : result; }, - link: function (path) { + link: function link(path) { return this._getRoot() + path; }, - pause: function (status = true) { + pause: function pause() { + var status = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; + this._paused = status; if (status) { this._historyAPIUpdateMethod = 'replaceState'; @@ -362,69 +357,74 @@ Navigo.prototype = { this._historyAPIUpdateMethod = 'pushState'; } }, - resume: function () { + resume: function resume() { this.pause(false); }, - historyAPIUpdateMethod: function (value) { + historyAPIUpdateMethod: function historyAPIUpdateMethod(value) { if (typeof value === 'undefined') return this._historyAPIUpdateMethod; this._historyAPIUpdateMethod = value; return value; }, - disableIfAPINotAvailable: function () { + disableIfAPINotAvailable: function disableIfAPINotAvailable() { if (!isPushStateAvailable()) { this.destroy(); } }, - lastRouteResolved() { + lastRouteResolved: function lastRouteResolved() { return this._lastRouteResolved; }, - getLinkPath(link) { + getLinkPath: function getLinkPath(link) { return link.getAttribute('href'); }, - hooks(hooks) { - this._genericHooks = hooks; + hooks: function hooks(_hooks) { + this._genericHooks = _hooks; }, - _add: function (route, handler = null, hooks = null) { + + _add: function _add(route) { + var handler = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + var hooks = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; + if (typeof route === 'string') { route = encodeURI(route); } - if (typeof handler === 'object') { - this._routes.push({ - route, - handler: handler.uses, - name: handler.as, - hooks: hooks || handler.hooks - }); - } else { - this._routes.push({ route, handler, hooks: hooks }); - } + this._routes.push((typeof handler === 'undefined' ? 'undefined' : _typeof(handler)) === 'object' ? { + route: route, + handler: handler.uses, + name: handler.as, + hooks: hooks || handler.hooks + } : { route: route, handler: handler, hooks: hooks }); + return this._add; }, - _getRoot: function () { + _getRoot: function _getRoot() { if (this.root !== null) return this.root; this.root = root(this._cLoc().split('?')[0], this._routes); return this.root; }, - _listen: function () { + _listen: function _listen() { + var _this3 = this; + if (this._usePushState) { window.addEventListener('popstate', this._onLocationChange); } else if (isHashChangeAPIAvailable()) { window.addEventListener('hashchange', this._onLocationChange); } else { - let cached = this._cLoc(), current, check; + var cached = this._cLoc(), + current = void 0, + _check = void 0; - check = () => { - current = this._cLoc(); + _check = function check() { + current = _this3._cLoc(); if (cached !== current) { cached = current; - this.resolve(); + _this3.resolve(); } - this._listeningInterval = setTimeout(check, 200); + _this3._listeningInterval = setTimeout(_check, 200); }; - check(); + _check(); } }, - _cLoc: function () { + _cLoc: function _cLoc() { if (typeof window !== 'undefined') { if (typeof window.__NAVIGO_WINDOW_LOCATION_MOCK__ !== 'undefined') { return window.__NAVIGO_WINDOW_LOCATION_MOCK__; @@ -433,15 +433,17 @@ Navigo.prototype = { } return ''; }, - _findLinks: function () { + _findLinks: function _findLinks() { return [].slice.call(document.querySelectorAll('[data-navigo]')); }, - _onLocationChange: function () { + _onLocationChange: function _onLocationChange() { this.resolve(); }, - _callLeave() { - if (this._lastRouteResolved && this._lastRouteResolved.hooks && this._lastRouteResolved.hooks.leave) { - this._lastRouteResolved.hooks.leave(this._lastRouteResolved.params); + _callLeave: function _callLeave() { + var lastRouteResolved = this._lastRouteResolved; + + if (lastRouteResolved && lastRouteResolved.hooks && lastRouteResolved.hooks.leave) { + lastRouteResolved.hooks.leave(lastRouteResolved.params); } } }; diff --git a/src/router/routes.js b/src/router/routes.js index e02ed4a..779fa0b 100644 --- a/src/router/routes.js +++ b/src/router/routes.js @@ -5,10 +5,10 @@ const route = { component: null }, - render (props) { + render () { var router = this.router, - path = props.path, - component = props.component; + path = this.props.path, + component = this.props.component; if (!component) { this.logWarn('route component requires a component attribute to be specified'); diff --git a/src/sidebar/_component.scss b/src/sidebar/_component.scss index 7d01b29..3a0fab7 100644 --- a/src/sidebar/_component.scss +++ b/src/sidebar/_component.scss @@ -73,7 +73,7 @@ .content-wrapper { - .main-wrapper { + .content-main { width: 100%; padding: $sidebar-padding; } @@ -82,10 +82,6 @@ } -.sidebar-navbar { - background-color: $sidebar-navbar-background-color -} - // small screens @media(max-width: $sidebar-small-screen-1) { @@ -134,5 +130,9 @@ color: $sidebar-ancor-color; text-decoration: none; } + + .navbar-toggler img { + height: $sidebar-navbar-toggler-height; + } } } diff --git a/src/sidebar/_variables.scss b/src/sidebar/_variables.scss index afa5de4..41c55e2 100644 --- a/src/sidebar/_variables.scss +++ b/src/sidebar/_variables.scss @@ -6,11 +6,12 @@ $sidebar-small-screen: 992px !default; $sidebar-small-screen-1: 991px !default; $sidebar-width: 250px !default; $sidebar-brand-height: 47px !default; -$sidebar-padding: 20px 0px !default; +$sidebar-padding: 20px 30px !default; $sidebar-lg-padding: 20px 10px !default; $sidebar-icon-margin: 10px !default; $sidebar-icon-font-size: 1.3em; $sidebar-ancor-border-width: 0; +$sidebar-navbar-toggler-height: 30px !default; // Default theme $sidebar-ancor-color: #999999 !default; diff --git a/src/sidebar/group.html b/src/sidebar/group.html new file mode 100644 index 0000000..b8258c2 --- /dev/null +++ b/src/sidebar/group.html @@ -0,0 +1,14 @@ +
  • + + + + + +
  • diff --git a/src/sidebar/index.js b/src/sidebar/index.js index aaec3ea..96e6e0b 100644 --- a/src/sidebar/index.js +++ b/src/sidebar/index.js @@ -1,7 +1,19 @@ import {viewModel} from 'd3-view'; +import active from '../active/index'; +import collapse from '../collapse/index'; +import {icon} from '../icons/index'; + import tpl from './template.html'; +import groupTpl from './group.html'; + +const group = { + + render () { + return groupTpl; + } +}; // // Reusable Sidebar component // ================================ @@ -12,28 +24,29 @@ import tpl from './template.html'; // * active directive (Optional) // export default { + components: {group, icon}, + directives: {active, collapse}, + props: { id: 'sidebar', brand: 'sidebar', - classes: 'navbar-sidebar navbar sticky-top navbar-dark bg-primary', + classes: 'sticky-top navbar-dark bg-primary', brandUrl: '/', itemAttr: '' }, - model: { - primaryItems: [], - secondaryItems: [], - sidebarToggle: '', - // navbar attributes - navbarItems: [], - navbarTitle: "", - navbarTitleUrl: "/", - // collapse action - $collapse () { - var collapse = this.$event ? this.$event.currentTarget.d3Collapse : null; - if (collapse) - collapse.hide(collapse.select(this.$event.currentTarget)); - } + model() { + return { + primaryItems: [], + secondaryItems: [], + sidebarToggle: '', + // sidebar + sectionCollapse: false, // allow sections in sidebar to be collapsible + // top navbar attributes + navbarItems: [], + navbarTitle: "", + navbarTitleUrl: "/" + }; }, render (props, attrs, el) { @@ -47,7 +60,7 @@ export default { }; -function asItems (model, items) { +const asItems = (model, items) => { let item; for (let i=0; i