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

Release 2 #10

Merged
merged 9 commits into from
May 4, 2018
2 changes: 2 additions & 0 deletions frontend/src/az-api/payload/payload.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export interface AzPayload {
suggesterName?: string;
autocompleteMode?: string;
scoringProfile?: string;
highlight?: string;
}

export const defaultAzPayload: AzPayload = {
Expand All @@ -43,4 +44,5 @@ export const defaultAzPayload: AzPayload = {
searchMode: "all",
top: 10,
scoringProfile: "demoBooster",
highlight: "text",
}
3 changes: 2 additions & 1 deletion frontend/src/az-api/payload/payload.parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ export const parsePayloadGET = (p: AzPayload): string => {
p.fuzzy ? `fuzzy=true` : "",
p.suggesterName ? `suggesterName=${p.suggesterName}` : "",
p.autocompleteMode ? `autocompleteMode=${p.autocompleteMode}` : "",
p.scoringProfile ? `scoringProfile=${p.scoringProfile}` : ""
p.scoringProfile ? `scoringProfile=${p.scoringProfile}` : "",
p.highlight ? `highlight=${p.highlight}` : ""
]
.filter(i => i)
.join("&");
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/az-api/response.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ export interface AzResponseConfig {
facetFromAccessor: string;
facetToAccessor: string;
valueAccessor: string;
highlightAccessor: string;
highlightTextAccessor: string;
}

export const defaultAzResponseConfig: AzResponseConfig = {
Expand All @@ -48,4 +50,6 @@ export const defaultAzResponseConfig: AzResponseConfig = {
facetFromAccessor: "from",
facetToAccessor: "to",
valueAccessor: "value",
highlightAccessor: "@search.highlights",
highlightTextAccessor: "text",
}
2 changes: 2 additions & 0 deletions frontend/src/az-api/response.parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,5 @@ export const parseResponse = async (response: Response, config: AzResponseConfig
facets: parseResponseFacetObject(jsonObject[config.facetsAccessor], config),
};
};


11 changes: 11 additions & 0 deletions frontend/src/common/components/hocr/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export const hocrAttributes = {
dataAnnotation: 'data-annotation',
};

export const hocrClasses = {
page: 'ocr_page',
area: 'ocr_carea',
paragraph: 'ocr_par',
line: 'ocr_line',
word: 'ocrx_word',
};
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export interface HocrDocumentProps {
targetWords?: string[];
caseSensitiveComparison?: boolean;
autoFocusId?: string;
hightlightId?: string;
hightlightPageIndex?: number;
userStyle?: HocrDocumentStyleMap;
onWordHover?: (wordId: string) => void;
onPageHover?: (pageIndex: number) => void;
Expand All @@ -37,6 +37,7 @@ interface HocrDocumentState {
docBody: Element;
wordCompare: WordComparator;
autoFocusNode: Element;
hightlightedPageNode: Element;
safeStyle: HocrDocumentStyleMap;
}

Expand All @@ -49,6 +50,7 @@ export class HocrDocumentComponent extends React.Component<HocrDocumentProps, Ho
wordCompare: CreateWordComparator(props.targetWords, props.caseSensitiveComparison),
safeStyle: injectDefaultDocumentStyle(props.userStyle),
autoFocusNode: null,
hightlightedPageNode: null,
}
}

Expand Down Expand Up @@ -87,11 +89,24 @@ export class HocrDocumentComponent extends React.Component<HocrDocumentProps, Ho
}
}

private hightlightPage = (pageIndex: number) => {
this.resetHighlight(this.state.hightlightedPageNode);
if (pageIndex) {
const pageNode = getNodeById(this.viewportRef, `page_${pageIndex}`);
this.setHighlight(pageNode);
this.setState({
...this.state,
hightlightedPageNode: pageNode,
});
}
}

// *** Lifecycle ***

public componentDidMount() {
if (this.props.autoFocusId) {
this.scrollTo(getNodeById(this.viewportRef, this.props.autoFocusId));
if ( this.viewportRef) {
this.props.autoFocusId && this.scrollTo(getNodeById(this.viewportRef, this.props.autoFocusId));
this.props.hightlightPageIndex && this.hightlightPage(this.props.hightlightPageIndex);
}
}

Expand All @@ -114,9 +129,14 @@ export class HocrDocumentComponent extends React.Component<HocrDocumentProps, Ho
...this.state,
safeStyle: injectDefaultDocumentStyle(nextProps.userStyle),
});
} else if (this.props.autoFocusId !== nextProps.autoFocusId) {
}

if (this.props.autoFocusId !== nextProps.autoFocusId) {
this.autoFocusToNode(nextProps.autoFocusId);
}
if (this.props.hightlightPageIndex !== nextProps.hightlightPageIndex) {
this.hightlightPage(nextProps.hightlightPageIndex);
}
}

