Replace svg sprite with fontawesome icons. Extend menu (WIP)
This commit is contained in:
parent
0fb816d074
commit
081cde4489
File diff suppressed because it is too large
Load Diff
|
@ -19,6 +19,8 @@
|
||||||
"bugs": "https://github.com/josdejong/jsoneditor/issues",
|
"bugs": "https://github.com/josdejong/jsoneditor/issues",
|
||||||
"private": false,
|
"private": false,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@fortawesome/fontawesome": "1.1.8",
|
||||||
|
"@fortawesome/fontawesome-free-solid": "5.0.13",
|
||||||
"ajv": "6.5.3",
|
"ajv": "6.5.3",
|
||||||
"brace": "0.11.1",
|
"brace": "0.11.1",
|
||||||
"javascript-natural-sort": "0.7.1",
|
"javascript-natural-sort": "0.7.1",
|
||||||
|
|
|
@ -15,6 +15,13 @@ import {
|
||||||
import { compileJSONPointer } from '../jsonPointer'
|
import { compileJSONPointer } from '../jsonPointer'
|
||||||
import { ERROR, EXPANDED, ID, SEARCH_PROPERTY, SEARCH_VALUE, SELECTION, TYPE, VALUE } from '../eson'
|
import { ERROR, EXPANDED, ID, SEARCH_PROPERTY, SEARCH_VALUE, SELECTION, TYPE, VALUE } from '../eson'
|
||||||
|
|
||||||
|
import fontawesome from '@fortawesome/fontawesome'
|
||||||
|
import faExclamationTriangle from '@fortawesome/fontawesome-free-solid/faExclamationTriangle'
|
||||||
|
import faCaretRight from '@fortawesome/fontawesome-free-solid/faCaretRight'
|
||||||
|
import faCaretDown from '@fortawesome/fontawesome-free-solid/faCaretDown'
|
||||||
|
|
||||||
|
fontawesome.library.add(faExclamationTriangle, faCaretRight, faCaretDown)
|
||||||
|
|
||||||
export default class JSONNode extends PureComponent {
|
export default class JSONNode extends PureComponent {
|
||||||
static URL_TITLE = 'Ctrl+Click or Ctrl+Enter to open url'
|
static URL_TITLE = 'Ctrl+Click or Ctrl+Enter to open url'
|
||||||
|
|
||||||
|
@ -96,12 +103,9 @@ export default class JSONNode extends PureComponent {
|
||||||
? [
|
? [
|
||||||
this.renderTag(`${jsonPropsCount} ${jsonPropsCount === 1 ? 'prop' : 'props'}`,
|
this.renderTag(`${jsonPropsCount} ${jsonPropsCount === 1 ? 'prop' : 'props'}`,
|
||||||
`Object containing ${jsonPropsCount} ${jsonPropsCount === 1 ? 'property' : 'properties'}`),
|
`Object containing ${jsonPropsCount} ${jsonPropsCount === 1 ? 'property' : 'properties'}`),
|
||||||
this.renderDelimiter('}', 'jsoneditor-delimiter-end jsoneditor-delimiter-collapsed'),
|
this.renderDelimiter('}', 'jsoneditor-delimiter-end jsoneditor-delimiter-collapsed')
|
||||||
this.renderInsertAfter()
|
|
||||||
]
|
]
|
||||||
: [
|
: null,
|
||||||
this.renderInsertBefore()
|
|
||||||
],
|
|
||||||
this.renderError(this.props.eson[ERROR])
|
this.renderError(this.props.eson[ERROR])
|
||||||
])
|
])
|
||||||
|
|
||||||
|
@ -131,8 +135,7 @@ export default class JSONNode extends PureComponent {
|
||||||
const floatingMenu = this.renderFloatingMenu('object', this.props.eson[SELECTION])
|
const floatingMenu = this.renderFloatingMenu('object', this.props.eson[SELECTION])
|
||||||
const nodeEnd = this.props.eson[EXPANDED]
|
const nodeEnd = this.props.eson[EXPANDED]
|
||||||
? h('div', {key: 'node-end', className: 'jsoneditor-node-end', 'data-area': 'empty'}, [
|
? h('div', {key: 'node-end', className: 'jsoneditor-node-end', 'data-area': 'empty'}, [
|
||||||
this.renderDelimiter('}', 'jsoneditor-delimiter-end'),
|
this.renderDelimiter('}', 'jsoneditor-delimiter-end')
|
||||||
this.renderInsertAfter()
|
|
||||||
])
|
])
|
||||||
: null
|
: null
|
||||||
|
|
||||||
|
@ -162,11 +165,8 @@ export default class JSONNode extends PureComponent {
|
||||||
this.renderTag(`${count} ${count === 1 ? 'item' : 'items'}`,
|
this.renderTag(`${count} ${count === 1 ? 'item' : 'items'}`,
|
||||||
`Array containing ${count} ${count === 1 ? 'item' : 'items'}`),
|
`Array containing ${count} ${count === 1 ? 'item' : 'items'}`),
|
||||||
this.renderDelimiter(']', 'jsoneditor-delimiter-end jsoneditor-delimiter-collapsed'),
|
this.renderDelimiter(']', 'jsoneditor-delimiter-end jsoneditor-delimiter-collapsed'),
|
||||||
this.renderInsertAfter(),
|
|
||||||
]
|
]
|
||||||
: [
|
: null,
|
||||||
this.renderInsertBefore()
|
|
||||||
],
|
|
||||||
this.renderError(this.props.eson[ERROR])
|
this.renderError(this.props.eson[ERROR])
|
||||||
])
|
])
|
||||||
|
|
||||||
|
@ -195,8 +195,7 @@ export default class JSONNode extends PureComponent {
|
||||||
const floatingMenu = this.renderFloatingMenu('array', this.props.eson[SELECTION])
|
const floatingMenu = this.renderFloatingMenu('array', this.props.eson[SELECTION])
|
||||||
const nodeEnd = this.props.eson[EXPANDED]
|
const nodeEnd = this.props.eson[EXPANDED]
|
||||||
? h('div', {key: 'node-end', className: 'jsoneditor-node-end', 'data-area': 'empty'}, [
|
? h('div', {key: 'node-end', className: 'jsoneditor-node-end', 'data-area': 'empty'}, [
|
||||||
this.renderDelimiter(']', 'jsoneditor-delimiter-end'),
|
this.renderDelimiter(']', 'jsoneditor-delimiter-end')
|
||||||
this.renderInsertAfter()
|
|
||||||
])
|
])
|
||||||
: null
|
: null
|
||||||
|
|
||||||
|
@ -219,7 +218,6 @@ export default class JSONNode extends PureComponent {
|
||||||
this.renderProperty(),
|
this.renderProperty(),
|
||||||
this.renderSeparator(),
|
this.renderSeparator(),
|
||||||
this.renderValue(this.props.eson[VALUE], this.props.eson[SEARCH_VALUE], this.props.options), // FIXME
|
this.renderValue(this.props.eson[VALUE], this.props.eson[SEARCH_VALUE], this.props.options), // FIXME
|
||||||
this.renderInsertAfter(),
|
|
||||||
this.renderError(this.props.eson[ERROR])
|
this.renderError(this.props.eson[ERROR])
|
||||||
])
|
])
|
||||||
|
|
||||||
|
@ -236,24 +234,6 @@ export default class JSONNode extends PureComponent {
|
||||||
}, [node, floatingMenu])
|
}, [node, floatingMenu])
|
||||||
}
|
}
|
||||||
|
|
||||||
renderInsertBefore () {
|
|
||||||
return h('div', {
|
|
||||||
key: 'insert',
|
|
||||||
className: 'jsoneditor-insert jsoneditor-insert-before',
|
|
||||||
title: 'Insert a new item or paste clipboard',
|
|
||||||
'data-area': 'inside'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
renderInsertAfter () {
|
|
||||||
return h('div', {
|
|
||||||
key: 'insert',
|
|
||||||
className: 'jsoneditor-insert jsoneditor-insert-after',
|
|
||||||
title: 'Insert a new item or paste clipboard after this line',
|
|
||||||
'data-area': 'after'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render contents for an empty object or array
|
* Render contents for an empty object or array
|
||||||
* @param {string} text
|
* @param {string} text
|
||||||
|
@ -398,7 +378,10 @@ export default class JSONNode extends PureComponent {
|
||||||
onFocus: this.updatePopoverDirection,
|
onFocus: this.updatePopoverDirection,
|
||||||
onMouseOver: this.updatePopoverDirection
|
onMouseOver: this.updatePopoverDirection
|
||||||
},
|
},
|
||||||
h('div', {className: 'jsoneditor-popover jsoneditor-right'}, error.message)
|
[
|
||||||
|
h('i', {className: 'fa fa-exclamation-triangle'}),
|
||||||
|
h('div', {className: 'jsoneditor-popover jsoneditor-right'}, error.message)
|
||||||
|
]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -445,7 +428,7 @@ export default class JSONNode extends PureComponent {
|
||||||
*/
|
*/
|
||||||
updatePopoverDirection = (event) => {
|
updatePopoverDirection = (event) => {
|
||||||
if (event.target.nodeName === 'BUTTON') {
|
if (event.target.nodeName === 'BUTTON') {
|
||||||
const popover = event.target.firstChild
|
const popover = event.target.lastChild
|
||||||
|
|
||||||
const directions = ['right', 'above', 'below', 'left']
|
const directions = ['right', 'above', 'below', 'left']
|
||||||
for (let i = 0; i < directions.length; i++) {
|
for (let i = 0; i < directions.length; i++) {
|
||||||
|
@ -537,16 +520,19 @@ export default class JSONNode extends PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
renderExpandButton () {
|
renderExpandButton () {
|
||||||
const className = `jsoneditor-button jsoneditor-${this.props.eson[EXPANDED] ? 'expanded' : 'collapsed'}`
|
const expanded = this.props.eson[EXPANDED]
|
||||||
|
const className = `jsoneditor-button jsoneditor-${expanded ? 'expanded' : 'collapsed'}`
|
||||||
|
|
||||||
return h('div', {key: 'expand', className: 'jsoneditor-button-container'},
|
// unique key depending on expanded state is to force the fontawesome icon to update
|
||||||
|
return h('div', {key: expanded, className: 'jsoneditor-button-container'},
|
||||||
h('button', {
|
h('button', {
|
||||||
className: className,
|
className: className,
|
||||||
onClick: this.handleExpand,
|
onClick: this.handleExpand,
|
||||||
title:
|
title:
|
||||||
'Click to expand/collapse this field. \n' +
|
'Click to expand/collapse this field. \n' +
|
||||||
'Ctrl+Click to expand/collapse including all childs.'
|
'Ctrl+Click to expand/collapse including all childs.'
|
||||||
})
|
}, h('i', {
|
||||||
|
className: expanded ? 'fa fa-caret-down' : 'fa fa-caret-right'}))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,17 @@
|
||||||
import { createElement as h, Component } from 'react'
|
import { Component, createElement as h } from 'react'
|
||||||
import Ajv from 'ajv'
|
import Ajv from 'ajv'
|
||||||
import { parseJSON } from '../utils/jsonUtils'
|
import { parseJSON } from '../utils/jsonUtils'
|
||||||
import { escapeUnicodeChars } from '../utils/stringUtils'
|
import { escapeUnicodeChars } from '../utils/stringUtils'
|
||||||
import { enrichSchemaError, limitErrors } from '../utils/schemaUtils'
|
import { enrichSchemaError, limitErrors } from '../utils/schemaUtils'
|
||||||
import { createFindKeyBinding } from '../utils/keyBindings'
|
import { createFindKeyBinding } from '../utils/keyBindings'
|
||||||
import { KEY_BINDINGS } from '../constants'
|
import { KEY_BINDINGS } from '../constants'
|
||||||
|
|
||||||
import ModeButton from './menu/ModeButton'
|
|
||||||
import { immutableJSONPatch } from '../immutableJSONPatch'
|
import { immutableJSONPatch } from '../immutableJSONPatch'
|
||||||
|
import TextModeMenu from './menu/TextModeMenu'
|
||||||
|
|
||||||
|
import fontawesome from '@fortawesome/fontawesome'
|
||||||
|
import faExclamationTriangle from '@fortawesome/fontawesome-free-solid/faExclamationTriangle'
|
||||||
|
|
||||||
|
fontawesome.library.add(faExclamationTriangle)
|
||||||
|
|
||||||
const AJV_OPTIONS = {
|
const AJV_OPTIONS = {
|
||||||
allErrors: true,
|
allErrors: true,
|
||||||
|
@ -112,37 +116,15 @@ export default class TextMode extends Component {
|
||||||
|
|
||||||
/** @protected */
|
/** @protected */
|
||||||
renderMenu () {
|
renderMenu () {
|
||||||
// TODO: move Menu into a separate Component
|
return h(TextModeMenu, {
|
||||||
return h('div', {key: 'menu', className: 'jsoneditor-menu'}, [
|
mode: this.props.mode,
|
||||||
h('button', {
|
modes: this.props.modes,
|
||||||
key: 'format',
|
onChangeMode: this.props.onChangeMode,
|
||||||
className: 'jsoneditor-format',
|
|
||||||
title: 'Format the JSON document',
|
|
||||||
onClick: this.handleFormat
|
|
||||||
}),
|
|
||||||
h('button', {
|
|
||||||
key: 'compact',
|
|
||||||
className: 'jsoneditor-compact',
|
|
||||||
title: 'Compact the JSON document',
|
|
||||||
onClick: this.handleCompact
|
|
||||||
}),
|
|
||||||
|
|
||||||
// TODO: implement a button "Repair"
|
onFormat: this.handleFormat,
|
||||||
|
onCompact: this.handleCompact,
|
||||||
h('div', {
|
onRepair: this.handleRepair
|
||||||
key: 'separator',
|
})
|
||||||
className: 'jsoneditor-vertical-menu-separator'
|
|
||||||
}),
|
|
||||||
|
|
||||||
this.props.modes && h(ModeButton, {
|
|
||||||
key: 'mode',
|
|
||||||
// TODO: simply pass all options?
|
|
||||||
modes: this.props.modes,
|
|
||||||
mode: this.props.mode,
|
|
||||||
onChangeMode: this.props.onChangeMode,
|
|
||||||
onError: this.props.onError
|
|
||||||
})
|
|
||||||
])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @protected */
|
/** @protected */
|
||||||
|
@ -188,7 +170,8 @@ export default class TextMode extends Component {
|
||||||
* @return {JSX.Element}
|
* @return {JSX.Element}
|
||||||
*/
|
*/
|
||||||
static renderSchemaError (error, index) {
|
static renderSchemaError (error, index) {
|
||||||
const icon = h('input', {type: 'button', className: 'jsoneditor-schema-error'})
|
const icon = h('button', {className: 'jsoneditor-schema-error'},
|
||||||
|
h('i', {className: 'fa fa-exclamation-triangle'}))
|
||||||
|
|
||||||
if (error && error.schema && error.schemaPath) {
|
if (error && error.schema && error.schemaPath) {
|
||||||
// this is an ajv error message
|
// this is an ajv error message
|
||||||
|
@ -301,6 +284,13 @@ export default class TextMode extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @protected */
|
||||||
|
handleRepair = () => {
|
||||||
|
// FIXME: implement repair button
|
||||||
|
console.log('handleRepair not yet implemented')
|
||||||
|
alert('sorry, not yet implemented...')
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply new text to the state, and emit an onChangeText event if there is a change
|
* Apply new text to the state, and emit an onChangeText event if there is a change
|
||||||
* @param {string} text
|
* @param {string} text
|
||||||
|
|
|
@ -30,8 +30,6 @@ import {
|
||||||
import JSONNode from './JSONNode'
|
import JSONNode from './JSONNode'
|
||||||
import JSONNodeView from './JSONNodeView'
|
import JSONNodeView from './JSONNodeView'
|
||||||
import JSONNodeForm from './JSONNodeForm'
|
import JSONNodeForm from './JSONNodeForm'
|
||||||
import ModeButton from './menu/ModeButton'
|
|
||||||
import Search from './menu/Search'
|
|
||||||
import {
|
import {
|
||||||
findBaseNode,
|
findBaseNode,
|
||||||
findNode,
|
findNode,
|
||||||
|
@ -64,6 +62,7 @@ import {
|
||||||
syncEson
|
syncEson
|
||||||
} from '../eson'
|
} from '../eson'
|
||||||
import TreeModeMenu from './menu/TreeModeMenu'
|
import TreeModeMenu from './menu/TreeModeMenu'
|
||||||
|
import Search from './menu/Search'
|
||||||
|
|
||||||
const AJV_OPTIONS = {
|
const AJV_OPTIONS = {
|
||||||
allErrors: true,
|
allErrors: true,
|
||||||
|
@ -73,6 +72,7 @@ const AJV_OPTIONS = {
|
||||||
|
|
||||||
const MAX_HISTORY_ITEMS = 1000 // maximum number of undo/redo items to be kept in memory
|
const MAX_HISTORY_ITEMS = 1000 // maximum number of undo/redo items to be kept in memory
|
||||||
const SCROLL_DURATION = 400 // milliseconds
|
const SCROLL_DURATION = 400 // milliseconds
|
||||||
|
const SEARCH_DEBOUNCE = 300 // milliseconds
|
||||||
|
|
||||||
export default class TreeMode extends PureComponent {
|
export default class TreeMode extends PureComponent {
|
||||||
id = Math.round(Math.random() * 1e5) // TODO: create a uuid here?
|
id = Math.round(Math.random() * 1e5) // TODO: create a uuid here?
|
||||||
|
@ -136,6 +136,7 @@ export default class TreeMode extends PureComponent {
|
||||||
|
|
||||||
options: {},
|
options: {},
|
||||||
|
|
||||||
|
showSearch: false,
|
||||||
searchResult: {
|
searchResult: {
|
||||||
text: '',
|
text: '',
|
||||||
matches: null,
|
matches: null,
|
||||||
|
@ -238,6 +239,8 @@ export default class TreeMode extends PureComponent {
|
||||||
}, [
|
}, [
|
||||||
this.renderMenu(),
|
this.renderMenu(),
|
||||||
|
|
||||||
|
this.renderSearch(),
|
||||||
|
|
||||||
h('div', {
|
h('div', {
|
||||||
key: 'contents',
|
key: 'contents',
|
||||||
ref: 'contents',
|
ref: 'contents',
|
||||||
|
@ -273,22 +276,30 @@ export default class TreeMode extends PureComponent {
|
||||||
modes: this.props.modes,
|
modes: this.props.modes,
|
||||||
onChangeMode: this.props.onChangeMode,
|
onChangeMode: this.props.onChangeMode,
|
||||||
|
|
||||||
onExpandAll: this.handleExpandAll,
|
|
||||||
onCollapseAll: this.handleCollapseAll,
|
|
||||||
|
|
||||||
enableHistory: this.props.history,
|
enableHistory: this.props.history,
|
||||||
canUndo: this.canUndo(),
|
canUndo: this.canUndo(),
|
||||||
canRedo: this.canRedo(),
|
canRedo: this.canRedo(),
|
||||||
onUndo: this.undo,
|
onUndo: this.undo,
|
||||||
onRedo: this.redo,
|
onRedo: this.redo,
|
||||||
|
|
||||||
enableSearch: this.props.search,
|
onToggleSearch: this.toggleSearch
|
||||||
searchResult: this.state.searchResult,
|
})
|
||||||
onSearch: this.handleSearch,
|
}
|
||||||
onSearchNext: this.handleNext,
|
|
||||||
onSearchPrevious: this.handlePrevious,
|
|
||||||
|
|
||||||
findKeyBinding: this.findKeyBinding,
|
renderSearch () {
|
||||||
|
if (!this.state.showSearch) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return h(Search, {
|
||||||
|
text: this.state.searchResult.text,
|
||||||
|
resultCount: this.state.searchResult.matches
|
||||||
|
? this.state.searchResult.matches.length : 0,
|
||||||
|
onChange: this.handleSearch,
|
||||||
|
onNext: this.handleNext,
|
||||||
|
onPrevious: this.handlePrevious,
|
||||||
|
findKeyBinding: this.props.findKeyBinding,
|
||||||
|
delay: SEARCH_DEBOUNCE
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -602,6 +613,12 @@ export default class TreeMode extends PureComponent {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toggleSearch = () => {
|
||||||
|
this.setState({
|
||||||
|
showSearch: !this.state.showSearch
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
handleSearch = (text) => {
|
handleSearch = (text) => {
|
||||||
// FIXME
|
// FIXME
|
||||||
// FIXME: also apply search when eson is changed
|
// FIXME: also apply search when eson is changed
|
||||||
|
|
|
@ -17,74 +17,6 @@ $insert-area-height: 6px;
|
||||||
line-height: normal;
|
line-height: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
.jsoneditor-menu {
|
|
||||||
width: 100%;
|
|
||||||
box-sizing: border-box;
|
|
||||||
|
|
||||||
color: white;
|
|
||||||
background-color: $theme-color;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
|
|
||||||
button {
|
|
||||||
width: 26px;
|
|
||||||
height: 26px;
|
|
||||||
margin: 2px;
|
|
||||||
padding: 0;
|
|
||||||
border-radius: 2px;
|
|
||||||
border: 1px solid transparent;
|
|
||||||
background: transparent url('img/jsoneditor-icons.svg');
|
|
||||||
color: white;
|
|
||||||
opacity: 0.8;
|
|
||||||
|
|
||||||
font-family: arial, sans-serif;
|
|
||||||
font-size: 10pt;
|
|
||||||
}
|
|
||||||
|
|
||||||
button:hover {
|
|
||||||
background-color: rgba(255,255,255,0.2);
|
|
||||||
border: 1px solid rgba(255,255,255,0.4);
|
|
||||||
}
|
|
||||||
button:focus,
|
|
||||||
button:active {
|
|
||||||
background-color: rgba(255,255,255,0.3);
|
|
||||||
}
|
|
||||||
button:disabled {
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.jsoneditor-vertical-menu-separator {
|
|
||||||
width: 8px;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
button.jsoneditor-expand-all {
|
|
||||||
background-position: 0 -120px;
|
|
||||||
}
|
|
||||||
button.jsoneditor-collapse-all {
|
|
||||||
background-position: 0 -96px;
|
|
||||||
}
|
|
||||||
|
|
||||||
button.jsoneditor-undo {
|
|
||||||
background-position: -24px -96px;
|
|
||||||
}
|
|
||||||
button.jsoneditor-undo:disabled {
|
|
||||||
background-position: -24px -120px;
|
|
||||||
}
|
|
||||||
button.jsoneditor-redo {
|
|
||||||
background-position: -48px -96px;
|
|
||||||
}
|
|
||||||
button.jsoneditor-redo:disabled {
|
|
||||||
background-position: -48px -120px;
|
|
||||||
}
|
|
||||||
|
|
||||||
button.jsoneditor-compact {
|
|
||||||
background-position: -72px -96px;
|
|
||||||
}
|
|
||||||
button.jsoneditor-format {
|
|
||||||
background-position: -72px -120px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.jsoneditor-contents {
|
.jsoneditor-contents {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -337,7 +269,9 @@ button.jsoneditor-button {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
border: none;
|
border: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
background: transparent url('img/jsoneditor-icons.svg');
|
background: transparent;
|
||||||
|
color: $gray-icon;
|
||||||
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
button.jsoneditor-button:focus {
|
button.jsoneditor-button:focus {
|
||||||
|
@ -349,31 +283,6 @@ button.jsoneditor-button:focus {
|
||||||
outline: #e5e5e5 solid 1px;
|
outline: #e5e5e5 solid 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: change icons from size 24x24 to 20x20 */
|
|
||||||
|
|
||||||
button.jsoneditor-button.jsoneditor-collapsed {
|
|
||||||
background-position: -2px -50px;
|
|
||||||
}
|
|
||||||
|
|
||||||
button.jsoneditor-button.jsoneditor-expanded {
|
|
||||||
background-position: -2px -74px;
|
|
||||||
}
|
|
||||||
|
|
||||||
button.jsoneditor-button.jsoneditor-drag {
|
|
||||||
background-position: -74px -74px;
|
|
||||||
cursor: move;
|
|
||||||
}
|
|
||||||
|
|
||||||
button.jsoneditor-button.jsoneditor-actionmenu {
|
|
||||||
background-position: -50px -74px;
|
|
||||||
}
|
|
||||||
|
|
||||||
button.jsoneditor-button.jsoneditor-actionmenu:hover,
|
|
||||||
button.jsoneditor-button.jsoneditor-actionmenu:focus,
|
|
||||||
button.jsoneditor-button.jsoneditor-actionmenu.jsoneditor-visible {
|
|
||||||
background-position: -50px -50px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*********************************** Menu *************************************/
|
/*********************************** Menu *************************************/
|
||||||
|
|
||||||
div.jsoneditor-menu-panel-right {
|
div.jsoneditor-menu-panel-right {
|
||||||
|
@ -445,159 +354,6 @@ button.jsoneditor-menu-button.jsoneditor-selected {
|
||||||
button.jsoneditor-menu-default {
|
button.jsoneditor-menu-default {
|
||||||
width: 104px; /* 136px - 32px */
|
width: 104px; /* 136px - 32px */
|
||||||
}
|
}
|
||||||
//
|
|
||||||
//button.jsoneditor-menu-expand {
|
|
||||||
// width: 32px;
|
|
||||||
// float: right;
|
|
||||||
// border-left: 1px solid #e5e5e5;
|
|
||||||
//}
|
|
||||||
|
|
||||||
//span.jsoneditor-icon {
|
|
||||||
// float: left;
|
|
||||||
// width: 24px;
|
|
||||||
// height: 24px;
|
|
||||||
// border: none;
|
|
||||||
// padding: 0;
|
|
||||||
// margin: 0;
|
|
||||||
// background-image: url('img/jsoneditor-icons.svg');
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//span.jsoneditor-icon.jsoneditor-icon-expand {
|
|
||||||
// float: right;
|
|
||||||
// width: 24px;
|
|
||||||
// margin: 0 4px;
|
|
||||||
//
|
|
||||||
// background-position: 0 -72px !important;
|
|
||||||
// opacity: 0.4;
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//div.jsoneditor-menu-item button.jsoneditor-menu-button:hover span.jsoneditor-icon-expand,
|
|
||||||
//div.jsoneditor-menu-item button:focus span.jsoneditor-icon-expand {
|
|
||||||
// opacity: 1;
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//span.jsoneditor-text {
|
|
||||||
// display: inline-block;
|
|
||||||
// line-height: 24px;
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//div.jsoneditor-menu-separator {
|
|
||||||
// height: 0;
|
|
||||||
// border-top: 1px solid #e5e5e5;
|
|
||||||
// padding-top: 5px;
|
|
||||||
// margin-top: 5px;
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//button.jsoneditor-remove span.jsoneditor-icon {
|
|
||||||
// background-position: -24px -24px;
|
|
||||||
//}
|
|
||||||
//button.jsoneditor-remove:hover span.jsoneditor-icon,
|
|
||||||
//button.jsoneditor-remove:focus span.jsoneditor-icon {
|
|
||||||
// background-position: -24px 0;
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//button.jsoneditor-insert span.jsoneditor-icon {
|
|
||||||
// background-position: 0 -24px;
|
|
||||||
//}
|
|
||||||
//button.jsoneditor-insert:hover span.jsoneditor-icon,
|
|
||||||
//button.jsoneditor-insert:focus span.jsoneditor-icon {
|
|
||||||
// background-position: 0 0;
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//button.jsoneditor-duplicate span.jsoneditor-icon {
|
|
||||||
// background-position: -48px -24px;
|
|
||||||
//}
|
|
||||||
//button.jsoneditor-duplicate:hover span.jsoneditor-icon,
|
|
||||||
//button.jsoneditor-duplicate:focus span.jsoneditor-icon {
|
|
||||||
// background-position: -48px 0;
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//button.jsoneditor-sort-asc span.jsoneditor-icon {
|
|
||||||
// background-position: -168px -24px;
|
|
||||||
//}
|
|
||||||
//button.jsoneditor-sort-asc:hover span.jsoneditor-icon,
|
|
||||||
//button.jsoneditor-sort-asc:focus span.jsoneditor-icon {
|
|
||||||
// background-position: -168px 0;
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//button.jsoneditor-sort-desc span.jsoneditor-icon {
|
|
||||||
// background-position: -192px -24px;
|
|
||||||
//}
|
|
||||||
//button.jsoneditor-sort-desc:hover span.jsoneditor-icon,
|
|
||||||
//button.jsoneditor-sort-desc:focus span.jsoneditor-icon {
|
|
||||||
// background-position: -192px 0;
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//div.jsoneditor-submenu {
|
|
||||||
// visibility: hidden;
|
|
||||||
// max-height: 0;
|
|
||||||
//
|
|
||||||
// overflow: hidden;
|
|
||||||
//
|
|
||||||
// transition: max-height 0.3s ease-out;
|
|
||||||
//
|
|
||||||
// box-shadow: inset 0 10px 10px -10px rgba(128, 128, 128, 0.5),
|
|
||||||
// inset 0 -10px 10px -10px rgba(128, 128, 128, 0.5)
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//div.jsoneditor-submenu.jsoneditor-expanded {
|
|
||||||
// visibility: visible;
|
|
||||||
// max-height: 104px; /* 4 * 24px + 2 * 5px */
|
|
||||||
// /* FIXME: shouldn't rely on max-height equal to 4 items, should be flexible */
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//div.jsoneditor-submenu.jsoneditor-collapsing {
|
|
||||||
// visibility: visible;
|
|
||||||
// max-height: 0;
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//div.jsoneditor-submenu button {
|
|
||||||
// padding-left: 24px;
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//div.jsoneditor-submenu div.jsoneditor-menu-item:first-child {
|
|
||||||
// margin-top: 5px;
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//div.jsoneditor-submenu div.jsoneditor-menu-item:last-child {
|
|
||||||
// margin-bottom: 5px;
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//button.jsoneditor-type-string span.jsoneditor-icon {
|
|
||||||
// background-position: -144px -24px;
|
|
||||||
//}
|
|
||||||
//button.jsoneditor-type-string:hover span.jsoneditor-icon,
|
|
||||||
//button.jsoneditor-type-string:focus span.jsoneditor-icon,
|
|
||||||
//button.jsoneditor-type-string.jsoneditor-selected span.jsoneditor-icon {
|
|
||||||
// background-position: -144px 0;
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//button.jsoneditor-type-value span.jsoneditor-icon {
|
|
||||||
// background-position: -120px -24px;
|
|
||||||
//}
|
|
||||||
//button.jsoneditor-type-value:hover span.jsoneditor-icon,
|
|
||||||
//button.jsoneditor-type-value:focus span.jsoneditor-icon,
|
|
||||||
//button.jsoneditor-type-value.jsoneditor-selected span.jsoneditor-icon {
|
|
||||||
// background-position: -120px 0;
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//button.jsoneditor-type-Object span.jsoneditor-icon {
|
|
||||||
// background-position: -72px -24px;
|
|
||||||
//}
|
|
||||||
//button.jsoneditor-type-Object:hover span.jsoneditor-icon,
|
|
||||||
//button.jsoneditor-type-Object:focus span.jsoneditor-icon,
|
|
||||||
//button.jsoneditor-type-Object.jsoneditor-selected span.jsoneditor-icon {
|
|
||||||
// background-position: -72px 0;
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//button.jsoneditor-type-Array span.jsoneditor-icon {
|
|
||||||
// background-position: -96px -24px;
|
|
||||||
//}
|
|
||||||
//button.jsoneditor-type-Array:hover span.jsoneditor-icon,
|
|
||||||
//button.jsoneditor-type-Array:focus span.jsoneditor-icon,
|
|
||||||
//button.jsoneditor-type-Array.jsoneditor-selected span.jsoneditor-icon {
|
|
||||||
// background-position: -96px 0;
|
|
||||||
//}
|
|
||||||
|
|
||||||
/******************************* Floating Menu **********************************/
|
/******************************* Floating Menu **********************************/
|
||||||
|
|
||||||
|
@ -665,39 +421,6 @@ div.jsoneditor-node-container {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
div.jsoneditor-insert {
|
|
||||||
width: $line-height;
|
|
||||||
height: $line-height;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: url('img/jsoneditor-icons.svg') -2px -26px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.jsoneditor-selected-insert-after {
|
|
||||||
border-bottom: 1px dashed $light-gray;
|
|
||||||
margin-bottom: -1px;
|
|
||||||
|
|
||||||
> .jsoneditor-node > .jsoneditor-insert-after,
|
|
||||||
> .jsoneditor-node-end > .jsoneditor-insert-after {
|
|
||||||
background-image: url('img/jsoneditor-icons.svg');
|
|
||||||
background-position: -2px -2px !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.jsoneditor-selected-insert-before {
|
|
||||||
> .jsoneditor-node > .jsoneditor-insert-before,
|
|
||||||
> .jsoneditor-node-end > .jsoneditor-insert-before {
|
|
||||||
background-image: url('img/jsoneditor-icons.svg');
|
|
||||||
background-position: -2px -2px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .jsoneditor-list {
|
|
||||||
border-top: 1px dashed $light-gray;
|
|
||||||
margin-top: -1px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.jsoneditor-hover {
|
&.jsoneditor-hover {
|
||||||
> .jsoneditor-node > .jsoneditor-button-container,
|
> .jsoneditor-node > .jsoneditor-button-container,
|
||||||
> .jsoneditor-node > .jsoneditor-button-placeholder {
|
> .jsoneditor-node > .jsoneditor-button-placeholder {
|
||||||
|
@ -712,10 +435,8 @@ div.jsoneditor-node-container {
|
||||||
//padding-left: $line-height + $input-padding + 2px;
|
//padding-left: $line-height + $input-padding + 2px;
|
||||||
border-left-color: $hoverColor;
|
border-left-color: $hoverColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
div.jsoneditor-floating-menu {
|
div.jsoneditor-floating-menu {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 100%;
|
bottom: 100%;
|
||||||
|
@ -782,15 +503,16 @@ div.jsoneditor-node-container {
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************* **********************************/
|
/******************************* **********************************/
|
||||||
|
|
||||||
div.jsoneditor-modes {
|
div.jsoneditor-modes {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
vertical-align: top;
|
|
||||||
|
|
||||||
button {
|
button {
|
||||||
background: none;
|
background: none;
|
||||||
width: auto;
|
width: auto;
|
||||||
padding: 2px 6px;
|
padding: 2px 6px;
|
||||||
|
font-size: $fontSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
button.jsoneditor-type-modes {
|
button.jsoneditor-type-modes {
|
||||||
|
@ -855,7 +577,7 @@ div.jsoneditor-code {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.jsoneditor-schema-error {
|
button.jsoneditor-schema-error {
|
||||||
//user-select: none;
|
//user-select: none;
|
||||||
outline: none;
|
outline: none;
|
||||||
border: none;
|
border: none;
|
||||||
|
@ -863,6 +585,7 @@ div.jsoneditor-code {
|
||||||
height: 20px;
|
height: 20px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0 4px;
|
margin: 0 4px;
|
||||||
background: url('img/jsoneditor-icons.svg') -171px -49px;
|
background: transparent;
|
||||||
|
color: $warning-color;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
@import '../style.scss';
|
||||||
|
@import './MenuButton.scss';
|
||||||
|
|
||||||
|
.jsoneditor-menu {
|
||||||
|
// TODO: there is also css for this menu in jsoneditor.scss, move this here
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
color: white;
|
||||||
|
background-color: $theme-color;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
|
||||||
|
.jsoneditor-menu-group {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
|
||||||
|
.jsoneditor-menu {
|
||||||
|
|
||||||
|
.jsoneditor-menu-group:not(:first-child) {
|
||||||
|
border-left: 1px solid rgba(255,255,255, 0.1);
|
||||||
|
margin-left: 5px;
|
||||||
|
padding-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
width: 26px;
|
||||||
|
height: 26px;
|
||||||
|
margin: 2px;
|
||||||
|
padding: 0;
|
||||||
|
border-radius: 2px;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
background: transparent;
|
||||||
|
color: white;
|
||||||
|
opacity: 0.8;
|
||||||
|
|
||||||
|
font-family: arial, sans-serif;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
background-color: rgba(255,255,255,0.2);
|
||||||
|
border: 1px solid rgba(255,255,255,0.4);
|
||||||
|
}
|
||||||
|
button:focus,
|
||||||
|
button:active {
|
||||||
|
background-color: rgba(255,255,255,0.3);
|
||||||
|
}
|
||||||
|
button:disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,8 +3,17 @@ import PropTypes from 'prop-types'
|
||||||
import { keyComboFromEvent } from '../../utils/keyBindings'
|
import { keyComboFromEvent } from '../../utils/keyBindings'
|
||||||
import { findEditorContainer, setSelection } from '../utils/domSelector'
|
import { findEditorContainer, setSelection } from '../utils/domSelector'
|
||||||
|
|
||||||
|
import fontawesome from '@fortawesome/fontawesome'
|
||||||
|
import faSearch from '@fortawesome/fontawesome-free-solid/faSearch'
|
||||||
|
import faCaretUp from '@fortawesome/fontawesome-free-solid/faCaretUp'
|
||||||
|
import faCaretDown from '@fortawesome/fontawesome-free-solid/faCaretDown'
|
||||||
|
|
||||||
|
import './Menu.css'
|
||||||
|
|
||||||
import './Search.css'
|
import './Search.css'
|
||||||
|
|
||||||
|
fontawesome.library.add(faSearch, faCaretUp, faCaretDown)
|
||||||
|
|
||||||
export default class Search extends Component {
|
export default class Search extends Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
super (props)
|
super (props)
|
||||||
|
@ -16,12 +25,14 @@ export default class Search extends Component {
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
return h('div', {className: 'jsoneditor-search'}, [
|
return h('div', {className: 'jsoneditor-search'}, [
|
||||||
this.renderResultsCount(this.props.resultCount),
|
|
||||||
h('form', {
|
h('form', {
|
||||||
key: 'box',
|
key: 'box',
|
||||||
className: 'jsoneditor-search-box',
|
className: 'jsoneditor-search-box',
|
||||||
onSubmit: this.handleSubmit
|
onSubmit: this.handleSubmit
|
||||||
}, [
|
}, [
|
||||||
|
h('div', { className: 'jsoneditor-search-icon' }, [
|
||||||
|
h('i', {className: 'fa fa-search'})
|
||||||
|
]),
|
||||||
h('input', {
|
h('input', {
|
||||||
key: 'input',
|
key: 'input',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
|
@ -30,21 +41,22 @@ export default class Search extends Component {
|
||||||
onInput: this.handleChange,
|
onInput: this.handleChange,
|
||||||
onKeyDown: this.handleKeyDown
|
onKeyDown: this.handleKeyDown
|
||||||
}),
|
}),
|
||||||
h('input', {
|
h('button', {
|
||||||
key: 'next',
|
key: 'next',
|
||||||
type: 'button',
|
type: 'button',
|
||||||
className: 'jsoneditor-search-next',
|
className: 'jsoneditor-search-next',
|
||||||
title: 'Next result',
|
title: 'Next result',
|
||||||
onClick: this.props.onNext
|
onClick: this.props.onNext
|
||||||
}),
|
}, h('i', {className: 'fa fa-caret-down'})),
|
||||||
h('input', {
|
h('button', {
|
||||||
key: 'previous',
|
key: 'previous',
|
||||||
type: 'button',
|
type: 'button',
|
||||||
className: 'jsoneditor-search-previous',
|
className: 'jsoneditor-search-previous',
|
||||||
title: 'Previous result',
|
title: 'Previous result',
|
||||||
onClick: this.props.onPrevious
|
onClick: this.props.onPrevious
|
||||||
})
|
}, h('i', {className: 'fa fa-caret-up'}))
|
||||||
])
|
]),
|
||||||
|
this.renderResultsCount(this.props.resultCount)
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,13 +66,13 @@ export default class Search extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resultCount === 0) {
|
if (resultCount === 0) {
|
||||||
return h('div', {key: 'count', className: 'jsoneditor-results'}, '(no results)')
|
return h('div', {key: 'count', className: 'jsoneditor-search-results'}, '(no results)')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resultCount > 0) {
|
if (resultCount > 0) {
|
||||||
const suffix = resultCount === 1 ? ' result' : ' results'
|
const suffix = resultCount === 1 ? ' result' : ' results'
|
||||||
|
|
||||||
return h('div', {key: 'count', className: 'jsoneditor-results'}, resultCount + suffix)
|
return h('div', {key: 'count', className: 'jsoneditor-search-results'}, resultCount + suffix)
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
return null
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
|
@import '../style.scss';
|
||||||
|
|
||||||
$theme-color: #3883fa;
|
$theme-color: #3883fa;
|
||||||
|
|
||||||
div.jsoneditor-search {
|
div.jsoneditor-search {
|
||||||
font-family: arial, sans-serif;
|
position: relative;
|
||||||
font-size: 10pt;
|
background: $theme-color;
|
||||||
|
font-family: $fontFamilyMenu;
|
||||||
div.jsoneditor-results {
|
font-size: $fontSize;
|
||||||
display: inline-block;
|
|
||||||
margin-right: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
form.jsoneditor-search-box {
|
form.jsoneditor-search-box {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
|
@ -15,18 +14,22 @@ div.jsoneditor-search {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
|
|
||||||
background-color: white;
|
background-color: white;
|
||||||
border: 2px solid $theme-color;
|
border: 1px solid $theme-color;
|
||||||
|
border-left-width: 0;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|
||||||
$search-icon-width: 22px;
|
$search-icon-width: 28px;
|
||||||
|
$search-icon-padding: 4px;
|
||||||
|
|
||||||
&::before {
|
div.jsoneditor-search-icon {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
display: inline-block;
|
|
||||||
width: $search-icon-width;
|
width: $search-icon-width;
|
||||||
height: 100%;
|
height: $search-icon-width;
|
||||||
background: transparent url('../img/jsoneditor-icons.svg') -97px -71px;
|
color: $light-gray;
|
||||||
content: '';
|
font-size: 16px;
|
||||||
|
padding: $search-icon-padding;
|
||||||
|
line-height: $search-icon-width - 2 * $search-icon-padding;
|
||||||
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
input.jsoneditor-search-text {
|
input.jsoneditor-search-text {
|
||||||
|
@ -43,42 +46,28 @@ div.jsoneditor-search {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type=button] {
|
button {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
width: 16px;
|
width: 16px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
line-height: 22px;
|
line-height: 28px;
|
||||||
margin: 2px 0;
|
background: transparent;
|
||||||
padding: 0;
|
|
||||||
border: none;
|
border: none;
|
||||||
background: transparent url('../img/jsoneditor-icons.svg');
|
outline: none;
|
||||||
opacity: 0.8;
|
color: $light-gray;
|
||||||
|
|
||||||
font-family: arial, sans-serif;
|
font-family: arial, sans-serif;
|
||||||
font-size: 10pt;
|
font-size: 16px;
|
||||||
}
|
padding: 0;
|
||||||
|
|
||||||
input[type=button]:hover {
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
input.jsoneditor-search-next {
|
|
||||||
cursor: pointer;
|
|
||||||
background-position: -124px -73px;
|
|
||||||
}
|
|
||||||
input.jsoneditor-search-next:hover {
|
|
||||||
background-position: -124px -49px;
|
|
||||||
}
|
|
||||||
|
|
||||||
input.jsoneditor-search-previous {
|
|
||||||
cursor: pointer;
|
|
||||||
background-position: -148px -73px;
|
|
||||||
margin-right: 2px;
|
|
||||||
}
|
|
||||||
input.jsoneditor-search-previous:hover {
|
|
||||||
background-position: -148px -49px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.jsoneditor-search-results {
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: 5px;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
import { createElement as h, PureComponent } from 'react'
|
||||||
|
import ModeButton from './ModeButton'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
|
||||||
|
import fontawesome from '@fortawesome/fontawesome'
|
||||||
|
import faAlignLeft from '@fortawesome/fontawesome-free-solid/faAlignLeft'
|
||||||
|
import faAlignJustify from '@fortawesome/fontawesome-free-solid/faAlignJustify'
|
||||||
|
import faScrewdriver from '@fortawesome/fontawesome-free-solid/faScrewdriver'
|
||||||
|
|
||||||
|
import './Menu.css'
|
||||||
|
|
||||||
|
fontawesome.library.add(faAlignLeft, faAlignJustify, faScrewdriver)
|
||||||
|
|
||||||
|
export default class TreeModeMenu extends PureComponent {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
mode: PropTypes.string.isRequired,
|
||||||
|
modes: PropTypes.arrayOf(PropTypes.string),
|
||||||
|
onChangeMode: PropTypes.func.isRequired,
|
||||||
|
|
||||||
|
onFormat: PropTypes.func.isRequired,
|
||||||
|
onCompact: PropTypes.func.isRequired,
|
||||||
|
onRepair: PropTypes.func.isRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
let items = []
|
||||||
|
|
||||||
|
// mode
|
||||||
|
if (this.props.modes ) {
|
||||||
|
items = items.concat([
|
||||||
|
h('div', {className: 'jsoneditor-menu-group'}, [
|
||||||
|
h(ModeButton, {
|
||||||
|
key: 'mode',
|
||||||
|
modes: this.props.modes,
|
||||||
|
mode: this.props.mode,
|
||||||
|
onChangeMode: this.props.onChangeMode,
|
||||||
|
onError: this.props.onError
|
||||||
|
})
|
||||||
|
])
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
// format / compact / repair
|
||||||
|
items = items.concat([
|
||||||
|
h('button', {
|
||||||
|
key: 'format',
|
||||||
|
className: 'jsoneditor-format',
|
||||||
|
title: 'Format the JSON document',
|
||||||
|
onClick: this.props.onFormat
|
||||||
|
}, h('i', {className: 'fa fa-align-left'})),
|
||||||
|
h('button', {
|
||||||
|
key: 'compact',
|
||||||
|
className: 'jsoneditor-compact',
|
||||||
|
title: 'Compact the JSON document',
|
||||||
|
onClick: this.props.onCompact
|
||||||
|
}, h('i', {className: 'fa fa-align-justify'})),
|
||||||
|
h('button', {
|
||||||
|
key: 'repair',
|
||||||
|
className: 'jsoneditor-repair',
|
||||||
|
title: 'Repair the JSON document',
|
||||||
|
onClick: this.props.onRepair
|
||||||
|
}, h('i', {className: 'fa fa-screwdriver'})),
|
||||||
|
])
|
||||||
|
|
||||||
|
return h('div', {key: 'menu', className: 'jsoneditor-menu'}, items)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,31 @@
|
||||||
import { createElement as h, PureComponent } from 'react'
|
import { createElement as h, PureComponent } from 'react'
|
||||||
import ModeButton from './ModeButton'
|
import ModeButton from './ModeButton'
|
||||||
import Search from './Search'
|
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
|
|
||||||
const SEARCH_DEBOUNCE = 300 // milliseconds
|
import fontawesome from '@fortawesome/fontawesome'
|
||||||
|
import faPlusSquare from '@fortawesome/fontawesome-free-solid/faPlusSquare'
|
||||||
|
import faMinusSquare from '@fortawesome/fontawesome-free-solid/faMinusSquare'
|
||||||
|
import faCut from '@fortawesome/fontawesome-free-solid/faCut'
|
||||||
|
import faCopy from '@fortawesome/fontawesome-free-solid/faCopy'
|
||||||
|
import faPaste from '@fortawesome/fontawesome-free-solid/faPaste'
|
||||||
|
import faPlus from '@fortawesome/fontawesome-free-solid/faPlus'
|
||||||
|
import faClone from '@fortawesome/fontawesome-free-solid/faClone'
|
||||||
|
import faTimes from '@fortawesome/fontawesome-free-solid/faTimes'
|
||||||
|
import faUndo from '@fortawesome/fontawesome-free-solid/faUndo'
|
||||||
|
import faRedo from '@fortawesome/fontawesome-free-solid/faRedo'
|
||||||
|
import faSortAmountDown from '@fortawesome/fontawesome-free-solid/faSortAmountDown'
|
||||||
|
import faFilter from '@fortawesome/fontawesome-free-solid/faFilter'
|
||||||
|
import faSearch from '@fortawesome/fontawesome-free-solid/faSearch'
|
||||||
|
|
||||||
|
import './Menu.css'
|
||||||
|
|
||||||
|
fontawesome.library.add(
|
||||||
|
faPlusSquare, faMinusSquare,
|
||||||
|
faCut, faCopy, faPaste,
|
||||||
|
faPlus, faClone, faTimes,
|
||||||
|
faUndo, faRedo,
|
||||||
|
faSortAmountDown, faFilter, faSearch
|
||||||
|
)
|
||||||
|
|
||||||
export default class TreeModeMenu extends PureComponent {
|
export default class TreeModeMenu extends PureComponent {
|
||||||
|
|
||||||
|
@ -12,8 +34,12 @@ export default class TreeModeMenu extends PureComponent {
|
||||||
modes: PropTypes.arrayOf(PropTypes.string),
|
modes: PropTypes.arrayOf(PropTypes.string),
|
||||||
onChangeMode: PropTypes.func.isRequired,
|
onChangeMode: PropTypes.func.isRequired,
|
||||||
|
|
||||||
onExpandAll: PropTypes.func.isRequired,
|
canCut: PropTypes.bool.isRequired,
|
||||||
onCollapseAll: PropTypes.func.isRequired,
|
canCopy: PropTypes.bool.isRequired,
|
||||||
|
canPaste: PropTypes.bool.isRequired,
|
||||||
|
onCut: PropTypes.func.isRequired,
|
||||||
|
onCopy: PropTypes.func.isRequired,
|
||||||
|
onPaste: PropTypes.func.isRequired,
|
||||||
|
|
||||||
enableHistory: PropTypes.bool,
|
enableHistory: PropTypes.bool,
|
||||||
canUndo: PropTypes.bool,
|
canUndo: PropTypes.bool,
|
||||||
|
@ -21,80 +47,124 @@ export default class TreeModeMenu extends PureComponent {
|
||||||
onUndo: PropTypes.func,
|
onUndo: PropTypes.func,
|
||||||
onRedo: PropTypes.func,
|
onRedo: PropTypes.func,
|
||||||
|
|
||||||
enableSearch: PropTypes.bool,
|
onToggleSearch: PropTypes.func
|
||||||
searchResult: PropTypes.string,
|
|
||||||
onSearch: PropTypes.func,
|
|
||||||
onSearchNext: PropTypes.func,
|
|
||||||
onSearchPrevious: PropTypes.func,
|
|
||||||
|
|
||||||
findKeyBinding: PropTypes.func.isRequired,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
let items = [
|
let items = []
|
||||||
h('button', {
|
|
||||||
key: 'expand-all',
|
|
||||||
className: 'jsoneditor-expand-all',
|
|
||||||
title: 'Expand all objects and arrays',
|
|
||||||
onClick: this.props.onExpandAll
|
|
||||||
}),
|
|
||||||
h('button', {
|
|
||||||
key: 'collapse-all',
|
|
||||||
className: 'jsoneditor-collapse-all',
|
|
||||||
title: 'Collapse all objects and arrays',
|
|
||||||
onClick: this.props.onCollapseAll
|
|
||||||
})
|
|
||||||
]
|
|
||||||
|
|
||||||
if (this.props.mode !== 'view' && this.props.enableHistory !== false) {
|
|
||||||
items = items.concat([
|
|
||||||
h('div', {key: 'history-separator', className: 'jsoneditor-vertical-menu-separator'}),
|
|
||||||
|
|
||||||
h('button', {
|
|
||||||
key: 'undo',
|
|
||||||
className: 'jsoneditor-undo',
|
|
||||||
title: 'Undo last action',
|
|
||||||
disabled: !this.props.canUndo,
|
|
||||||
onClick: this.props.onUndo
|
|
||||||
}),
|
|
||||||
h('button', {
|
|
||||||
key: 'redo',
|
|
||||||
className: 'jsoneditor-redo',
|
|
||||||
title: 'Redo',
|
|
||||||
disabled: !this.props.canRedo,
|
|
||||||
onClick: this.props.onRedo
|
|
||||||
})
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// mode
|
||||||
if (this.props.modes ) {
|
if (this.props.modes ) {
|
||||||
items = items.concat([
|
items = items.concat([
|
||||||
h('div', {key: 'mode-separator', className: 'jsoneditor-vertical-menu-separator'}),
|
h('div', {className: 'jsoneditor-menu-group'}, [
|
||||||
|
h(ModeButton, {
|
||||||
h(ModeButton, {
|
key: 'mode',
|
||||||
key: 'mode',
|
modes: this.props.modes,
|
||||||
modes: this.props.modes,
|
mode: this.props.mode,
|
||||||
mode: this.props.mode,
|
onChangeMode: this.props.onChangeMode,
|
||||||
onChangeMode: this.props.onChangeMode,
|
onError: this.props.onError
|
||||||
onError: this.props.onError
|
})
|
||||||
})
|
])
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.props.enableSearch !== false) {
|
// cut / copy / paste
|
||||||
// option search is true or undefined
|
items = items.concat([
|
||||||
|
h('div', {className: 'jsoneditor-menu-group'}, [
|
||||||
|
h('button', {
|
||||||
|
key: 'cut',
|
||||||
|
className: 'jsoneditor-cut',
|
||||||
|
title: 'Cut current selection',
|
||||||
|
disabled: !this.props.canCut,
|
||||||
|
onClick: this.props.onCut
|
||||||
|
}, h('i', {className: 'fa fa-cut'})),
|
||||||
|
h('button', {
|
||||||
|
key: 'copy',
|
||||||
|
className: 'jsoneditor-copy',
|
||||||
|
title: 'Copy current selection',
|
||||||
|
// disabled: !this.props.canPaste,
|
||||||
|
onClick: this.props.onPaste
|
||||||
|
}, h('i', {className: 'fa fa-copy'})),
|
||||||
|
h('button', {
|
||||||
|
key: 'paste',
|
||||||
|
className: 'jsoneditor-paste',
|
||||||
|
title: 'Paste copied selection',
|
||||||
|
// disabled: !this.props.canPaste,
|
||||||
|
onClick: this.props.onPaste
|
||||||
|
}, h('i', {className: 'fa fa-paste'}))
|
||||||
|
])
|
||||||
|
])
|
||||||
|
|
||||||
|
// TODO: [insert structure / insert value / insert array / insert object] / duplicate / remove
|
||||||
|
items = items.concat([
|
||||||
|
h('div', {className: 'jsoneditor-menu-group'}, [
|
||||||
|
h('button', {
|
||||||
|
key: 'insert',
|
||||||
|
className: 'jsoneditor-insert',
|
||||||
|
title: 'Insert new contents',
|
||||||
|
onClick: this.props.onInsert
|
||||||
|
}, h('i', {className: 'fa fa-plus'})),
|
||||||
|
h('button', {
|
||||||
|
key: 'duplicate',
|
||||||
|
className: 'jsoneditor-duplicate',
|
||||||
|
title: 'Duplicate current selection',
|
||||||
|
disabled: !this.props.canDuplicate,
|
||||||
|
onClick: this.props.onDuplicate
|
||||||
|
}, h('i', {className: 'fa fa-clone'})),
|
||||||
|
h('button', {
|
||||||
|
key: 'remove',
|
||||||
|
className: 'jsoneditor-remove',
|
||||||
|
title: 'Remove selection',
|
||||||
|
disabled: !this.props.canRemove,
|
||||||
|
onClick: this.props.onRemove
|
||||||
|
}, h('i', {className: 'fa fa-times'}))
|
||||||
|
])
|
||||||
|
])
|
||||||
|
|
||||||
|
// sort / transform
|
||||||
|
items = items.concat([
|
||||||
|
h('div', {className: 'jsoneditor-menu-group'}, [
|
||||||
|
h('button', {
|
||||||
|
key: 'sort',
|
||||||
|
className: 'jsoneditor-sort',
|
||||||
|
title: 'Sort contents',
|
||||||
|
onClick: this.props.onSort // TODO: implement onSort
|
||||||
|
}, h('i', {className: 'fa fa-sort-amount-down'})),
|
||||||
|
h('button', {
|
||||||
|
key: 'transform',
|
||||||
|
className: 'jsoneditor-transform',
|
||||||
|
title: 'Transform contents',
|
||||||
|
// disabled: !this.props.canPaste,
|
||||||
|
onClick: this.props.onTransform
|
||||||
|
}, h('i', {className: 'fa fa-filter'})),
|
||||||
|
h('button', {
|
||||||
|
key: 'search',
|
||||||
|
className: 'jsoneditor-search',
|
||||||
|
title: 'Search and replace',
|
||||||
|
onClick: this.props.onToggleSearch
|
||||||
|
}, h('i', {className: 'fa fa-search'}))
|
||||||
|
])
|
||||||
|
])
|
||||||
|
|
||||||
|
// undo / redo
|
||||||
|
if (this.props.mode !== 'view' && this.props.enableHistory !== false) {
|
||||||
items = items.concat([
|
items = items.concat([
|
||||||
h('div', {key: 'search', className: 'jsoneditor-menu-panel-right'},
|
h('div', {className: 'jsoneditor-menu-group'}, [
|
||||||
h(Search, {
|
h('button', {
|
||||||
text: this.props.searchResult.text,
|
key: 'undo',
|
||||||
resultCount: this.props.searchResult.matches ? this.props.searchResult.matches.length : 0,
|
className: 'jsoneditor-undo',
|
||||||
onChange: this.props.onSearch,
|
title: 'Undo last action',
|
||||||
onNext: this.props.onSearchNext,
|
disabled: !this.props.canUndo,
|
||||||
onPrevious: this.props.onSearchPrevious,
|
onClick: this.props.onUndo
|
||||||
findKeyBinding: this.props.findKeyBinding,
|
}, h('i', {className: 'fa fa-undo'})),
|
||||||
delay: SEARCH_DEBOUNCE
|
h('button', {
|
||||||
})
|
key: 'redo',
|
||||||
)
|
className: 'jsoneditor-redo',
|
||||||
|
title: 'Redo',
|
||||||
|
disabled: !this.props.canRedo,
|
||||||
|
onClick: this.props.onRedo
|
||||||
|
}, h('i', {className: 'fa fa-redo'}))
|
||||||
|
])
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
|
|
||||||
$fontFamily: "dejavu sans mono", "droid sans mono", consolas, monaco, "lucida console", "courier new", courier, monospace, sans-serif;
|
$fontFamily: "dejavu sans mono", "droid sans mono", consolas, monaco, "lucida console", "courier new", courier, monospace, sans-serif;
|
||||||
$fontSize: 10pt;
|
$fontSize: 10pt;
|
||||||
|
$fontFamilyMenu: arial, "sans-serif";
|
||||||
|
|
||||||
$black: #1A1A1A;
|
$black: #1A1A1A;
|
||||||
$contentsMinHeight: 150px;
|
$contentsMinHeight: 150px;
|
||||||
$theme-color: #3883fa;
|
$theme-color: #3883fa;
|
||||||
|
@ -10,6 +12,8 @@ $floating-menu-color: #fff;
|
||||||
$selectedColor: #ffed99;
|
$selectedColor: #ffed99;
|
||||||
$hoverColor: #d3d3d3;
|
$hoverColor: #d3d3d3;
|
||||||
$hoverAndSelectedColor: #ffdb80;
|
$hoverAndSelectedColor: #ffdb80;
|
||||||
|
$warning-color: #FBB917;
|
||||||
$gray: #9d9d9d;
|
$gray: #9d9d9d;
|
||||||
|
$gray-icon: #5e5e5e;
|
||||||
$light-gray: #c0c0c0;
|
$light-gray: #c0c0c0;
|
||||||
$input-padding: 5px;
|
$input-padding: 5px;
|
||||||
|
|
|
@ -158,7 +158,7 @@ export function findParentWithClassName (element, className) {
|
||||||
* @return {boolean}
|
* @return {boolean}
|
||||||
*/
|
*/
|
||||||
export function hasClassName (element, className) {
|
export function hasClassName (element, className) {
|
||||||
return element && element.className
|
return element && element.className && element.className.split
|
||||||
? element.className.split(' ').indexOf(className) !== -1
|
? element.className.split(' ').indexOf(className) !== -1
|
||||||
: false
|
: false
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue