Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Annotation persistence #112

Merged
merged 8 commits into from
Jul 4, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
"no-constant-condition": 0, // disallow use of constant expressions in conditions
"no-control-regex": 0, // disallow control characters in regular expressions
"no-debugger": 1, // disallow use of debugger
"no-dupe-keys": 1, // disallow duplicate keys when creating object literals
"no-dupe-keys": 0, // disallow duplicate keys when creating object literals
"no-empty": 1, // disallow empty statements
"no-empty-class": 0, // disallow the use of empty character classes in regular expressions
"no-ex-assign": 1, // disallow assigning to the exception in a catch block
Expand Down
40 changes: 35 additions & 5 deletions browser/js/components/Annotator/actions.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
'use strict'

import axios from 'axios'
import * as api from './apiActions'

export const SELECTION = 'SELECTION'
export const ANNOTATION = 'ANNOTATION'
export const ANNOTATION_CLEAR = 'ANNOTATION_CLEAR'
export const ANNOTATION_ADDED = 'ANNOTATION_ADDED'


export function selection(_selection){
Expand All @@ -12,12 +17,37 @@ export function selection(_selection){
}
}

export function annotation(_selection, _annotation){
export function annotation(_annotation){
let {selection, annotation, location} = _annotation;
return api.postAnnotation({selection, annotation, location})
}

export function finishAnnotation(payload){
let finisher = payload;
finisher.added = false;
return {
type: ANNOTATION,
annotation: _annotation,
selection: _selection,
selectionString: _selection.toString(),
added: false
payload: payload
}
}

export function clearAnnotation( added = false, selection = null, annotation = null ){
return {
type: ANNOTATION_CLEAR,
payload: {
added,
annotation,
selection,
selectionString: !selection ? null : selection.toString() }
}
}

export function annotationAdded( added = true, clear = false ){
if(clear) clearAnnotation( added, null, null );
return {
type: ANNOTATION_ADDED,
payload: {
added
}
}
}
148 changes: 148 additions & 0 deletions browser/js/components/Annotator/apiActions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
'use strict';

import axios from 'axios';
import APIROUTES from '../../utils/apiRoutes'
import {cloneDeep as _cloneDeep} from 'lodash';
import {getXPath} from 'xpath-dom';
import {finishAnnotation} from './actions'

export const LOAD_ANNOTATIONS_REQUEST = 'LOAD_ANNOTATIONS_REQUEST'
export const LOAD_ANNOTATIONS_SUCCESS = 'LOAD_ANNOTATIONS_SUCCESS'
export const LOAD_ANNOTATIONS_FAILURE = 'LOAD_ANNOTATIONS_FAILURE'
export const CREATE_ANNOTATION_REQUEST = 'CREATE_ANNOTATION_REQUEST'
export const CREATE_ANNOTATION_SUCCESS = 'CREATE_ANNOTATION_SUCCESS'
export const CREATE_ANNOTATION_FAILURE = 'CREATE_ANNOTATION_FAILURE'
export const LOAD_ANNOTATION_REQUEST = 'LOAD_ANNOTATION_REQUEST'
export const LOAD_ANNOTATION_SUCCESS = 'LOAD_ANNOTATION_SUCCESS'
export const LOAD_ANNOTATION_FAILURE = 'LOAD_ANNOTATION_FAILURE'
export const UPDATE_ANNOTATION_REQUEST = 'UPDATE_ANNOTATION_REQUEST'
export const UPDATE_ANNOTATION_SUCCESS = 'UPDATE_ANNOTATION_SUCCESS'
export const UPDATE_ANNOTATION_FAILURE = 'UPDATE_ANNOTATION_FAILURE'


export const getUserAnnotations =
userId =>
dispatch => {
dispatch(LOAD_ANNOTATIONS_REQUEST)
return axios.get(APIROUTES.annotationsByUserId(userId))
.then( res => res.data )
.then( resData => dispatch({
type: LOAD_ANNOTATIONS_SUCCESS,
payload: resData
}))
.catch( err => dispatch({
type: LOAD_ANNOTATIONS_FAILURE,
payload: err
})) }

export const getAnnotationById =
annotationId =>
dispatch => {
dispatch(LOAD_ANNOTATION_REQUEST)
return axios.get(APIROUTES.annotationById(annotationId))
.then( res => res.data )
.then( resData => dispatch({
type: LOAD_ANNOTATION_REQUEST,
payload: resData
}))
.catch( err => dispatch({
type: LOAD_ANNOTATION_FAILURE,
payload: err
}))}

export const getAnnotationsByUserTest =
userTestId =>
dispatch => {
dispatch(LOAD_ANNOTATIONS_REQUEST)
return axios.get(APIROUTES.annotationsByUserTest(userTestId))
.then( res => res.data )
.then( resData => dispatch({
type: LOAD_ANNOTATIONS_REQUEST,
payload: resData
}))
.catch( err => dispatch({
type: LOAD_ANNOTATIONS_FAILURE,
payload: err
}))}

export const postAnnotation =
annotation =>
(dispatch, getState) =>{
let selection = annotation.selection;
let payload = {
route: APIROUTES.annotation,
anchorNode: getXPath(selection.anchorNode),
anchorOffset: selection.anchorOffset,
focusNode: getXPath(selection.focusNode),
focusOffset: selection.focusOffset,
rangeCount: selection.rangeCount,
selectionString: selection.toString(),
color: annotation.color,
location: annotation.location
}
dispatch({
type: CREATE_ANNOTATION_REQUEST,
payload
})
return axios.post(APIROUTES.annotation, payload)
.then(res => res.data)
.then(resData => {
dispatch({
type: CREATE_ANNOTATION_SUCCESS,
payload: resData
})
payload.selection = annotation.selection;
payload.resData = resData;
return dispatch(finishAnnotation(payload))
}
)
.catch( err => dispatch({
type: CREATE_ANNOTATION_FAILURE,
payload: err
}))}


export const postAnnotationByUserTest =
(annotation, userTestId) =>
(dispath, getState) =>{
dispatch(CREATE_ANNOTATION_REQUEST)
return axios.post(APIROUTES.annotationsByUserTest(userTestId), annotation)
.then( res => res.data)
.then(resData => dispatch({
type: CREATE_ANNOTATION_SUCCESS,
payload: resData
}))
.catch( err => dispatch({
type: CREATE_ANNOTATION_FAILURE,
payloard: err
}))}

export const updateAnnotation =
(annotation, annotationId) =>
(dispatch, getState) =>{
dispatch(UPDATE_ANNOTATION_REQUEST)
return axios.put(APIROUTES.annotationById(annotationId), annotation)
.then(res => res.data)
.then(resData => dispatch({
type: UPDATE_ANNOTATION_SUCCESS,
payload: resData
}))
.catch( err => dispatch({
type: UPDATE_ANNOTATION_FAILURE,
payload: err
}))}

export const deleteAnnotation =
annotationId =>
(dispatch, getState) =>{
dispatch(DELETE_ANNOTATION_REQUEST)
return axios.delete(APIROUTES.annotationById(annotationId), annotation)
.then(res => res.data)
.then(resData => dispatch({
type: DELETE_ANNOTATION_SUCCESS,
payload: resData
}))
.catch( err => dispatch({
type: DELETE_ANNOTATION_FAILURE,
payload: err
}))}
33 changes: 28 additions & 5 deletions browser/js/components/Annotator/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import {annotation, selection} from './actions';
class AnnotationHandler extends Component{
constructor(props){
super(props);
console.log(this.props);
this.handleMouseUp = this.handleMouseUp.bind(this);
this.handleMouseDown = this.handleMouseDown.bind(this);
this.state = {
Expand Down Expand Up @@ -49,10 +48,12 @@ class AnnotationHandler extends Component{
});
}
componentWillReceiveProps(nextProps){
console.log('receiving props');
this.setState({
selectionString: nextProps.selectionString
});
this.setState({
currentLocation: nextProps.location
})
}
render (){
return (
Expand All @@ -61,7 +62,10 @@ class AnnotationHandler extends Component{
{this.props.children}
</div>
<div style={this.state.annotationStyles} >
<AnnotateContextMenu {...this.props} selection={this.state.selection}>
<AnnotateContextMenu
selection={this.state.selection}
currentLocation={this.state.currentLocation}
{...this.props} >
</AnnotateContextMenu>
</div>
</div>
Expand All @@ -74,9 +78,20 @@ export class AnnotateContextMenu extends Component {
constructor(props) {
super(props);
this.annotate = this.annotate.bind( this );
this.state = {
currentLocation: props.currentLocation
}
}
annotate( ) {
this.props.dispatch(annotation(this.props.selection));
let currentLocation = this.state.currentLocation
return this.props.dispatch(annotation({
selection: this.props.selection,
annotation: this.props.selection,
location: currentLocation
}));
}
componentWillReceiveProps(nextProps){
this.setState({currentLocation: nextProps.currentLocation})
}
render() {
return (
Expand All @@ -88,4 +103,12 @@ export class AnnotateContextMenu extends Component {
}
}

export default connect()(AnnotationHandler);
const mapStateToProps = (state, props)=>{
let nextProps = {};
// nextProps.currentLocation = state.currentFile.path;
// replace this \/ with this /\
nextProps.currentLocation = 'https://github.com/Code-Genius/checkpoint-express-review/blob/master/app.js'
return nextProps;
}

export default connect(mapStateToProps)(AnnotationHandler);
13 changes: 10 additions & 3 deletions browser/js/components/Annotator/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,17 @@ export default function annotationReducer(state = annotator_initialState, action
selectionString: action.selectionString
})
case 'ANNOTATION':
return Object.assign({}, state, action.payload, {
annotation: action.payload.annotation,
selection: action.payload.selection,
selectionString: action.payload.selectionString,
added: action.payload.added
})
case 'ANNOTATION_CLEAR':
return Object.assign({}, state, action.payload)
case 'ANNOTATION_ADDED':
return Object.assign({}, state, {
annotation: action.annotation,
selection: action.selection,
selectionString: action.selectionString
added: action.payload.added
})
default:
return state
Expand Down
Loading