Skip to content

Commit

Permalink
Added linearize story feature to editor
Browse files Browse the repository at this point in the history
  • Loading branch information
Echsecutor committed Nov 30, 2024
1 parent 3752425 commit 9b76be0
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 21 deletions.
21 changes: 21 additions & 0 deletions commons/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,24 @@ export function create_element_with_classes_and_attributes(
}
return element;
}

export function replace_variables(text, variables) {
if (!variables || !text) {
return text;
}
var re = text;
for (const key in variables) {
re = re.replaceAll("${" + key + "}", variables[key]);
}
return re;
}

export function get_text_from_section(section, variables){
let text = "";
if (section?.text_lines) {
text = section.text_lines.join("\n");
} else if (section?.text) {
text = section.text;
}
return replace_variables(text, variables);
}
108 changes: 107 additions & 1 deletion editor/code.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ cytoscape.use(cytoscapeKlay);

import { toast_alert, toast_ok } from "./toast.js";
import { supported_actions } from "./common.js";
import { create_element_with_classes_and_attributes } from "./utils.js";
import {
create_element_with_classes_and_attributes,
get_text_from_section,
} from "./utils.js";

const data_url_regexp = /^data:image\/([a-z]*);base64,(.*)$/;

Expand Down Expand Up @@ -925,6 +928,10 @@ document
.getElementById("redraw_button")
.addEventListener("click", redraw_adventure_graph);

document
.getElementById("linearize_button")
.addEventListener("click", create_linear_story);

document.addEventListener("keydown", handle_global_key_down);

async function load_example() {
Expand All @@ -940,6 +947,105 @@ async function load_example() {
}
}

function create_linear_story() {
const start_at = prompt("Start at section:", "1");
if (!start_at) {
return;
}
const end_at = prompt("Finish at section:");
if (!end_at) {
return;
}
const passing_through = [];
var passing = prompt(
"Add section to pass through list (leave empty to finish):"
);
while (passing) {
passing_through.push(passing);
passing = prompt(
"Add section to pass through list (leave empty to finish):"
);
}
toast_ok("Generating linear story...");
console.debug(
"Creating linearized story from",
start_at,
"to",
end_at,
"passing_through",
passing_through
);
const linearized_history = depth_first_search(
[start_at],
end_at,
passing_through
);
console.debug("linearized_history", linearized_history);
toast_ok("Found a linear story. Generating Markdown...");

const markdown = markdown_from_section_id_list(linearized_history);

trigger_data_dl(
"data:text/plain;charset=utf-8," + encodeURIComponent(markdown),
get_file_safe_title() + ".md"
);
}

function markdown_from_section_id_list(section_ids) {
let md = "";
for (const id of section_ids) {
console.debug("adding section to markdown", id);
md += get_text_from_section(story.sections?.[id], story?.state?.variables);
md += "\n\n";
if (story.sections?.[id]?.media?.src) {
md += "![](" + story.sections?.[id]?.media?.src + ")\n\n";
}
}
return md;
}

function depth_first_search(linearized_history, end_at, passing_through) {
if (linearized_history[linearized_history.length - 1] == end_at) {
console.debug("dfs reached target", end_at);
if (passing_through) {
for (const passing of passing_through) {
if (!linearized_history.includes(passing)) {
console.debug(linearized_history, "not passing through", passing);
return null;
}
}
}
console.debug(
linearized_history,
"is passing through all of",
passing_through
);
return linearized_history;
}
const current_section_id = linearized_history[linearized_history.length - 1];
const current_section = story.sections[current_section_id];
if (!current_section) {
toast_alert("No section " + current_section_id);
return null;
}
if (!current_section.next) {
console.debug("Dead end", current_section_id);
return null;
}
for (const next of current_section.next) {
const found_path = depth_first_search(
[...linearized_history, next.next],
end_at,
passing_through
);
if (found_path) {
return found_path;
}
}
console.debug("No continuation possible for", linearized_history);
return null;
}

function on_load() {
redraw_adventure_graph();
load_variables_menu();
Expand Down
1 change: 1 addition & 0 deletions editor/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
<li><a class="dropdown-item" id="load_button" href="#">Load Adventure</a></li>
<li><a class="dropdown-item" id="download_in_one_button" href="#">Save Adventure in one file</a></li>
<li><a class="dropdown-item" id="download_split_button" href="#">Save Adventure text and pictures separately</a></li>
<li><a class="dropdown-item" id="linearize_button" href="#">Create Linear Story</a></li>
</ul>
</li>
<li class="nav-item dropdown">
Expand Down
23 changes: 3 additions & 20 deletions viewer/code.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { toast_alert, toast_ok } from "./toast.js";
import { marked } from "./marked.esm.js";
import DOMPurify from "./purify.es.mjs";
import { supported_actions } from "./common.js";
import { replace_variables, get_text_from_section } from "./utils.js";

var story = {};

Expand Down Expand Up @@ -113,17 +114,6 @@ function start_playing() {
show_ui_components_according_to_state();
}

function replace_variables(text, variables) {
if (!variables || !text) {
return text;
}
var re = text;
for (const key in variables) {
re = re.replaceAll("${" + key + "}", variables[key]);
}
return re;
}

function execute_actions(script) {
for (const action of script) {
if (!(action.action in supported_actions)) {
Expand Down Expand Up @@ -156,18 +146,11 @@ function load_section(id, add_current_section_to_history = true) {
execute_actions(section.script);
}

let text = "";
if (section?.text_lines) {
text = section.text_lines.join("\n");
} else if (section?.text) {
text = section.text;
}
const text = get_text_from_section(section, story.state?.variables)

if (!text) {
toast_alert("This section has no text");
}

text = replace_variables(text, story.state?.variables);

story_text.innerHTML = DOMPurify.sanitize(marked.parse(text));

if (section?.media?.type === "image" && section?.media?.src) {
Expand Down
1 change: 1 addition & 0 deletions viewer/utils.js

0 comments on commit 9b76be0

Please sign in to comment.