good initial page state
This commit is contained in:
parent
2cd689b468
commit
7e71cb947b
@ -250,13 +250,9 @@ fn get_prim_by_path(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_prim_model_by_path_with_file(path: &str, file: &CosFile) -> Result<PrimitiveModel, String> {
|
fn get_prim_model_by_path_with_file(path: &str, file: &CosFile) -> Result<PrimitiveModel, String> {
|
||||||
let (step, prim, detail_path) = get_prim_by_path_with_file(path, file)?;
|
let (step, prim, trace) = get_prim_by_path_with_file(path, file)?;
|
||||||
|
|
||||||
Ok(PrimitiveModel::from_primitive_with_children(
|
Ok(PrimitiveModel::from_primitive_with_children(&prim, trace))
|
||||||
step.get_key(),
|
|
||||||
&prim,
|
|
||||||
detail_path,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_prim_by_path_with_file(
|
fn get_prim_by_path_with_file(
|
||||||
@ -286,7 +282,7 @@ fn get_prim_by_steps_with_file(
|
|||||||
current_prim = resolve_step(¤t_prim, &step)?;
|
current_prim = resolve_step(¤t_prim, &step)?;
|
||||||
if let Primitive::Reference(xref) = current_prim {
|
if let Primitive::Reference(xref) = current_prim {
|
||||||
last_jump = xref.id.to_string();
|
last_jump = xref.id.to_string();
|
||||||
parent = resolve_pref(xref.clone(), file)?;
|
parent = resolve_p_ref(xref.clone(), file)?;
|
||||||
current_prim = &parent;
|
current_prim = &parent;
|
||||||
}
|
}
|
||||||
trace.push(PathTrace::new(step.get_key(), last_jump.clone()));
|
trace.push(PathTrace::new(step.get_key(), last_jump.clone()));
|
||||||
@ -296,9 +292,9 @@ fn get_prim_by_steps_with_file(
|
|||||||
|
|
||||||
fn resolve_parent(step: Step, file: &CosFile) -> Result<(Primitive, PathTrace), String> {
|
fn resolve_parent(step: Step, file: &CosFile) -> Result<(Primitive, PathTrace), String> {
|
||||||
let parent = match step {
|
let parent = match step {
|
||||||
|
Step::Page(page_num) => return retrieve_page(page_num, file),
|
||||||
Step::Number(obj_num) => resolve_xref(obj_num, file)?,
|
Step::Number(obj_num) => resolve_xref(obj_num, file)?,
|
||||||
Step::Trailer => retrieve_trailer(file),
|
Step::Trailer => retrieve_trailer(file),
|
||||||
Step::Page(page_num) => retrieve_page(page_num, file)?,
|
|
||||||
_ => return Err(String::from(format!("{:?} is not a valid path!", step))),
|
_ => return Err(String::from(format!("{:?} is not a valid path!", step))),
|
||||||
};
|
};
|
||||||
Ok((parent, PathTrace::new(step.get_key(), step.get_key())))
|
Ok((parent, PathTrace::new(step.get_key(), step.get_key())))
|
||||||
@ -323,12 +319,11 @@ fn get_prim_tree_by_path_with_file(
|
|||||||
file: &CosFile,
|
file: &CosFile,
|
||||||
) -> Result<PrimitiveModel, String> {
|
) -> Result<PrimitiveModel, String> {
|
||||||
let step = node.step()?;
|
let step = node.step()?;
|
||||||
let (mut parent, trace) = resolve_parent(step.clone(), file)?;
|
let (parent, trace) = resolve_parent(step.clone(), file)?;
|
||||||
|
|
||||||
let path = vec![trace];
|
let path = vec![trace];
|
||||||
|
let mut parent_model = PrimitiveModel::from_primitive_with_children(&parent, path);
|
||||||
|
|
||||||
let mut parent_model =
|
|
||||||
PrimitiveModel::from_primitive_with_children(step.get_key(), &parent, path);
|
|
||||||
for child in node.children.iter() {
|
for child in node.children.iter() {
|
||||||
expand(child, &mut parent_model, &parent, file)?;
|
expand(child, &mut parent_model, &parent, file)?;
|
||||||
}
|
}
|
||||||
@ -420,7 +415,6 @@ fn resolve_step<'a>(current_prim: &'a Primitive, step: &Step) -> Result<&'a Prim
|
|||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Step::Data => return Err("Not implemented!".to_string()),
|
|
||||||
_ => return Err(format!("Invalid Step: {}", step.get_key())),
|
_ => return Err(format!("Invalid Step: {}", step.get_key())),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -430,9 +424,13 @@ fn retrieve_trailer(file: &CosFile) -> Primitive {
|
|||||||
file.trailer.to_primitive(&mut updater).unwrap()
|
file.trailer.to_primitive(&mut updater).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn retrieve_page(page_num: u32, file: &CosFile) -> Result<Primitive, String> {
|
fn retrieve_page(page_num: u32, file: &CosFile) -> Result<(Primitive, PathTrace), String> {
|
||||||
let page_rc = t!(file.get_page(page_num - 1));
|
let page_rc = t!(file.get_page(page_num - 1));
|
||||||
resolve_pref(page_rc.get_ref().get_inner(), file)
|
let p_ref = page_rc.get_ref().get_inner();
|
||||||
|
Ok((
|
||||||
|
resolve_p_ref(p_ref, file)?,
|
||||||
|
PathTrace::new(format!("Page{}", page_num), p_ref.id.to_string()),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum Step {
|
pub enum Step {
|
||||||
@ -498,10 +496,10 @@ impl Step {
|
|||||||
|
|
||||||
fn resolve_xref(id: u64, file: &CosFile) -> Result<Primitive, String> {
|
fn resolve_xref(id: u64, file: &CosFile) -> Result<Primitive, String> {
|
||||||
let plain_ref = PlainRef { id, gen: 0 };
|
let plain_ref = PlainRef { id, gen: 0 };
|
||||||
resolve_pref(plain_ref, file)
|
resolve_p_ref(plain_ref, file)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_pref(plain_ref: PlainRef, file: &CosFile) -> Result<Primitive, String> {
|
fn resolve_p_ref(plain_ref: PlainRef, file: &CosFile) -> Result<Primitive, String> {
|
||||||
file.resolver()
|
file.resolver()
|
||||||
.resolve(plain_ref)
|
.resolve(plain_ref)
|
||||||
.map_err(|e| e.to_string())
|
.map_err(|e| e.to_string())
|
||||||
@ -595,12 +593,12 @@ impl PrimitiveModel {
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_primitive_with_children(
|
fn from_primitive_with_children(primitive: &Primitive, path: Vec<PathTrace>) -> PrimitiveModel {
|
||||||
key: String,
|
let mut model = PrimitiveModel::from_primitive(
|
||||||
primitive: &Primitive,
|
path.last().unwrap().key.clone(),
|
||||||
path: Vec<PathTrace>,
|
primitive,
|
||||||
) -> PrimitiveModel {
|
path.clone(),
|
||||||
let mut model = PrimitiveModel::from_primitive(key, primitive, path.clone());
|
);
|
||||||
model.add_children(primitive, path);
|
model.add_children(primitive, path);
|
||||||
model
|
model
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,7 +23,7 @@
|
|||||||
let treeShowing: boolean = $state(true);
|
let treeShowing: boolean = $state(true);
|
||||||
let pagesShowing: boolean = $state(false);
|
let pagesShowing: boolean = $state(false);
|
||||||
let fileViewHeight: number = $derived(
|
let fileViewHeight: number = $derived(
|
||||||
Math.max(innerHeight - footerHeight - titleBarHeight, 0),
|
Math.max(innerHeight - footerHeight - tabBarHeight - titleBarHeight, 0),
|
||||||
);
|
);
|
||||||
|
|
||||||
let fStates: Map<string, FileViewState> = new Map<string, FileViewState>();
|
let fStates: Map<string, FileViewState> = new Map<string, FileViewState>();
|
||||||
@ -109,7 +109,7 @@
|
|||||||
<div style="height: {titleBarHeight}px">
|
<div style="height: {titleBarHeight}px">
|
||||||
<TitleBar></TitleBar>
|
<TitleBar></TitleBar>
|
||||||
</div>
|
</div>
|
||||||
<div style="height: {fileViewHeight}px">
|
<div class="fileview_container" style="height: {fileViewHeight + 30}px">
|
||||||
<Splitpanes theme="forge-movable" dblClickSplitter={false}>
|
<Splitpanes theme="forge-movable" dblClickSplitter={false}>
|
||||||
<Pane size={2.5} minSize={1.5} maxSize={4}>
|
<Pane size={2.5} minSize={1.5} maxSize={4}>
|
||||||
<ToolbarLeft bind:tree={treeShowing} bind:pages={pagesShowing}
|
<ToolbarLeft bind:tree={treeShowing} bind:pages={pagesShowing}
|
||||||
|
|||||||
@ -7,8 +7,8 @@
|
|||||||
|
|
||||||
let { fState, height }: { fState: FileViewState; height: number } =
|
let { fState, height }: { fState: FileViewState; height: number } =
|
||||||
$props();
|
$props();
|
||||||
let h = $derived(height - 34);
|
let h = $derived(height);
|
||||||
let path = $derived(fState.prim?.getLastJump().toString());
|
let path = $derived(fState.prim?.getFirstJump()?.toString());
|
||||||
let id = $derived(fState.file.id);
|
let id = $derived(fState.file.id);
|
||||||
let contents: ContentModel | undefined = $state(undefined);
|
let contents: ContentModel | undefined = $state(undefined);
|
||||||
let editorContainer: HTMLElement;
|
let editorContainer: HTMLElement;
|
||||||
@ -41,6 +41,7 @@
|
|||||||
|
|
||||||
invoke<ContentModel>("get_contents", { id, path })
|
invoke<ContentModel>("get_contents", { id, path })
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
|
console.log("Contents loaded", result);
|
||||||
contents = result;
|
contents = result;
|
||||||
if (contents && editor) {
|
if (contents && editor) {
|
||||||
const text = contents.parts
|
const text = contents.parts
|
||||||
@ -49,13 +50,6 @@
|
|||||||
"\n\n%-------------------% EOF %-------------------%\n\n",
|
"\n\n%-------------------% EOF %-------------------%\n\n",
|
||||||
);
|
);
|
||||||
editor.setValue(text);
|
editor.setValue(text);
|
||||||
const model = editor.getModel();
|
|
||||||
if (model) {
|
|
||||||
monaco.editor.setModelLanguage(
|
|
||||||
model,
|
|
||||||
"pdf-content-stream",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((err) => console.error(err));
|
.catch((err) => console.error(err));
|
||||||
|
|||||||
@ -4,9 +4,12 @@
|
|||||||
import PrimitiveView from "./PrimitiveView.svelte";
|
import PrimitiveView from "./PrimitiveView.svelte";
|
||||||
import TreeView from "./TreeView.svelte";
|
import TreeView from "./TreeView.svelte";
|
||||||
import type FileViewState from "../models/FileViewState.svelte";
|
import type FileViewState from "../models/FileViewState.svelte";
|
||||||
import { onMount } from "svelte";
|
import { createEventDispatcher, onMount } from "svelte";
|
||||||
import PageList from "./PageList.svelte";
|
import PageList from "./PageList.svelte";
|
||||||
import ContentsView from "./ContentsView.svelte";
|
import ContentsView from "./ContentsView.svelte";
|
||||||
|
import TreeViewNode from "../models/TreeViewNode.svelte";
|
||||||
|
import TreeViewState from "../models/TreeViewState.svelte";
|
||||||
|
import type { PathSelectedEvent } from "../events/PathSelectedEvent";
|
||||||
|
|
||||||
let {
|
let {
|
||||||
treeShowing,
|
treeShowing,
|
||||||
@ -49,37 +52,33 @@
|
|||||||
window.removeEventListener("mousedown", handleMouseButton);
|
window.removeEventListener("mousedown", handleMouseButton);
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function pathSelectedHandler(event: PathSelectedEvent) {
|
||||||
|
console.log("Path selected", event.detail.path);
|
||||||
|
fState.selectPath(event.detail.path);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div bind:clientWidth={width} class="file-view-container">
|
<div bind:clientWidth={width} class="file-view-container">
|
||||||
<div style="width: {splitPanesWidth}px">
|
<div
|
||||||
|
class="flex flex-row"
|
||||||
|
style="width: {splitPanesWidth}px; height: {height}px"
|
||||||
|
>
|
||||||
<Splitpanes theme="forge-movable" pushOtherPanes={false}>
|
<Splitpanes theme="forge-movable" pushOtherPanes={false}>
|
||||||
<Pane
|
<Pane
|
||||||
size={treeShowing || pagesShowing ? 15 : 0}
|
size={treeShowing || pagesShowing ? 15 : 0}
|
||||||
minSize={treeShowing || pagesShowing ? 1 : 0}
|
minSize={treeShowing || pagesShowing ? 2 : 0}
|
||||||
maxSize={treeShowing || pagesShowing ? 100 : 0}
|
maxSize={treeShowing || pagesShowing ? 100 : 0}
|
||||||
>
|
>
|
||||||
<Splitpanes
|
{#if pagesShowing}
|
||||||
theme="forge-movable"
|
<PageList {fState} h={height}></PageList>
|
||||||
horizontal
|
{:else if treeShowing}
|
||||||
pushOtherPanes={false}
|
<TreeView
|
||||||
style="height: {height}px"
|
bind:pathSelectedHandler
|
||||||
>
|
file_id={fState.file.id}
|
||||||
<Pane
|
root={TreeViewNode.TRAILER}
|
||||||
size={treeShowing ? (pagesShowing ? 50 : 100) : 0}
|
></TreeView>
|
||||||
minSize={treeShowing ? 2 : 0}
|
{/if}
|
||||||
maxSize={treeShowing ? 100 : 0}
|
|
||||||
>
|
|
||||||
<TreeView {fState}></TreeView>
|
|
||||||
</Pane>
|
|
||||||
<Pane
|
|
||||||
size={pagesShowing ? (treeShowing ? 50 : 100) : 0}
|
|
||||||
minSize={pagesShowing ? 2 : 0}
|
|
||||||
maxSize={pagesShowing ? 100 : 0}
|
|
||||||
>
|
|
||||||
<PageList {fState}></PageList>
|
|
||||||
</Pane>
|
|
||||||
</Splitpanes>
|
|
||||||
</Pane>
|
</Pane>
|
||||||
|
|
||||||
<Pane minSize={1}>
|
<Pane minSize={1}>
|
||||||
@ -98,7 +97,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{#if xrefTableShowing}
|
{#if xrefTableShowing}
|
||||||
<div class="xref-modal" class:visible={xrefTableShowing}>
|
<div class="xref-modal" class:visible={xrefTableShowing}>
|
||||||
<XRefTable {fState}></XRefTable>
|
<XRefTable {fState} {height}></XRefTable>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
@ -110,21 +109,13 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.xref-modal-container {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
width: 0;
|
|
||||||
overflow: visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
.xref-modal {
|
.xref-modal {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
border-left: 1px solid var(--border-color);
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
width: 281px;
|
width: 280px;
|
||||||
background: var(--background-color);
|
background: var(--background-color);
|
||||||
box-shadow: -2px 0 5px rgba(0, 0, 0, 0.1);
|
box-shadow: -2px 0 5px rgba(0, 0, 0, 0.1);
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
|
|||||||
@ -24,8 +24,6 @@
|
|||||||
fState && fState.prim ? toElements(fState.prim.trace) : undefined,
|
fState && fState.prim ? toElements(fState.prim.trace) : undefined,
|
||||||
);
|
);
|
||||||
|
|
||||||
$inspect(fState?.path);
|
|
||||||
$inspect(fState?.prim?.trace);
|
|
||||||
function toElements(path: Trace[]): Path[] {
|
function toElements(path: Trace[]): Path[] {
|
||||||
if (path.length == 0) {
|
if (path.length == 0) {
|
||||||
return [new Path("Trailer", 0)];
|
return [new Path("Trailer", 0)];
|
||||||
@ -52,38 +50,30 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div class="footer" style="height: {footerHeight}px">
|
||||||
class="bg-forge-prim border border-forge-bound"
|
{#if elements}
|
||||||
style="height: {footerHeight}px"
|
{#each elements as path}
|
||||||
>
|
<button
|
||||||
<div class="flex flex-row items-center" style="height: {footerHeight}px">
|
class="flex flex-row items-center ml-2"
|
||||||
{#if elements}
|
onclick={() => selectPath(path)}
|
||||||
{#each elements as path}
|
>
|
||||||
<button
|
{#if path.jump}
|
||||||
class="flex flex-row items-center ml-2"
|
<PrimitiveIcon ptype={"Reference"}></PrimitiveIcon>
|
||||||
onclick={() => selectPath(path)}
|
{:else}
|
||||||
>
|
<CaretRightOutline class="text-forge-sec" />
|
||||||
{#if path.jump}
|
{/if}
|
||||||
<div
|
<p class="text-xs ml-1">{path.value}</p>
|
||||||
class="flex items-center mr-1 ml-1"
|
</button>
|
||||||
style="height: {footerHeight}px"
|
{/each}
|
||||||
>
|
{/if}
|
||||||
<PrimitiveIcon ptype={"Reference"}></PrimitiveIcon>
|
|
||||||
</div>
|
|
||||||
{:else}
|
|
||||||
<div
|
|
||||||
class="flex items-center"
|
|
||||||
style="height: {footerHeight}px"
|
|
||||||
>
|
|
||||||
<CaretRightOutline class="text-forge-sec" />
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
<p class="text-xs ml-1">{path.value}</p>
|
|
||||||
</button>
|
|
||||||
{/each}
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="postcss">
|
<style lang="postcss">
|
||||||
|
.footer {
|
||||||
|
@apply bg-forge-prim border border-forge-bound flex flex-row items-center;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -3,8 +3,7 @@
|
|||||||
import PrimitiveIcon from "./PrimitiveIcon.svelte";
|
import PrimitiveIcon from "./PrimitiveIcon.svelte";
|
||||||
import type PageModel from "../models/PageModel";
|
import type PageModel from "../models/PageModel";
|
||||||
|
|
||||||
let { fState }: { fState: FileViewState } = $props();
|
let { fState, h }: { fState: FileViewState; h: number } = $props();
|
||||||
let h: number = $state(100);
|
|
||||||
let selected: PageModel | undefined = $state(undefined);
|
let selected: PageModel | undefined = $state(undefined);
|
||||||
|
|
||||||
function handlePageSelect(page: PageModel) {
|
function handlePageSelect(page: PageModel) {
|
||||||
@ -13,43 +12,37 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div bind:clientHeight={h} class="full-container">
|
<div class="overflow-x-auto">
|
||||||
<div class="overflow-x-auto">
|
<table>
|
||||||
<div class="w-[251px]">
|
<thead>
|
||||||
<table>
|
<tr>
|
||||||
<thead>
|
<td class="page-cell t-header border-forge-prim">Page</td>
|
||||||
<tr>
|
<td class="ref-cell t-header border-forge-sec">Ref</td>
|
||||||
<td class="page-cell t-header border-forge-prim"
|
</tr>
|
||||||
>Page</td
|
</thead>
|
||||||
>
|
</table>
|
||||||
<td class="ref-cell t-header border-forge-sec">Ref</td>
|
<div class="overflow-y-auto" style="height: {h - 25}px">
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
{#each fState.file.pages as page}
|
||||||
|
<tr
|
||||||
|
class:selected={page === selected}
|
||||||
|
class="hover:bg-forge-sec"
|
||||||
|
ondblclick={() => handlePageSelect(page)}
|
||||||
|
>
|
||||||
|
<td class="page-cell t-data">
|
||||||
|
<div class="key-field">
|
||||||
|
<PrimitiveIcon ptype={"Reference"} />
|
||||||
|
<p class="text-left">
|
||||||
|
{page.key}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td class="ref-cell t-data">{page.obj_num}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
{/each}
|
||||||
</table>
|
</tbody>
|
||||||
<div class="overflow-y-auto" style="height: {h - 55}px">
|
</table>
|
||||||
<table>
|
|
||||||
<tbody>
|
|
||||||
{#each fState.file.pages as page}
|
|
||||||
<tr
|
|
||||||
class:selected={page === selected}
|
|
||||||
class="hover:bg-forge-sec"
|
|
||||||
ondblclick={() => handlePageSelect(page)}
|
|
||||||
>
|
|
||||||
<td class="page-cell t-data">
|
|
||||||
<div class="key-field">
|
|
||||||
<PrimitiveIcon ptype={"Reference"} />
|
|
||||||
<p class="text-left">
|
|
||||||
{page.key}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td class="ref-cell t-data">{page.id}</td>
|
|
||||||
</tr>
|
|
||||||
{/each}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -71,7 +64,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.t-data {
|
.t-data {
|
||||||
@apply border border-forge-sec text-sm text-forge-text text-left;
|
@apply border border-forge-sec text-xs text-forge-text text-left;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,11 +6,10 @@
|
|||||||
|
|
||||||
let { fState, height }: { fState: FileViewState; height: number } =
|
let { fState, height }: { fState: FileViewState; height: number } =
|
||||||
$props();
|
$props();
|
||||||
let bodyHeight = $derived(height - 54);
|
let bodyHeight = $derived(height - 24);
|
||||||
let selected: Primitive | undefined = $state(undefined);
|
|
||||||
let prim = $derived(fState.prim);
|
let prim = $derived(fState.prim);
|
||||||
let showContents = $state(false);
|
let showContents = $state(false);
|
||||||
|
$inspect(fState.highlightedPrim);
|
||||||
function handlePrimSelect(prim: Primitive) {
|
function handlePrimSelect(prim: Primitive) {
|
||||||
if (prim.isContainer()) {
|
if (prim.isContainer()) {
|
||||||
if (!prim) {
|
if (!prim) {
|
||||||
@ -44,9 +43,10 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
{#each prim.children as entry}
|
{#each prim.children as entry}
|
||||||
<tr
|
<tr
|
||||||
class:selected={entry === selected}
|
class:selected={entry.key ===
|
||||||
|
fState.highlightedPrim?.key}
|
||||||
class="hover:bg-forge-sec"
|
class="hover:bg-forge-sec"
|
||||||
onclick={() => (selected = entry)}
|
onclick={() => (fState.highlightedPrim = entry)}
|
||||||
ondblclick={() => handlePrimSelect(entry)}
|
ondblclick={() => handlePrimSelect(entry)}
|
||||||
>
|
>
|
||||||
<td class="page-cell t-data">
|
<td class="page-cell t-data">
|
||||||
|
|||||||
@ -1,33 +1,48 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {BookOpenSolid, CodeBranchSolid} from "flowbite-svelte-icons";
|
import { BookOpenSolid, CodeBranchSolid } from "flowbite-svelte-icons";
|
||||||
|
|
||||||
let {tree = $bindable(false), pages = $bindable(false)}: { tree: boolean, pages: boolean } = $props();
|
|
||||||
|
|
||||||
|
let {
|
||||||
|
tree = $bindable(false),
|
||||||
|
pages = $bindable(false),
|
||||||
|
}: { tree: boolean; pages: boolean } = $props();
|
||||||
|
|
||||||
function toggleTree() {
|
function toggleTree() {
|
||||||
tree = !tree;
|
tree = !tree;
|
||||||
|
if (tree) {
|
||||||
|
pages = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function togglePages() {
|
function togglePages() {
|
||||||
pages = !pages;
|
pages = !pages;
|
||||||
|
if (pages) {
|
||||||
|
tree = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="grid grid-cols-1">
|
<div class="grid grid-cols-1">
|
||||||
<button class={ tree ? "tool-button active" : "tool-button" } onclick={toggleTree} >
|
<button
|
||||||
|
class={tree ? "tool-button active" : "tool-button"}
|
||||||
|
onclick={toggleTree}
|
||||||
|
>
|
||||||
<div class="justify-center flex m-0">
|
<div class="justify-center flex m-0">
|
||||||
<CodeBranchSolid class="rotate-180 scale-x-[-1]"/>
|
<CodeBranchSolid class="rotate-180 scale-x-[-1]" />
|
||||||
</div>
|
</div>
|
||||||
<b class="button-title">Tree</b>
|
<b class="button-title">Tree</b>
|
||||||
</button>
|
</button>
|
||||||
<button id="#page" class={ pages ? "tool-button active" : "tool-button" } onclick={togglePages}>
|
<button
|
||||||
<div class="justify-center flex ">
|
id="#page"
|
||||||
<BookOpenSolid/>
|
class={pages ? "tool-button active" : "tool-button"}
|
||||||
|
onclick={togglePages}
|
||||||
|
>
|
||||||
|
<div class="justify-center flex">
|
||||||
|
<BookOpenSolid />
|
||||||
</div>
|
</div>
|
||||||
<b class="button-title">Page</b>
|
<b class="button-title">Page</b>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<style lang="postcss">
|
<style lang="postcss">
|
||||||
.button-title {
|
.button-title {
|
||||||
@apply text-forge-text_sec text-xs;
|
@apply text-forge-text_sec text-xs;
|
||||||
|
|||||||
@ -2,16 +2,21 @@
|
|||||||
import type Primitive from "../models/Primitive.svelte";
|
import type Primitive from "../models/Primitive.svelte";
|
||||||
import PrimitiveIcon from "./PrimitiveIcon.svelte";
|
import PrimitiveIcon from "./PrimitiveIcon.svelte";
|
||||||
import { CaretRightOutline, CaretDownOutline } from "flowbite-svelte-icons";
|
import { CaretRightOutline, CaretDownOutline } from "flowbite-svelte-icons";
|
||||||
import type FileViewState from "../models/FileViewState.svelte";
|
import type TreeViewState from "../models/TreeViewState.svelte";
|
||||||
import { arraysAreEqual } from "../utils.js";
|
import { PathSelectedEvent } from "../events/PathSelectedEvent";
|
||||||
|
import { createEventDispatcher } from "svelte";
|
||||||
|
|
||||||
let {
|
let {
|
||||||
prim,
|
parent_view,
|
||||||
path,
|
parent_path,
|
||||||
fState,
|
treeState,
|
||||||
}: { prim: Primitive | undefined; path: string[]; fState: FileViewState } =
|
pathSelectedHandler = $bindable(),
|
||||||
$props();
|
}: {
|
||||||
let active = $derived(arraysAreEqual(path, fState.path));
|
parent_view: Primitive;
|
||||||
|
parent_path: string[];
|
||||||
|
treeState: TreeViewState;
|
||||||
|
pathSelectedHandler: any;
|
||||||
|
} = $props();
|
||||||
|
|
||||||
function copyPathAndAppend(key: string): string[] {
|
function copyPathAndAppend(key: string): string[] {
|
||||||
const _path = copyPath();
|
const _path = copyPath();
|
||||||
@ -22,33 +27,31 @@
|
|||||||
function copyPath(): string[] {
|
function copyPath(): string[] {
|
||||||
const _path: string[] = [];
|
const _path: string[] = [];
|
||||||
|
|
||||||
for (let item of path) {
|
for (let item of parent_path) {
|
||||||
_path.push(item);
|
_path.push(item);
|
||||||
}
|
}
|
||||||
return _path;
|
return _path;
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectItem(child: Primitive) {
|
function selectItem(child: Primitive) {
|
||||||
if (child.isContainer()) {
|
let _path = copyPathAndAppend(child.key);
|
||||||
let _path = copyPathAndAppend(child.key);
|
console.log("Selecting from tree", _path);
|
||||||
fState.expandTree(_path);
|
treeState.expandTree(_path);
|
||||||
fState.selectPath(_path);
|
|
||||||
} else {
|
const event = new PathSelectedEvent(_path);
|
||||||
let _path = copyPath();
|
pathSelectedHandler(event);
|
||||||
fState.selectPath(_path);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if prim}
|
{#if parent_view}
|
||||||
<ul class="active">
|
<ul class="active">
|
||||||
{#each prim.children as child}
|
{#each parent_view.children as child}
|
||||||
<li>
|
<li>
|
||||||
<div class="item">
|
<div class="item">
|
||||||
{#if child.children.length > 0}
|
{#if child.children.length > 0}
|
||||||
<button
|
<button
|
||||||
onclick={() =>
|
onclick={() =>
|
||||||
fState.collapseTree(
|
treeState.collapseTree(
|
||||||
copyPathAndAppend(child.key),
|
copyPathAndAppend(child.key),
|
||||||
)}
|
)}
|
||||||
><span class="caret"><CaretDownOutline /></span
|
><span class="caret"><CaretDownOutline /></span
|
||||||
@ -57,7 +60,9 @@
|
|||||||
{:else if child.isContainer()}
|
{:else if child.isContainer()}
|
||||||
<button
|
<button
|
||||||
onclick={() =>
|
onclick={() =>
|
||||||
fState.expandTree(copyPathAndAppend(child.key))}
|
treeState.expandTree(
|
||||||
|
copyPathAndAppend(child.key),
|
||||||
|
)}
|
||||||
><span class="caret"><CaretRightOutline /></span
|
><span class="caret"><CaretRightOutline /></span
|
||||||
></button
|
></button
|
||||||
>
|
>
|
||||||
@ -85,9 +90,10 @@
|
|||||||
</div>
|
</div>
|
||||||
{#if child.children.length > 0}
|
{#if child.children.length > 0}
|
||||||
<svelte:self
|
<svelte:self
|
||||||
prim={child}
|
parent_view={child}
|
||||||
path={copyPathAndAppend(child.key)}
|
parent_path={copyPathAndAppend(child.key)}
|
||||||
{fState}
|
{treeState}
|
||||||
|
bind:pathSelectedHandler
|
||||||
></svelte:self>
|
></svelte:self>
|
||||||
{/if}
|
{/if}
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@ -1,30 +1,48 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import TreeNode from "./TreeNode.svelte";
|
import TreeNode from "./TreeNode.svelte";
|
||||||
import type FileViewState from "../models/FileViewState.svelte";
|
|
||||||
import type Primitive from "../models/Primitive.svelte";
|
|
||||||
import PrimitiveIcon from "./PrimitiveIcon.svelte";
|
import PrimitiveIcon from "./PrimitiveIcon.svelte";
|
||||||
|
import TreeViewState from "../models/TreeViewState.svelte";
|
||||||
|
import type TreeViewNode from "../models/TreeViewNode.svelte";
|
||||||
|
|
||||||
let { fState }: { fState: FileViewState } = $props();
|
let {
|
||||||
let prim: Primitive | undefined = $derived(fState.treeView);
|
file_id,
|
||||||
|
root,
|
||||||
|
pathSelectedHandler = $bindable(),
|
||||||
|
active = true,
|
||||||
|
}: {
|
||||||
|
file_id: string;
|
||||||
|
root: TreeViewNode;
|
||||||
|
pathSelectedHandler: any;
|
||||||
|
active: boolean;
|
||||||
|
} = $props();
|
||||||
let h = $state(100);
|
let h = $state(100);
|
||||||
|
let treeState = $state(new TreeViewState(file_id, root));
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div bind:clientHeight={h} class="full-container">
|
<div bind:clientHeight={h} class="full-container">
|
||||||
<div class="overflow-auto" style="height: {h}px">
|
<div class="overflow-auto" style="height: {h}px">
|
||||||
<ul id="myUL">
|
<ul id="myUL">
|
||||||
{#if prim}
|
{#if treeState.view}
|
||||||
<li>
|
<li>
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<PrimitiveIcon ptype={"Dictionary"} />
|
<PrimitiveIcon ptype={"Dictionary"} />
|
||||||
{"Trailer "}
|
{"Trailer "}
|
||||||
</div>
|
</div>
|
||||||
<TreeNode {prim} path={prim.getTrace()} {fState}></TreeNode>
|
{#if active}
|
||||||
|
<TreeNode
|
||||||
|
bind:pathSelectedHandler
|
||||||
|
parent_view={treeState.view}
|
||||||
|
parent_path={treeState.view.getPath()}
|
||||||
|
{treeState}
|
||||||
|
></TreeNode>
|
||||||
|
{/if}
|
||||||
</li>
|
</li>
|
||||||
{/if}
|
{/if}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
getTrace
|
getTrace
|
||||||
</div>
|
</div>
|
||||||
|
getPath
|
||||||
|
|
||||||
<style lang="postcss">
|
<style lang="postcss">
|
||||||
.item {
|
.item {
|
||||||
|
|||||||
@ -3,10 +3,10 @@
|
|||||||
import type XRefEntry from "../models/XRefEntry";
|
import type XRefEntry from "../models/XRefEntry";
|
||||||
|
|
||||||
const cellH = 25;
|
const cellH = 25;
|
||||||
const headerOffset = 80;
|
const headerOffset = 2 * cellH;
|
||||||
let { fState }: { fState: FileViewState } = $props();
|
let { fState, height }: { fState: FileViewState; height: number } =
|
||||||
|
$props();
|
||||||
|
|
||||||
let viewHeight: number = $state(100);
|
|
||||||
let fillerHeight: number = $state(0);
|
let fillerHeight: number = $state(0);
|
||||||
|
|
||||||
let firstEntry = $state(0);
|
let firstEntry = $state(0);
|
||||||
@ -15,9 +15,8 @@
|
|||||||
fState.xref_entries.slice(firstEntry, lastEntry),
|
fState.xref_entries.slice(firstEntry, lastEntry),
|
||||||
);
|
);
|
||||||
|
|
||||||
let bodyViewHeight: number = $derived(
|
let bodyViewHeight: number = $derived(Math.max(height - headerOffset, 0));
|
||||||
Math.max(viewHeight - headerOffset, 0),
|
$inspect(bodyViewHeight);
|
||||||
);
|
|
||||||
let selectedPath: number | string | undefined = $derived(
|
let selectedPath: number | string | undefined = $derived(
|
||||||
fState.getLastJump(),
|
fState.getLastJump(),
|
||||||
);
|
);
|
||||||
@ -38,7 +37,7 @@
|
|||||||
|
|
||||||
if (
|
if (
|
||||||
targetY - startY > 0 &&
|
targetY - startY > 0 &&
|
||||||
targetY - startY < Math.max(viewHeight - headerOffset, 0)
|
targetY - startY < Math.max(height - headerOffset, 0)
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -74,61 +73,55 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div bind:clientHeight={viewHeight} class="full-container">
|
<div class="overflow-x-auto" style="height: {height}px;">
|
||||||
<div class="overflow-x-auto">
|
<div class="w-[281px]">
|
||||||
<div class="w-[281px]">
|
<table>
|
||||||
<table>
|
<thead>
|
||||||
<thead>
|
<tr>
|
||||||
<tr>
|
<td class="cell t-header border-forge-prim">Obj Nr</td>
|
||||||
<td class="cell t-header border-forge-prim">Obj Nr</td>
|
<td class="cell t-header border-forge-prim">Gen Nr</td>
|
||||||
<td class="cell t-header border-forge-prim">Gen Nr</td>
|
<td class="cell t-header border-forge-prim">Type</td>
|
||||||
<td class="cell t-header border-forge-prim">Type</td>
|
<td class="cell t-header border-forge-sec">Offset</td>
|
||||||
<td class="cell t-header border-forge-sec">Offset</td>
|
</tr>
|
||||||
</tr>
|
<tr
|
||||||
<tr
|
class={selectedPath === "/"
|
||||||
class={selectedPath === "/"
|
? "bg-forge-acc"
|
||||||
? "bg-forge-acc"
|
: "hover:bg-forge-sec"}
|
||||||
: "hover:bg-forge-sec"}
|
ondblclick={() => fState.selectXref(undefined)}
|
||||||
ondblclick={() => fState.selectXref(undefined)}
|
|
||||||
>
|
|
||||||
<td class="cell t-data">Trailer</td>
|
|
||||||
<td class="cell t-data">65535</td>
|
|
||||||
<td class="cell t-data">Dictionary</td>
|
|
||||||
<td class="cell t-data">End of file</td>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
</table>
|
|
||||||
<div
|
|
||||||
class="scrollContainer"
|
|
||||||
style="height: {bodyViewHeight}px"
|
|
||||||
onscroll={handleScroll}
|
|
||||||
bind:this={scrollContainer}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="container"
|
|
||||||
style="height: {totalBodyHeight - headerOffset}px"
|
|
||||||
>
|
>
|
||||||
<table>
|
<td class="cell t-data">Trailer</td>
|
||||||
<tbody>
|
<td class="cell t-data">65535</td>
|
||||||
<tr class="filler" style="height: {fillerHeight}px"
|
<td class="cell t-data">Dictionary</td>
|
||||||
></tr>
|
<td class="cell t-data">End of file</td>
|
||||||
{#each entriesToDisplay as entry}
|
</tr>
|
||||||
<tr
|
</thead>
|
||||||
class={selectedPath === entry.obj_num
|
</table>
|
||||||
? "bg-forge-acc"
|
<div
|
||||||
: "hover:bg-forge-sec"}
|
class="scrollContainer"
|
||||||
ondblclick={() => fState.selectXref(entry)}
|
style="height: {bodyViewHeight}px"
|
||||||
>
|
onscroll={handleScroll}
|
||||||
<td class="cell t-data">{entry.obj_num}</td>
|
bind:this={scrollContainer}
|
||||||
<td class="cell t-data">{entry.gen_num}</td>
|
>
|
||||||
<td class="cell t-data">{entry.obj_type}</td
|
<div class="container" style="height: {totalBodyHeight}px">
|
||||||
>
|
<table>
|
||||||
<td class="cell t-data">{entry.offset}</td>
|
<tbody>
|
||||||
</tr>
|
<tr class="filler" style="height: {fillerHeight}px"
|
||||||
{/each}
|
></tr>
|
||||||
</tbody>
|
{#each entriesToDisplay as entry}
|
||||||
</table>
|
<tr
|
||||||
</div>
|
class={selectedPath === entry.obj_num
|
||||||
|
? "bg-forge-acc"
|
||||||
|
: "hover:bg-forge-sec"}
|
||||||
|
ondblclick={() => fState.selectXref(entry)}
|
||||||
|
>
|
||||||
|
<td class="cell t-data">{entry.obj_num}</td>
|
||||||
|
<td class="cell t-data">{entry.gen_num}</td>
|
||||||
|
<td class="cell t-data">{entry.obj_type}</td>
|
||||||
|
<td class="cell t-data">{entry.offset}</td>
|
||||||
|
</tr>
|
||||||
|
{/each}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
10
src/events/PathSelectedEvent.ts
Normal file
10
src/events/PathSelectedEvent.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
export class PathSelectedEvent extends CustomEvent<{ path: string[] }> {
|
||||||
|
static readonly eventName = 'pathselected';
|
||||||
|
|
||||||
|
constructor(path: string[]) {
|
||||||
|
super(PathSelectedEvent.eventName, {
|
||||||
|
detail: { path },
|
||||||
|
bubbles: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -8,10 +8,9 @@ import type XRefTable from "./XRefTable";
|
|||||||
export default class FileViewState {
|
export default class FileViewState {
|
||||||
|
|
||||||
public path: string[] = $state(["Trailer"]);
|
public path: string[] = $state(["Trailer"]);
|
||||||
public treeRoot: TreeViewNode = $state(new TreeViewNode("Trailer", [new TreeViewNode("Root", [])]));
|
|
||||||
public file: PdfFile;
|
public file: PdfFile;
|
||||||
public prim: Primitive | undefined = $state();
|
public prim: Primitive | undefined = $state();
|
||||||
public treeView: Primitive | undefined = $state();
|
public highlightedPrim: Primitive | undefined = $state();
|
||||||
public xref_entries: XRefEntry[] = $state([]);
|
public xref_entries: XRefEntry[] = $state([]);
|
||||||
|
|
||||||
|
|
||||||
@ -19,7 +18,6 @@ export default class FileViewState {
|
|||||||
|
|
||||||
this.file = file;
|
this.file = file;
|
||||||
this.selectPath(this.path);
|
this.selectPath(this.path);
|
||||||
this.loadTreeView();
|
|
||||||
this.loadXrefEntries()
|
this.loadXrefEntries()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,83 +40,30 @@ export default class FileViewState {
|
|||||||
public selectPath(newPath: string[]) {
|
public selectPath(newPath: string[]) {
|
||||||
invoke<Primitive>("get_prim_by_path", { id: this.file.id, path: this.mergePaths(newPath) })
|
invoke<Primitive>("get_prim_by_path", { id: this.file.id, path: this.mergePaths(newPath) })
|
||||||
.then(result => {
|
.then(result => {
|
||||||
this.prim = new Primitive(result)
|
let _prim = new Primitive(result)
|
||||||
this.path = newPath
|
if (_prim.isContainer()) {
|
||||||
|
this.prim = _prim;
|
||||||
|
this.path = newPath
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
this.highlightedPrim = _prim;
|
||||||
|
this.selectPath(newPath.slice(0, newPath.length - 1))
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.catch(err => console.error(err));
|
.catch(err => console.error(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public loadTreeView() {
|
|
||||||
invoke<Primitive>("get_prim_tree_by_path", { id: this.file.id, path: this.treeRoot })
|
|
||||||
.then(result => {
|
|
||||||
this.treeView = new Primitive(result);
|
|
||||||
}
|
|
||||||
).catch(err => console.error(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
public getTreeRoot() {
|
public getTreeRoot() {
|
||||||
return this.treeRoot;
|
return this.treeState;
|
||||||
}
|
}
|
||||||
|
|
||||||
public expandTree(path: string[]) {
|
|
||||||
if (path.length == 0) {
|
|
||||||
console.error("Empty path")
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let node;
|
|
||||||
if (path[0] === "/") {
|
|
||||||
node = this.treeRoot;
|
|
||||||
} else {
|
|
||||||
console.error("Invalid Path " + path);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (let key of path.slice(1, path.length)) {
|
|
||||||
let _node: TreeViewNode | undefined = node.getChild(key)
|
|
||||||
if (_node) {
|
|
||||||
node = _node;
|
|
||||||
} else {
|
|
||||||
node = node.addChild(key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.loadTreeView();
|
|
||||||
}
|
|
||||||
|
|
||||||
public collapseTree(path: string[]) {
|
|
||||||
if (path.length == 0) {
|
|
||||||
console.error("Empty path")
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let node;
|
|
||||||
if (path[0] === "/") {
|
|
||||||
node = this.treeRoot;
|
|
||||||
} else {
|
|
||||||
console.error("Invalid Path " + path);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (path.length == 1) {
|
|
||||||
this.treeRoot.clearChildren();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (let key of path.slice(1, path.length - 1)) {
|
|
||||||
if (node) {
|
|
||||||
node = node.getChild(key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (node) {
|
|
||||||
node.removeChild(path[path.length - 1]);
|
|
||||||
}
|
|
||||||
this.loadTreeView()
|
|
||||||
}
|
|
||||||
|
|
||||||
public getMergedPath() {
|
public getMergedPath() {
|
||||||
return this.mergePaths(this.path);
|
return this.mergePaths(this.path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public displayPath() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public popPath() {
|
public popPath() {
|
||||||
let path = this.copyPath();
|
let path = this.copyPath();
|
||||||
if (path.length == 1) {
|
if (path.length == 1) {
|
||||||
|
|||||||
@ -27,7 +27,7 @@ export default class Primitive {
|
|||||||
return this.ptype === "Dictionary" || this.ptype === "Array" || this.ptype === "Reference" || this.ptype === "Stream";
|
return this.ptype === "Dictionary" || this.ptype === "Array" || this.ptype === "Reference" || this.ptype === "Stream";
|
||||||
}
|
}
|
||||||
|
|
||||||
public getTrace(): string[] {
|
public getPath(): string[] {
|
||||||
return this.trace.map(path => path.key);
|
return this.trace.map(path => path.key);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,7 +38,14 @@ export default class Primitive {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public isPage(): boolean {
|
public isPage(): boolean {
|
||||||
return this.trace[0].last_jump.startsWith("Page");
|
return this.trace[0].key.startsWith("Page") && !isNaN(+this.trace[0].key.replace("Page", ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
public getPageNumber(): number {
|
||||||
|
if (!this.isPage()) {
|
||||||
|
throw new Error("Primitive is not a page");
|
||||||
|
}
|
||||||
|
return +this.trace[0].key.replace("Page", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
public getFirstJump(): string | number | undefined {
|
public getFirstJump(): string | number | undefined {
|
||||||
|
|||||||
@ -10,6 +10,9 @@ export default class TreeViewNode {
|
|||||||
this.children = children;
|
this.children = children;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static TRAILER = new TreeViewNode("Trailer", [new TreeViewNode("Root", [])]);
|
||||||
|
|
||||||
|
|
||||||
public getChild(key: string) {
|
public getChild(key: string) {
|
||||||
return this.children.find(child => child.key === key);
|
return this.children.find(child => child.key === key);
|
||||||
}
|
}
|
||||||
|
|||||||
65
src/models/TreeViewState.svelte.ts
Normal file
65
src/models/TreeViewState.svelte.ts
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import { invoke } from "@tauri-apps/api/core";
|
||||||
|
import Primitive from "./Primitive.svelte";
|
||||||
|
import TreeViewNode from "./TreeViewNode.svelte";
|
||||||
|
import type FileViewState from "./FileViewState.svelte";
|
||||||
|
|
||||||
|
export default class TreeViewState {
|
||||||
|
public root: TreeViewNode = $state(new TreeViewNode("Trailer", [new TreeViewNode("Root", [])]));
|
||||||
|
public view: Primitive | undefined = $state();
|
||||||
|
file_id: string;
|
||||||
|
|
||||||
|
constructor(file_id: string, root: TreeViewNode) {
|
||||||
|
console.log("Creating tree view state", file_id, root);
|
||||||
|
this.file_id = file_id;
|
||||||
|
this.root = root;
|
||||||
|
this.loadTreeView();
|
||||||
|
}
|
||||||
|
|
||||||
|
public loadTreeView() {
|
||||||
|
console.log("Loading tree view", this.root);
|
||||||
|
invoke<Primitive>("get_prim_tree_by_path", {
|
||||||
|
id: this.file_id,
|
||||||
|
path: this.root,
|
||||||
|
})
|
||||||
|
.then((result) => {
|
||||||
|
this.view = new Primitive(result);
|
||||||
|
})
|
||||||
|
.catch((err) => console.error(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
public expandTree(path: string[]) {
|
||||||
|
if (path.length == 0) {
|
||||||
|
console.error("Empty path");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let node = this.root;
|
||||||
|
for (let key of path.slice(1, path.length)) {
|
||||||
|
let _node: TreeViewNode | undefined = node.getChild(key);
|
||||||
|
if (_node) {
|
||||||
|
node = _node;
|
||||||
|
} else {
|
||||||
|
node = node.addChild(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.loadTreeView();
|
||||||
|
}
|
||||||
|
|
||||||
|
public collapseTree(path: string[]) {
|
||||||
|
if (path.length == 0) {
|
||||||
|
console.error("Empty path");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (path.length == 1) {
|
||||||
|
this.root.clearChildren();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let node: TreeViewNode | undefined = this.root;
|
||||||
|
for (let key of path.slice(1, path.length - 1)) {
|
||||||
|
node = node?.getChild(key);
|
||||||
|
}
|
||||||
|
if (node) {
|
||||||
|
node.removeChild(path[path.length - 1]);
|
||||||
|
}
|
||||||
|
this.loadTreeView();
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user