Skip to content

Commit b7ae3c6

Browse files
committed
Merge remote-tracking branch 'ceets/focus_start' into develop
2 parents 493769b + 4ef9428 commit b7ae3c6

10 files changed

Lines changed: 206 additions & 25 deletions

File tree

dist/engine/core/monogatari.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/engine/core/monogatari.js.map

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/engine/debug/debug.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/engine/debug/debug.js.map

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/monogatari.module.js

Lines changed: 12 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/monogatari.module.js.map

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/monogatari.node.js

Lines changed: 12 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/monogatari.node.js.map

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/actions/Dialog.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Action } from './../lib/Action';
2-
import Typed from './../lib/vendor/typed.min.js';
2+
import Typed from './../lib/MonoTyped';
33
import { $_ } from '@aegis-framework/artemis/index';
44

55
export class Dialog extends Action {

src/lib/MonoTyped.js

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
export default class Typed {
2+
constructor (element, config) {
3+
config.typeSpeed = config.typeSpeed ?? 100;
4+
this.speed = config.typeSpeed; // use default type speed
5+
this.nextPause = null;
6+
this.config = config;
7+
this.timeout = null;
8+
9+
this.el = typeof element === 'string'
10+
? document.querySelector(element)
11+
: element;
12+
13+
this.nodeCounter = 0;
14+
this.setDisplay(this.el, config.strings[0]);
15+
this.spans = this.el.querySelectorAll('span');
16+
17+
// We only have one string per instance, so these callbacks are equivalent.
18+
this.config.onBegin(this);
19+
this.config.preStringTyped(0, this);
20+
21+
this.typewrite();
22+
}
23+
24+
get strings () {
25+
return this.config.strings;
26+
}
27+
28+
/**
29+
@param {HTMLElement} element
30+
@param {string} curString
31+
*/
32+
setDisplay (element, curString) {
33+
const newElement = document.createElement('div');
34+
newElement.innerHTML = curString;
35+
const textNodes = getLeafNodes(newElement);
36+
this.actions = [];
37+
for (const textNode of textNodes) {
38+
const [nodes, actions] = this.parseString(textNode.textContent);
39+
this.actions = this.actions.concat(...actions);
40+
41+
// overwrite the node with <span> text
42+
textNode.replaceWith(...nodes);
43+
}
44+
element.replaceChildren(...newElement.childNodes);
45+
}
46+
47+
stop () {
48+
clearTimeout(this.timeout);
49+
this.config.onStop(0, this);
50+
}
51+
52+
start () {
53+
if(!this.timeout) {
54+
this.typewrite();
55+
this.config.onStart(0, this);
56+
}
57+
}
58+
59+
parseString (curString) {
60+
61+
// Separate curString into text and action sections
62+
// eg: "{speed:10}hello {pause:1000}{speed:1000}world!"
63+
// -> [ '', '{speed:10}', 'hello ', '{pause:1000}', '', '{speed:1000}', 'world!' ]
64+
// `(?:<pattern>)` is a non-capturing group, see https://devdocs.io/javascript/regular_expressions/non-capturing_group
65+
const actionPattern = /(\{(?:pause|speed):\d+\})/;
66+
const sections = curString.split(actionPattern);
67+
68+
const nodes = [];
69+
const actions = [];
70+
let nodeCounter = 0;
71+
72+
sections.forEach((section, i) => {
73+
// text section
74+
if (i % 2 === 0) {
75+
// iterate over the string, adding <span>s to the element as we go
76+
for (const char of section) {
77+
const textNode = document.createTextNode(char);
78+
let node;
79+
const isWhite = /\s/.test(char);
80+
if (isWhite) {
81+
node = textNode;
82+
} else {
83+
nodeCounter++;
84+
node = document.createElement('span');
85+
node.append(textNode);
86+
node.style.visibility = 'hidden';
87+
}
88+
nodes.push(node);
89+
}
90+
91+
// action section
92+
} else {
93+
// extract action and parameter
94+
const match = /\{(?<action>pause|speed):(?<n>\d+)\}/.exec(section);
95+
actions[nodeCounter] = {
96+
action: match.groups.action,
97+
n: match.groups.n,
98+
};
99+
}
100+
});
101+
// Force length of 'actions' to equal nodeCounter
102+
actions[nodeCounter-1] = actions[nodeCounter-1];
103+
return [nodes, actions];
104+
}
105+
106+
executeAction (action) {
107+
if (action.action == 'speed') {
108+
this.speed = action.n; // overwrites speed value permanently
109+
} else if (action.action == 'pause') {
110+
this.config.onTypingPaused(0, this);
111+
this.nextPause = action.n; // sets a wait time temporarily
112+
}
113+
114+
}
115+
116+
typewrite () {
117+
if (this.actions[this.nodeCounter]) {
118+
this.executeAction(this.actions[this.nodeCounter]);
119+
}
120+
const waitTime = this.nextPause ?? this.speed;
121+
this.timeout = setTimeout(() => {
122+
if (this.nextPause) {
123+
this.nextPause = null;
124+
this.config.onTypingResumed(0, this);
125+
}
126+
this.spans[this.nodeCounter].style = '';
127+
this.nodeCounter += 1;
128+
if (this.nodeCounter < this.spans.length) {
129+
this.typewrite();
130+
} else {
131+
this.timeout = null;
132+
this.config.onStringTyped(0, this);
133+
}
134+
}, waitTime);
135+
}
136+
137+
destroy () {
138+
clearTimeout(this.timeout);
139+
this.timeout = null;
140+
this.el.replaceChildren();
141+
this.config.onDestroy(this);
142+
}
143+
}
144+
145+
function getLeafNodes (node) {
146+
const leafNodes = [];
147+
148+
function traverse (currentNode) {
149+
if (currentNode.childNodes.length === 0) {
150+
// It's a leaf node (no child nodes)
151+
leafNodes.push(currentNode);
152+
} else {
153+
// Recursively process child nodes
154+
currentNode.childNodes.forEach(child => traverse(child));
155+
}
156+
}
157+
158+
traverse(node);
159+
return leafNodes;
160+
}

0 commit comments

Comments
 (0)