public shouldComponentUpdate(nextProps: HocrDocumentProps, nextState: HocrDocumentState) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,17 @@
padding: 1rem;
border-radius: 0.5rem;
background-color: white;
transition: box-shadow 0.3s ease-out;

&:hover,
&.highlight {
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
}
}

.area {
padding-left: 10px;
border-left: 3px solid transparent;

&:hover {
border-left: 3px solid #39f;
}
}

.paragraph {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from "react";
import { getNodeOptions, bboxToPosSize, getNodeId, composeId, PosSize } from "../util/common-util";
import { getNodeOptions, bboxToPosSize, getNodeId, composeId, PosSize, getAnnotationMessage } from "../util/common-util";
import { RectangleProps } from "./rectangleProps";

/**
Expand Down Expand Up @@ -29,21 +29,21 @@ export const SvgRectComponent: React.StatelessComponent<SvgRectProps> = (props)
y={nodePosSize.y}
width={nodePosSize.width}
height={nodePosSize.height}
onMouseEnter={onHover(props, true, id, props.node.textContent, nodePosSize.height)}
onMouseEnter={onHover(props, true, id, getAnnotationMessage(props.node), nodePosSize.height)}
onMouseLeave={onHover(props, false, null, null)}
/>
);
};

const onHover = (props: SvgRectProps, isHover: boolean, id?: string, word?: string, height?: number) => (e) => {
const onHover = (props: SvgRectProps, isHover: boolean, id?: string, tooltipMessage?: string, height?: number) => (e) => {
const reactangle = e.target.getBoundingClientRect();
if (props.onHover) {
props.onHover({
id,
left: reactangle.left,
top: reactangle.top,
height,
word,
tooltipMessage,
isHover,
});
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as React from "react";
import { Tooltip } from "material-ui";
import { cryptonyms } from "../../../constants/cryptonyms";
import { RectangleProps } from "./rectangleProps";
import { TooltipComponent } from "../tooltip";

Expand Down Expand Up @@ -38,7 +37,7 @@ export class HocrTooltipComponent extends React.PureComponent<Props, State> {
isOpen: rectangleProps.isHover,
left: rectangleProps.left,
top: rectangleProps.top + rectangleProps.height + topOffset,
message: getTooltipMessage(rectangleProps.word),
message: rectangleProps.tooltipMessage,
});
}

Expand All @@ -55,17 +54,6 @@ export class HocrTooltipComponent extends React.PureComponent<Props, State> {
}
}

const getTooltipMessage = (word: string): string => {
const cryptonym = Object.keys(cryptonyms).find((key) => (
Boolean(word) &&
key.toLowerCase() === word.toLowerCase()
));

return Boolean(cryptonym) ?
cryptonyms[cryptonym] :
'';
};

const getBodyOverflow = (isHover: boolean) => (
isHover ?
'hidden' :
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ export interface RectangleProps {
left: number;
top: number;
height: number;
word: string;
tooltipMessage: string;
isHover: boolean;
}

Expand All @@ -13,5 +13,5 @@ export const createEmptyRectangleProps = (): RectangleProps => ({
height: 0,
left: 0,
top: 0,
word: '',
tooltipMessage: '',
});
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,15 @@ interface HocrProofreaderProps {
interface HocrProofreaderState {
docIdHighlighted: string;
previewIdHightlighted: string;
previewPageIndex: PageIndex;
}

export class HocrProofreaderComponent extends React.PureComponent<HocrProofreaderProps, HocrProofreaderState> {
constructor(props) {
super(props);

this.state = {
docIdHighlighted: null,
docIdHighlighted: `page_${this.props.pageIndex}`, // Start focusing initial page also in document view.
previewIdHightlighted: null,
previewPageIndex: this.props.pageIndex,
};
this.fixIndex = this.props.pageIndex;
}
Expand All @@ -53,10 +51,6 @@ export class HocrProofreaderComponent extends React.PureComponent<HocrProofreade

private handleDocumentPageHover = (index: number) => {
this.fixIndex = index; // **FIX. Read below.
this.setState({
...this.state,
previewPageIndex: index,
});
}

private handlePreviewWordHover = (id: string) => {
Expand All @@ -73,7 +67,7 @@ export class HocrProofreaderComponent extends React.PureComponent<HocrProofreade
className={style.hocrPreview}
hocr={this.props.hocr}
zoomMode={this.props.zoomMode}
pageIndex={/*this.state.previewPageIndex*/this.fixIndex}
pageIndex={this.fixIndex}
autoFocusId={this.state.previewIdHightlighted}
targetWords={this.props.targetWords}
onWordHover={this.handlePreviewWordHover}
Expand All @@ -83,6 +77,7 @@ export class HocrProofreaderComponent extends React.PureComponent<HocrProofreade
className={this.props.showText ? style.hocrDocument : style.hocrDocumentHidden}
hocr={this.props.hocr}
targetWords={this.props.targetWords}
hightlightPageIndex={Number(this.fixIndex)}
autoFocusId={this.state.docIdHighlighted}
onWordHover={this.handleDocumentWordHover}
onPageHover={this.handleDocumentPageHover}
Expand Down
30 changes: 19 additions & 11 deletions frontend/src/common/components/hocr/util/common-util.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { hocrClasses, hocrAttributes } from "../constants";

