squiffy-runtime 6.0.0-alpha.7 → 6.0.0-alpha.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -14,7 +14,7 @@ export interface SquiffyApi {
14
14
  restart: () => void;
15
15
  get: (attribute: string) => any;
16
16
  set: (attribute: string, value: any) => void;
17
- clickLink: (link: HTMLElement) => void;
17
+ clickLink: (link: HTMLElement) => boolean;
18
18
  update: (story: Story) => void;
19
19
  }
20
20
  interface SquiffyJsFunctionApi {
@@ -31,8 +31,11 @@ export const init = (options) => {
31
31
  return JSON.parse(result);
32
32
  }
33
33
  function handleLink(link) {
34
+ const outputSection = link.closest('.squiffy-output-section');
35
+ if (outputSection !== currentSectionElement)
36
+ return false;
34
37
  if (link.classList.contains('disabled'))
35
- return;
38
+ return false;
36
39
  let passage = link.getAttribute('data-passage');
37
40
  let section = link.getAttribute('data-section');
38
41
  const rotateAttr = link.getAttribute('data-rotate');
@@ -55,15 +58,16 @@ export const init = (options) => {
55
58
  showPassage('@last');
56
59
  }
57
60
  }
61
+ return true;
58
62
  }
59
- else if (section) {
60
- disableLink(link);
63
+ if (section) {
61
64
  section = processLink(section);
62
65
  if (section) {
63
66
  go(section);
64
67
  }
68
+ return true;
65
69
  }
66
- else if (rotateOrSequenceAttr) {
70
+ if (rotateOrSequenceAttr) {
67
71
  const result = rotate(rotateOrSequenceAttr, rotateAttr ? link.innerText : '');
68
72
  link.innerHTML = result[0].replace(/"/g, '"').replace(/'/g, '\'');
69
73
  const dataAttribute = rotateAttr ? 'data-rotate' : 'data-sequence';
@@ -76,7 +80,9 @@ export const init = (options) => {
76
80
  set(attribute, result[0]);
77
81
  }
78
82
  save();
83
+ return true;
79
84
  }
85
+ return false;
80
86
  }
81
87
  function handleClick(event) {
82
88
  const target = event.target;
@@ -88,9 +94,6 @@ export const init = (options) => {
88
94
  link.classList.add('disabled');
89
95
  link.setAttribute('tabindex', '-1');
90
96
  }
91
- function disableLinks(links) {
92
- links.forEach(disableLink);
93
- }
94
97
  function begin() {
95
98
  if (!load()) {
96
99
  go(story.start);
@@ -336,7 +339,6 @@ export const init = (options) => {
336
339
  }
337
340
  function newSection(sectionName) {
338
341
  if (currentSectionElement) {
339
- disableLinks(currentSectionElement.querySelectorAll('.squiffy-link'));
340
342
  currentSectionElement.querySelectorAll('input').forEach(el => {
341
343
  const attribute = el.getAttribute('data-attribute') || el.id;
342
344
  if (attribute)
@@ -591,6 +593,7 @@ export const init = (options) => {
591
593
  }
592
594
  function update(newStory) {
593
595
  // TODO: Re-disable clicked links after update
596
+ // TODO: Delete empty output blocks
594
597
  for (const existingSection of Object.keys(story.sections)) {
595
598
  const elements = getSectionContent(existingSection);
596
599
  if (elements.length) {
package/package.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "squiffy-runtime",
3
- "version": "6.0.0-alpha.7",
3
+ "version": "6.0.0-alpha.8",
4
4
  "main": "dist/squiffy.runtime.js",
5
5
  "types": "dist/squiffy.runtime.d.ts",
6
6
  "scripts": {
7
+ "dev": "vitest",
7
8
  "test": "vitest --run",
8
9
  "build": "tsc",
9
10
  "prepublishOnly": "npm run build && npm run test"
@@ -45,12 +45,12 @@ exports[`Click a section link 2`] = `
45
45
  "
46
46
  <div class="squiffy-output-section" id="squiffy-section-1" data-section="Introduction"><div class="squiffy-output-block"><div data-source="[[Introduction]]"><h1>Squiffy Test</h1>
47
47
  <p>This is <a href="http://textadventures.co.uk">a website link</a>.</p>
48
- <p>This should be <a class="squiffy-link link-passage disabled" data-passage="passage" role="link" tabindex="-1">a link to a passage</a>. Here's <a class="squiffy-link link-passage disabled" data-passage="passage2" role="link" tabindex="-1">another one</a>.</p>
49
- <p>You don't need to specify a name - for example, this <a class="squiffy-link link-passage disabled" data-passage="link" role="link" tabindex="-1">link</a> and this <a class="squiffy-link link-section disabled" data-section="section" role="link" tabindex="-1">section</a>.</p>
50
- <p>And this goes to the <a class="squiffy-link link-section disabled" data-section="section2" role="link" tabindex="-1">next section</a>.</p>
51
- <p>This line has links to <a class="squiffy-link link-section disabled" data-section="section 3" role="link" tabindex="-1">section 3</a> and <a class="squiffy-link link-section disabled" data-section="section four" role="link" tabindex="-1">section 4</a>.</p>
52
- <p>This line has links to <a class="squiffy-link link-passage disabled" data-passage="passage 3" role="link" tabindex="-1">passage 3</a> and <a class="squiffy-link link-passage disabled" data-passage="passage four" role="link" tabindex="-1">passage 4</a>.</p>
53
- <p>Oh look - <a class="squiffy-link link-passage disabled" data-passage="it's a passage with an apostrophe" role="link" tabindex="-1">it's a passage with an apostrophe</a>.</p></div></div></div><div class="squiffy-output-section" id="squiffy-section-2" data-section="section 3"><div class="squiffy-output-block"><div data-source="[[section 3]]"><p>Another section is here.</p></div></div></div>"
48
+ <p>This should be <a class="squiffy-link link-passage" data-passage="passage" role="link" tabindex="0">a link to a passage</a>. Here's <a class="squiffy-link link-passage" data-passage="passage2" role="link" tabindex="0">another one</a>.</p>
49
+ <p>You don't need to specify a name - for example, this <a class="squiffy-link link-passage" data-passage="link" role="link" tabindex="0">link</a> and this <a class="squiffy-link link-section" data-section="section" role="link" tabindex="0">section</a>.</p>
50
+ <p>And this goes to the <a class="squiffy-link link-section" data-section="section2" role="link" tabindex="0">next section</a>.</p>
51
+ <p>This line has links to <a class="squiffy-link link-section" data-section="section 3" role="link" tabindex="0">section 3</a> and <a class="squiffy-link link-section" data-section="section four" role="link" tabindex="0">section 4</a>.</p>
52
+ <p>This line has links to <a class="squiffy-link link-passage" data-passage="passage 3" role="link" tabindex="0">passage 3</a> and <a class="squiffy-link link-passage" data-passage="passage four" role="link" tabindex="0">passage 4</a>.</p>
53
+ <p>Oh look - <a class="squiffy-link link-passage" data-passage="it's a passage with an apostrophe" role="link" tabindex="0">it's a passage with an apostrophe</a>.</p></div></div></div><div class="squiffy-output-section" id="squiffy-section-2" data-section="section 3"><div class="squiffy-output-block"><div data-source="[[section 3]]"><p>Another section is here, with passages <a class="squiffy-link link-passage" data-passage="a" role="link" tabindex="0">a</a> and <a class="squiffy-link link-passage" data-passage="b" role="link" tabindex="0">b</a>.</p></div></div></div>"
54
54
  `;
55
55
 
56
56
  exports[`Delete passage 1`] = `
@@ -65,12 +65,12 @@ exports[`Delete passage 2`] = `
65
65
 
66
66
  exports[`Delete section 1`] = `
67
67
  "
68
- <div class="squiffy-output-section" id="squiffy-section-1" data-section="_default"><div class="squiffy-output-block"><div data-source="[[_default]]"><p>Click this: <a class="squiffy-link link-section disabled" data-section="a" role="link" tabindex="-1">a</a></p></div></div></div><div class="squiffy-output-section" id="squiffy-section-2" data-section="a"><div class="squiffy-output-block"><div data-source="[[a]]"><p>New section</p></div></div></div>"
68
+ <div class="squiffy-output-section" id="squiffy-section-1" data-section="_default"><div class="squiffy-output-block"><div data-source="[[_default]]"><p>Click this: <a class="squiffy-link link-section" data-section="a" role="link" tabindex="0">a</a></p></div></div></div><div class="squiffy-output-section" id="squiffy-section-2" data-section="a"><div class="squiffy-output-block"><div data-source="[[a]]"><p>New section</p></div></div></div>"
69
69
  `;
70
70
 
71
71
  exports[`Delete section 2`] = `
72
72
  "
73
- <div class="squiffy-output-section" id="squiffy-section-1" data-section="_default"><div class="squiffy-output-block"><div data-source="[[_default]]"><p>Click this: <a class="squiffy-link link-section disabled" data-section="a" role="link" tabindex="-1">a</a></p></div></div></div><div class="squiffy-output-section" id="squiffy-section-2" data-section="a"><div class="squiffy-output-block"></div></div>"
73
+ <div class="squiffy-output-section" id="squiffy-section-1" data-section="_default"><div class="squiffy-output-block"><div data-source="[[_default]]"><p>Click this: <a class="squiffy-link link-section" data-section="a" role="link" tabindex="0">a</a></p></div></div></div><div class="squiffy-output-section" id="squiffy-section-2" data-section="a"><div class="squiffy-output-block"></div></div>"
74
74
  `;
75
75
 
76
76
  exports[`Update default section output 1`] = `
@@ -61,7 +61,7 @@ const initScript = async (script: string) => {
61
61
  };
62
62
 
63
63
  const findLink = (element: HTMLElement, linkType: string, linkText: string, onlyEnabled: boolean = false) => {
64
- const links = element.querySelectorAll(`a.squiffy-link.link-${linkType}`);
64
+ const links = element.querySelectorAll(`.squiffy-output-section:last-child a.squiffy-link.link-${linkType}`);
65
65
  return Array.from(links).find(link => link.textContent === linkText && (onlyEnabled ? !link.classList.contains("disabled") : true)) as HTMLElement;
66
66
  };
67
67
 
@@ -100,13 +100,14 @@ test('Click a section link', async () => {
100
100
  expect(linkToPassage).not.toBeNull();
101
101
  expect(section3Link).not.toBeNull();
102
102
  expect(linkToPassage.classList).not.toContain('disabled');
103
- expect(section3Link.classList).not.toContain('disabled');
104
103
 
105
- squiffyApi.clickLink(section3Link);
104
+ const handled = squiffyApi.clickLink(section3Link);
105
+ expect(handled).toBe(true);
106
106
 
107
- expect(linkToPassage.classList).toContain('disabled');
108
- expect(section3Link.classList).toContain('disabled');
109
107
  expect(element.innerHTML).toMatchSnapshot();
108
+
109
+ // passage link is from the previous section, so should be unclickable
110
+ expect(squiffyApi.clickLink(linkToPassage)).toBe(false);
110
111
  });
111
112
 
112
113
  test('Click a passage link', async () => {
@@ -121,13 +122,15 @@ test('Click a passage link', async () => {
121
122
  expect(linkToPassage).not.toBeNull();
122
123
  expect(section3Link).not.toBeNull();
123
124
  expect(linkToPassage.classList).not.toContain('disabled');
124
- expect(section3Link.classList).not.toContain('disabled');
125
125
 
126
- squiffyApi.clickLink(linkToPassage);
126
+ const handled = squiffyApi.clickLink(linkToPassage);
127
+ expect(handled).toBe(true);
127
128
 
128
129
  expect(linkToPassage.classList).toContain('disabled');
129
- expect(section3Link.classList).not.toContain('disabled');
130
130
  expect(element.innerHTML).toMatchSnapshot();
131
+
132
+ // shouldn't be able to click it again
133
+ expect(squiffyApi.clickLink(linkToPassage)).toBe(false);
131
134
  });
132
135
 
133
136
  test('Run JavaScript functions', async () => {
@@ -156,7 +159,8 @@ test('Run JavaScript functions', async () => {
156
159
  const clickContinue = () => {
157
160
  const continueLink = findLink(element, 'section', 'Continue...', true);
158
161
  expect(continueLink).not.toBeNull();
159
- squiffyApi.clickLink(continueLink);
162
+ const handled = squiffyApi.clickLink(continueLink);
163
+ expect(handled).toBe(true);
160
164
  };
161
165
 
162
166
  const { squiffyApi, element } = await initScript(script);
@@ -208,7 +212,8 @@ test('Update passage output', async () => {
208
212
  Passage a content`);
209
213
 
210
214
  const link = findLink(element, 'passage', 'a');
211
- squiffyApi.clickLink(link);
215
+ const handled = squiffyApi.clickLink(link);
216
+ expect(handled).toBe(true);
212
217
 
213
218
  let defaultOutput = getSectionContent(element, '_default');
214
219
  expect(defaultOutput).toBe('Click this: a');
@@ -238,7 +243,8 @@ test('Delete section', async () => {
238
243
  New section`);
239
244
 
240
245
  const link = findLink(element, 'section', 'a');
241
- squiffyApi.clickLink(link);
246
+ const handled = squiffyApi.clickLink(link);
247
+ expect(handled).toBe(true);
242
248
 
243
249
  let defaultOutput = getSectionContent(element, '_default');
244
250
  expect(defaultOutput).toBe('Click this: a');
@@ -265,7 +271,8 @@ test('Delete passage', async () => {
265
271
  New passage`);
266
272
 
267
273
  const link = findLink(element, 'passage', 'a');
268
- squiffyApi.clickLink(link);
274
+ const handled = squiffyApi.clickLink(link);
275
+ expect(handled).toBe(true);
269
276
 
270
277
  let defaultOutput = getSectionContent(element, '_default');
271
278
  expect(defaultOutput).toBe('Click this: a');
@@ -16,7 +16,7 @@ export interface SquiffyApi {
16
16
  restart: () => void;
17
17
  get: (attribute: string) => any;
18
18
  set: (attribute: string, value: any) => void;
19
- clickLink: (link: HTMLElement) => void;
19
+ clickLink: (link: HTMLElement) => boolean;
20
20
  update: (story: Story) => void;
21
21
  }
22
22
 
@@ -93,8 +93,12 @@ export const init = (options: SquiffyInitOptions): SquiffyApi => {
93
93
  return JSON.parse(result);
94
94
  }
95
95
 
96
- function handleLink(link: HTMLElement) {
97
- if (link.classList.contains('disabled')) return;
96
+ function handleLink(link: HTMLElement): boolean {
97
+ const outputSection = link.closest('.squiffy-output-section');
98
+ if (outputSection !== currentSectionElement) return false;
99
+
100
+ if (link.classList.contains('disabled')) return false;
101
+
98
102
  let passage = link.getAttribute('data-passage');
99
103
  let section = link.getAttribute('data-section');
100
104
  const rotateAttr = link.getAttribute('data-rotate');
@@ -117,15 +121,20 @@ export const init = (options: SquiffyInitOptions): SquiffyApi => {
117
121
  showPassage('@last');
118
122
  }
119
123
  }
124
+
125
+ return true;
120
126
  }
121
- else if (section) {
122
- disableLink(link);
127
+
128
+ if (section) {
123
129
  section = processLink(section);
124
130
  if (section) {
125
131
  go(section);
126
132
  }
133
+
134
+ return true;
127
135
  }
128
- else if (rotateOrSequenceAttr) {
136
+
137
+ if (rotateOrSequenceAttr) {
129
138
  const result = rotate(rotateOrSequenceAttr, rotateAttr ? link.innerText : '');
130
139
  link.innerHTML = result[0]!.replace(/&quot;/g, '"').replace(/&#39;/g, '\'');
131
140
  const dataAttribute = rotateAttr ? 'data-rotate' : 'data-sequence';
@@ -138,7 +147,11 @@ export const init = (options: SquiffyInitOptions): SquiffyApi => {
138
147
  set(attribute, result[0]);
139
148
  }
140
149
  save();
150
+
151
+ return true;
141
152
  }
153
+
154
+ return false;
142
155
  }
143
156
 
144
157
  function handleClick(event: Event) {
@@ -153,10 +166,6 @@ export const init = (options: SquiffyInitOptions): SquiffyApi => {
153
166
  link.setAttribute('tabindex', '-1');
154
167
  }
155
168
 
156
- function disableLinks(links: NodeListOf<Element>) {
157
- links.forEach(disableLink);
158
- }
159
-
160
169
  function begin() {
161
170
  if (!load()) {
162
171
  go(story.start);
@@ -412,7 +421,6 @@ export const init = (options: SquiffyInitOptions): SquiffyApi => {
412
421
 
413
422
  function newSection(sectionName: string | null) {
414
423
  if (currentSectionElement) {
415
- disableLinks(currentSectionElement.querySelectorAll('.squiffy-link'));
416
424
  currentSectionElement.querySelectorAll('input').forEach(el => {
417
425
  const attribute = el.getAttribute('data-attribute') || el.id;
418
426
  if (attribute) set(attribute, el.value);
@@ -685,6 +693,7 @@ export const init = (options: SquiffyInitOptions): SquiffyApi => {
685
693
 
686
694
  function update(newStory: Story) {
687
695
  // TODO: Re-disable clicked links after update
696
+ // TODO: Delete empty output blocks
688
697
 
689
698
  for (const existingSection of Object.keys(story.sections)) {
690
699
  const elements = getSectionContent(existingSection);