diff --git a/asl_rulebook2/webapp/content.py b/asl_rulebook2/webapp/content.py index 6d453a7..e4c0161 100644 --- a/asl_rulebook2/webapp/content.py +++ b/asl_rulebook2/webapp/content.py @@ -2,6 +2,7 @@ import os import re +from collections import defaultdict from flask import jsonify, send_file, url_for, abort @@ -70,6 +71,7 @@ def load_content_sets( startup_msgs, logger ): if not app.config.get( "IGNORE_MISSING_DATA_FILES" ): logger.warn( "Didn't find targets file: %s", fname ) load_file( fname_stem+".chapters", content_doc, "chapters", startup_msgs.warning ) + load_file( fname_stem+".vo-notes", content_doc, "vo-notes", startup_msgs.warning ) if load_file( fname_stem+".footnotes", content_doc, "footnotes", startup_msgs.warning ): # update the footnote index # NOTE: The front-end doesn't care about what chapter a footnote belongs to, @@ -308,7 +310,7 @@ def get_content_docs(): } if "filename" in cdoc: cdoc2["url"] = url_for( "get_content", cdoc_id=cdoc["cdoc_id"] ) - for key in [ "targets", "chapters", "background", "icon" ]: + for key in [ "targets", "vo-notes", "chapters", "background", "icon" ]: if key in cdoc: cdoc2[key] = cdoc[key] resp[ cdoc["cdoc_id"] ] = cdoc2 @@ -348,3 +350,30 @@ def get_chapter_resource( chapter_id, rtype ): if not fname: abort( 404 ) return send_file( fname ) + +# --------------------------------------------------------------------- + +@app.route( "/vo-note-targets" ) +def get_vo_note_targets(): + """Return the Chapter H vehicle/ordnance note targets.""" + targets = defaultdict( lambda: defaultdict( dict ) ) + def add_targets( dest, key, vo_entries ): + for vo_note_id, vo_entry in vo_entries.items(): + dest[ vo_note_id ] = { + "caption": vo_entry["caption"], + "target": "{}:{}".format( key, vo_note_id ), + } + for cset in _content_sets.values(): + for cdoc in cset["content_docs"].values(): + vo_notes = cdoc.get( "vo-notes" ) + if not vo_notes: + continue + for nat in vo_notes: + if nat == "landing-craft": + key = "{}/{}".format( cdoc["cdoc_id"], nat ) + add_targets( targets["landing-craft"], key, vo_notes[nat] ) + else: + for vo_type in ["vehicles","ordnance"]: + key = "{}/{}_{}".format( cdoc["cdoc_id"], nat, vo_type ) + add_targets( targets[nat][vo_type], key, vo_notes[nat][vo_type] ) + return jsonify( targets ) diff --git a/asl_rulebook2/webapp/static/MainApp.js b/asl_rulebook2/webapp/static/MainApp.js index 985ded1..d77339a 100644 --- a/asl_rulebook2/webapp/static/MainApp.js +++ b/asl_rulebook2/webapp/static/MainApp.js @@ -151,20 +151,46 @@ gMainApp.component( "main-app", { // install the content docs gContentDocs = contentDocs ; // build an index of all the targets - gTargetIndex = {} ; - Object.values( contentDocs ).forEach( (cdoc) => { - if ( ! cdoc.targets ) - return ; - for ( let ruleid in cdoc.targets ) { - let ruleidLC = ruleid.toLowerCase() ; - if ( ! gTargetIndex[ ruleidLC ] ) - gTargetIndex[ ruleidLC ] = [] ; - gTargetIndex[ ruleidLC ].push( { + function updateTargetIndex( entries, key, cdoc ) { + for ( let vo_note_id in entries ) { + let dest = key + ":" + vo_note_id ; + if ( ! gTargetIndex[ dest ] ) + gTargetIndex[ dest ] = [] ; + gTargetIndex[ dest ].push( { cset_id: cdoc.parent_cset_id, cdoc_id: cdoc.cdoc_id, - ruleid: ruleid + ruleid: dest, } ) ; } + } + gTargetIndex = {} ; + Object.values( contentDocs ).forEach( (cdoc) => { + if ( cdoc.targets ) { + // add entries for each of the normal rules + for ( let ruleid in cdoc.targets ) { + let ruleidLC = ruleid.toLowerCase() ; + if ( ! gTargetIndex[ ruleidLC ] ) + gTargetIndex[ ruleidLC ] = [] ; + gTargetIndex[ ruleidLC ].push( { + cset_id: cdoc.parent_cset_id, + cdoc_id: cdoc.cdoc_id, + ruleid: ruleid + } ) ; + } + } + if ( cdoc["vo-notes"] ) { + // add entries for each of the vehicle/ordnance notes + for ( let nat in cdoc["vo-notes"] ) { + if ( nat == "landing-craft" ) { + updateTargetIndex( cdoc["vo-notes"][nat], nat, cdoc ) ; + continue ; + } + for ( let vo_type in cdoc["vo-notes"][nat] ) { + let key = nat + "_" + vo_type ; + updateTargetIndex( cdoc["vo-notes"][nat][vo_type], key, cdoc ) ; + } + } + } } ) ; // build an index of the available chapters resources function preloadImage( url ) { @@ -208,15 +234,20 @@ gMainApp.component( "main-app", { } ).catch( (errorMsg) => { showErrorMsg( "Couldn't get the startup messages.", errorMsg ) ; } ) ; - // check if we should start with a query + // check if we should start with a query or target let queryString = gUrlParams.get( "query" ) || gUrlParams.get( "q" ) ; if ( window.location.hash != "" ) queryString = window.location.hash.substring( 1 ) ; + let target = gUrlParams.get( "target" ) || gUrlParams.get( "t" ) || "" ; + let targetSplitPos = target.indexOf( "/" ) ; if ( queryString != null && queryString != undefined ) { // yup - make it so // NOTE: The content pane flickers as it shows the cover page, then jumps to search result. // I tried opening the PDF at the target destination, but the same thing still happens :-( gEventBus.emit( "search", queryString ) ; + } else if ( targetSplitPos > 0 ) { + // yup - make it so + gEventBus.emit( "show-target", target.substring(0,targetSplitPos), target.substring(targetSplitPos+1) ) ; } else { // start off showing the main ASL rulebook // NOTE: To avoid forcing the user to configure which document this is, diff --git a/asl_rulebook2/webapp/static/utils.js b/asl_rulebook2/webapp/static/utils.js index 89a4866..15d4e84 100644 --- a/asl_rulebook2/webapp/static/utils.js +++ b/asl_rulebook2/webapp/static/utils.js @@ -23,12 +23,15 @@ export function findTargets( ruleid, csetId ) // also have the concept of a "target", which is a ruleid plus the content set it's in. // One can only hope that ruleid's are unique in this context, even if there are multiple documents // in each content set... + // NOTE: With vasl-templates integrations, there are destinations within the PDF that are not + // actually ruleid's (i.e. Chapter H vehicle/ordnance notes), but we retain the old terminology, + // since it will usually be the case. // check if the ruleid is known to us - let pos = ruleid.indexOf( "-" ) ; - if ( pos >= 0 ) { + let match = ruleid.match( /-[0-9.]/ ) ; + if ( match ) { // NOTE: For ruleid's of the form "A12.3-.4", we want to target "A12.3". - ruleid = ruleid.substring( 0, pos ) ; + ruleid = ruleid.substring( 0, match.index ) ; } let targets = gTargetIndex[ ruleid.toLowerCase() ] ; if ( targets && csetId )