export type PageIndex = number | "auto";
export type WordComparator = (word: string) => boolean;

Expand All @@ -8,11 +10,11 @@ export interface WordPosition {


const hocrEntityMap = {
page: "ocr_page",
area: "ocr_carea",
paragraph: "ocr_par",
line: "ocr_line",
word: "ocrx_word",
page: hocrClasses.page,
area: hocrClasses.area,
paragraph: hocrClasses.paragraph,
line: hocrClasses.line,
word: hocrClasses.word,
}

export const resolveNodeEntity = (node: Element): string => {
Expand Down Expand Up @@ -43,21 +45,21 @@ export const parseWordPosition = (doc: Document, pageIndex: PageIndex,
if (typeof pageIndex === "number") {
const validatedPageIndex = (pageIndex < 0 || !checkPageIndexInRange(doc, pageIndex)) ? 0 : pageIndex;
const firstOcurrenceNode = wordIdInPage(doc.body.children[validatedPageIndex], wordComparator);
return {
return {
pageIndex: validatedPageIndex,
firstOcurrenceNode,
};
} else { // Auto page index based on the first ocurrence of a target word.
return findFirstOcurrencePosition(doc, wordComparator);
}
}
};

const checkPageIndexInRange = (doc: Document, pageIndex: number) => {
return doc.body && doc.body.children && (pageIndex < doc.body.children.length);
};

const findFirstOcurrencePosition = (doc: Document, wordComparator: WordComparator): WordPosition => {
let pos: WordPosition = {pageIndex: 0, firstOcurrenceNode: null};
let pos: WordPosition = { pageIndex: 0, firstOcurrenceNode: null };
if (wordComparator) {
Array.from(doc.body.children).some((page, index) => {
const foundNode = wordIdInPage(page, wordComparator);
Expand All @@ -67,7 +69,7 @@ const findFirstOcurrencePosition = (doc: Document, wordComparator: WordComparato
}
return Boolean(foundNode);
});
}
}
return pos;
};

Expand Down Expand Up @@ -100,7 +102,7 @@ export const getNodeOptions = (node: Element): any => {
const optionsStr = node["title"] ? node["title"] : "";
const regex = /(?:^|;)\s*(\w+)\s+(?:([^;"']+?)|"((?:\\"|[^"])+?)"|'((?:\\'|[^'])+?)')\s*(?=;|$)/g;
let match;

let options = {};
while (match = regex.exec(optionsStr)) {
const name = match[1];
Expand Down Expand Up @@ -155,5 +157,11 @@ export const calculateNodeShiftInContainer = (target: PosSize, container: PosSiz
const shiftCentroidXPercentage = shiftCentroidX / container.width;
const shiftCentroidYPercentage = shiftCentroidY / container.height;

return {x: shiftCentroidXPercentage, y: shiftCentroidYPercentage};
return { x: shiftCentroidXPercentage, y: shiftCentroidYPercentage };
}

export const getAnnotationMessage = (node: Element): string => (
Boolean(node.attributes[hocrAttributes.dataAnnotation]) ?
node.attributes[hocrAttributes.dataAnnotation].value :
null
);
4 changes: 0 additions & 4 deletions frontend/src/common/constants/cryptonyms.ts

This file was deleted.

6 changes: 0 additions & 6 deletions frontend/src/common/constants/synonyms.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as React from "react";
import { ItemComponent } from "./item.component";
import { ItemCollection, Item } from "../../view-model";
import { cnc } from "../../../../util";
import { cnc, getUniqueStrings } from "../../../../util";

const style = require("./item-collection-view.style.scss");

Expand All @@ -19,6 +19,10 @@ export class ItemCollectionViewComponent extends React.Component<ItemViewProps,
super(props);
}

private injectHighlightWords = (targetWords: string[], highlightWords: string[]): string[] => {
return getUniqueStrings([...targetWords, ...highlightWords]);
}

public render() {
return (
<div className={cnc(style.container, this.props.listMode && style.containerList)}>
Expand All @@ -28,7 +32,7 @@ export class ItemCollectionViewComponent extends React.Component<ItemViewProps,
item={child}
listMode={this.props.listMode}
activeSearch={this.props.activeSearch}
targetWords={this.props.targetWords}
targetWords={this.injectHighlightWords(this.props.targetWords, child.highlightWords)}
onClick={this.props.onClick}
key={index}
/>
Expand Down