mirror of
https://github.com/serratus/quaggaJS.git
synced 2026-08-13 05:31:37 +08:00
added es-lint config to sandbox
This commit is contained in:
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"root": true,
|
||||||
|
"extends": "./node_modules/eslint-config-netconomy/react.js",
|
||||||
|
"parser": "babel-eslint",
|
||||||
|
"rules": {
|
||||||
|
"comma-dangle": [2, "always-multiline"],
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,6 +11,8 @@
|
|||||||
|
|
||||||
<link rel="stylesheet" type="text/css" href="static/style.css" />
|
<link rel="stylesheet" type="text/css" href="static/style.css" />
|
||||||
<meta name="viewport" content="width=device-width; initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width; initial-scale=1.0" />
|
||||||
|
<link href='https://fonts.googleapis.com/css?family=Roboto:400,300,500' rel='stylesheet' type='text/css'>
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body style="margin: 0">
|
<body style="margin: 0">
|
||||||
|
|||||||
@@ -10,11 +10,15 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel-core": "^6.9.0",
|
"babel-core": "^6.9.0",
|
||||||
|
"babel-eslint": "^6.1.2",
|
||||||
"babel-loader": "^6.2.4",
|
"babel-loader": "^6.2.4",
|
||||||
"babel-plugin-transform-class-properties": "^6.9.0",
|
"babel-plugin-transform-class-properties": "^6.9.0",
|
||||||
"babel-preset-es2015-webpack": "^6.4.1",
|
"babel-preset-es2015-webpack": "^6.4.1",
|
||||||
"babel-preset-react": "^6.5.0",
|
"babel-preset-react": "^6.5.0",
|
||||||
"babel-preset-stage-0": "^6.5.0",
|
"babel-preset-stage-0": "^6.5.0",
|
||||||
|
"eslint": "^3.0.1",
|
||||||
|
"eslint-config-netconomy": "^300.0.0",
|
||||||
|
"eslint-plugin-react": "^5.2.2",
|
||||||
"webpack": "^2.1.0-beta.7"
|
"webpack": "^2.1.0-beta.7"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -1,33 +1,38 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import AppBar from 'material-ui/AppBar';
|
import AppBar from 'material-ui/AppBar';
|
||||||
import Drawer from 'material-ui/Drawer';
|
import Drawer from 'material-ui/Drawer';
|
||||||
import MenuItem from 'material-ui/MenuItem';
|
|
||||||
import Paper from 'material-ui/Paper';
|
|
||||||
import FloatingActionButton from 'material-ui/FloatingActionButton';
|
import FloatingActionButton from 'material-ui/FloatingActionButton';
|
||||||
import ContentAdd from 'material-ui/svg-icons/content/add';
|
|
||||||
import Dialog from 'material-ui/Dialog';
|
import Dialog from 'material-ui/Dialog';
|
||||||
import FlatButton from 'material-ui/FlatButton';
|
import FlatButton from 'material-ui/FlatButton';
|
||||||
import {Card, CardTitle, CardText} from 'material-ui/Card';
|
import {Card, CardTitle, CardText} from 'material-ui/Card';
|
||||||
|
import IconButton from 'material-ui/IconButton';
|
||||||
|
import TuneIcon from 'material-ui/svg-icons/image/tune';
|
||||||
|
|
||||||
import Scanner from './Scanner';
|
import Scanner from './Scanner';
|
||||||
import ScanIcon from './ScanIcon';
|
import ScanIcon from './ScanIcon';
|
||||||
|
import ConfigView from './ConfigView';
|
||||||
|
|
||||||
export default class App extends React.Component {
|
export default class App extends React.Component {
|
||||||
state = {
|
state = {
|
||||||
drawerOpen: false,
|
drawerOpen: false,
|
||||||
scanning: false,
|
scanning: false,
|
||||||
|
currentView: 'root',
|
||||||
scannedCodes: [{
|
scannedCodes: [{
|
||||||
codeResult: {
|
codeResult: {
|
||||||
code: "FANAVF1461710",
|
code: "FANAVF1461710",
|
||||||
format: "code_128"
|
format: "code_128",
|
||||||
},
|
},
|
||||||
timestamp: new Date()
|
timestamp: new Date(),
|
||||||
}]
|
}],
|
||||||
};
|
};
|
||||||
|
|
||||||
_handleToggle = () => this.setState({drawerOpen: !this.state.drawerOpen});
|
_handleToggle = () => {
|
||||||
|
this.setState({drawerOpen: !this.state.drawerOpen});
|
||||||
|
}
|
||||||
_handleClose = () => this.setState({drawerOpen: false});
|
_handleClose = () => this.setState({drawerOpen: false});
|
||||||
_onRequestChange = drawerOpen => this.setState({drawerOpen});
|
_onRequestChange = drawerOpen => {
|
||||||
|
this.setState({drawerOpen});
|
||||||
|
};
|
||||||
|
|
||||||
_startScanning = (e) => {
|
_startScanning = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -47,22 +52,27 @@ export default class App extends React.Component {
|
|||||||
.concat(this.state.scannedCodes)});
|
.concat(this.state.scannedCodes)});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_navigateTo = (route) => {
|
||||||
|
this.setState({
|
||||||
|
drawerOpen: false,
|
||||||
|
currentView: route,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Drawer
|
<Drawer
|
||||||
docked={false}
|
docked={false}
|
||||||
width={200}
|
|
||||||
open={this.state.drawerOpen}
|
open={this.state.drawerOpen}
|
||||||
onRequestChange={this._onRequestChange}
|
onRequestChange={this._onRequestChange}
|
||||||
>
|
>
|
||||||
<MenuItem onTouchTap={this._handleClose}>Menu Item</MenuItem>
|
<ConfigView />
|
||||||
<MenuItem onTouchTap={this._handleClose}>Menu Item 2</MenuItem>
|
|
||||||
</Drawer>
|
</Drawer>
|
||||||
<AppBar
|
<AppBar
|
||||||
style={{position: 'fixed', top: '0px'}}
|
style={{position: 'fixed', top: '0px'}}
|
||||||
title="QuaggaJS"
|
title="QuaggaJS"
|
||||||
iconClassNameRight="muidocs-icon-navigation-expand-more"
|
iconElementLeft={<IconButton onTouchTap={this._handleToggle}><TuneIcon /></IconButton>}
|
||||||
onLeftIconButtonTouchTap={this._handleToggle}
|
onLeftIconButtonTouchTap={this._handleToggle}
|
||||||
/>
|
/>
|
||||||
<FloatingActionButton
|
<FloatingActionButton
|
||||||
@@ -80,7 +90,7 @@ export default class App extends React.Component {
|
|||||||
<FlatButton
|
<FlatButton
|
||||||
label="Cancel"
|
label="Cancel"
|
||||||
primary={true}
|
primary={true}
|
||||||
onTouchTap={this._stopScanning}/>
|
onTouchTap={this._stopScanning}/>,
|
||||||
]}
|
]}
|
||||||
modal={true}
|
modal={true}
|
||||||
contentStyle={{width: '95%', maxWidth: '95%', height: '95%', maxHeight: '95%'}}
|
contentStyle={{width: '95%', maxWidth: '95%', height: '95%', maxHeight: '95%'}}
|
||||||
@@ -89,7 +99,7 @@ export default class App extends React.Component {
|
|||||||
<Scanner onDetected={this._handleResult} onCancel={this._stopScanning} />
|
<Scanner onDetected={this._handleResult} onCancel={this._stopScanning} />
|
||||||
</Dialog>
|
</Dialog>
|
||||||
<div style={{paddingTop: '64px'}}>
|
<div style={{paddingTop: '64px'}}>
|
||||||
{this.state.scannedCodes.map((scannedCode, i) => (
|
{this.state.currentView === 'root' && this.state.scannedCodes.map((scannedCode, i) => (
|
||||||
<Card key={i} style={{margin: '0.5em 0.25em 0em'}}>
|
<Card key={i} style={{margin: '0.5em 0.25em 0em'}}>
|
||||||
<CardTitle
|
<CardTitle
|
||||||
titleStyle={{textOverflow: 'ellipsis', overflow: 'hidden'}}
|
titleStyle={{textOverflow: 'ellipsis', overflow: 'hidden'}}
|
||||||
|
|||||||
@@ -0,0 +1,125 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import {List, ListItem} from 'material-ui/List';
|
||||||
|
import Subheader from 'material-ui/Subheader';
|
||||||
|
import Toggle from 'material-ui/Toggle';
|
||||||
|
import SelectField from 'material-ui/SelectField';
|
||||||
|
import MenuItem from 'material-ui/MenuItem';
|
||||||
|
|
||||||
|
function generateItems(keyValuePairs) {
|
||||||
|
return keyValuePairs.map(([value, label]) => (
|
||||||
|
<MenuItem key={value} value={value} primaryText={label} />
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
const availableReaders = [
|
||||||
|
['ean_reader', "EAN-13", true],
|
||||||
|
['ean_8_reader', "EAN-8"],
|
||||||
|
["upc_e_reader", "UPC-E"],
|
||||||
|
["code_39_reader", "CODE 39", true],
|
||||||
|
["codabar_reader", "Codabar"],
|
||||||
|
["code_128_reader", "CODE 128", true],
|
||||||
|
["i2of5_reader", "ITF", true],
|
||||||
|
];
|
||||||
|
|
||||||
|
let configOptions = {
|
||||||
|
width: [[640, "640px"], [800, "800px"], [1280, "1280px"], [1920, "1920px"]],
|
||||||
|
height: [[480, "480px"], [600, "600px"], [720, "720px"], [1080, "1080px"]],
|
||||||
|
facingMode: [["user", "user"], ["environment", "environment"]],
|
||||||
|
aspectRatio: [[1, '1/1'], [4 / 3, '4/3'], [16 / 9, '16/9'], [21 / 9, '21/9']],
|
||||||
|
deviceId: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
let items = Object.keys(configOptions).reduce((result, option) => ({
|
||||||
|
...result,
|
||||||
|
[option]: generateItems(configOptions[option]),
|
||||||
|
}), {});
|
||||||
|
|
||||||
|
const selectStyle = {
|
||||||
|
};
|
||||||
|
const selectedItemStyle = {
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
textOverflow: 'ellipsis',
|
||||||
|
overflow: 'hidden',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class ConfigView extends React.Component {
|
||||||
|
state = {
|
||||||
|
devicesFetched: false,
|
||||||
|
numOfWorkers: 2,
|
||||||
|
...Object
|
||||||
|
.keys(configOptions)
|
||||||
|
.reduce((result, option) => ({...result, [option]: (configOptions[option][0] || [null])[0]}), {}),
|
||||||
|
};
|
||||||
|
|
||||||
|
handleChange = (category, event, index, value) => {
|
||||||
|
this.setState({[category]: value});
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillMount() {
|
||||||
|
navigator.mediaDevices
|
||||||
|
.enumerateDevices()
|
||||||
|
.then((devices) => {
|
||||||
|
const videoDevices = devices
|
||||||
|
.filter(info => info.kind === 'videoinput')
|
||||||
|
.map(videoDevice => ([
|
||||||
|
videoDevice.deviceId,
|
||||||
|
videoDevice.label,
|
||||||
|
]));
|
||||||
|
configOptions = {
|
||||||
|
...configOptions,
|
||||||
|
deviceId: videoDevices,
|
||||||
|
};
|
||||||
|
items = {
|
||||||
|
...items,
|
||||||
|
deviceId: generateItems(configOptions.deviceId),
|
||||||
|
};
|
||||||
|
this.setState({devicesFetched: true});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Subheader>Constraints</Subheader>
|
||||||
|
<div style={{paddingLeft: 16, paddingRight: 16}}>
|
||||||
|
{Object.keys(items).map(option => (
|
||||||
|
<SelectField fullWidth={true} key={option} style={selectStyle}
|
||||||
|
labelStyle={selectedItemStyle}
|
||||||
|
value={this.state[option]}
|
||||||
|
onChange={this.handleChange.bind(this, option)}
|
||||||
|
floatingLabelText={option}
|
||||||
|
>
|
||||||
|
{items[option]}
|
||||||
|
</SelectField>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<List>
|
||||||
|
<Subheader>General</Subheader>
|
||||||
|
<ListItem primaryText="locate" secondaryText="Automatically detect position" rightToggle={<Toggle />} />
|
||||||
|
<div style={{paddingLeft: 16, paddingRight: 16}}>
|
||||||
|
<SelectField fullWidth={true} key={'numOfWorkers'}
|
||||||
|
style={selectStyle}
|
||||||
|
labelStyle={selectedItemStyle}
|
||||||
|
value={this.state.numOfWorkers}
|
||||||
|
onChange={this.handleChange.bind(this, 'numOfWorkers')}
|
||||||
|
floatingLabelText='numOfWorkers'
|
||||||
|
>
|
||||||
|
{[0, 1, 2, 4, 8]
|
||||||
|
.map(numOfWorkers => <MenuItem key={numOfWorkers} value={numOfWorkers} primaryText={numOfWorkers} />)
|
||||||
|
}
|
||||||
|
</SelectField>
|
||||||
|
</div>
|
||||||
|
</List>
|
||||||
|
<List>
|
||||||
|
<Subheader>Readers</Subheader>
|
||||||
|
{availableReaders.map(([reader, label, enabled]) => (
|
||||||
|
<ListItem
|
||||||
|
key={reader}
|
||||||
|
primaryText={label}
|
||||||
|
rightToggle={<Toggle defaultToggled={enabled ? enabled : false} />}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</List>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -2,6 +2,11 @@ import React from 'react';
|
|||||||
import Quagga from '../../../../dist/quagga';
|
import Quagga from '../../../../dist/quagga';
|
||||||
|
|
||||||
export default class Scanner extends React.Component {
|
export default class Scanner extends React.Component {
|
||||||
|
propTypes = {
|
||||||
|
onDetected: React.PropTypes.func,
|
||||||
|
onCancel: React.PropTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this._scanner = Quagga
|
this._scanner = Quagga
|
||||||
@@ -13,23 +18,19 @@ export default class Scanner extends React.Component {
|
|||||||
constraints: {
|
constraints: {
|
||||||
width: 800,
|
width: 800,
|
||||||
height: 600,
|
height: 600,
|
||||||
facingMode: "environment"
|
facingMode: "environment",
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
this._onCancel = this._onCancel.bind(this);
|
|
||||||
}
|
}
|
||||||
_onCancel(e) {
|
|
||||||
|
_onCancel = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (this._scanUntilResult) {
|
if (this._scanUntilResult) {
|
||||||
this._scanUntilResult.cancel();
|
this._scanUntilResult.cancel();
|
||||||
this._scanUntilResult = null;
|
this._scanUntilResult = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div className="overlay__content" />
|
|
||||||
);
|
|
||||||
}
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this._scanUntilResult = this._scanner.toPromise();
|
this._scanUntilResult = this._scanner.toPromise();
|
||||||
this._scanUntilResult.promise
|
this._scanUntilResult.promise
|
||||||
@@ -37,6 +38,12 @@ export default class Scanner extends React.Component {
|
|||||||
.catch(this.props.onCancel);
|
.catch(this.props.onCancel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className="overlay__content" />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
this._scanner
|
this._scanner
|
||||||
.removeEventListener('detected', this.props.onDetected)
|
.removeEventListener('detected', this.props.onDetected)
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
html {
|
||||||
|
font-family: 'Roboto', sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
.overlay__content {
|
.overlay__content {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user