@thoughtbot/superglue 0.53.4 → 0.54.0

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.
@@ -0,0 +1,779 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __export = (target, all) => {
3
+ for (var name in all)
4
+ __defProp(target, name, { get: all[name], enumerable: true });
5
+ };
6
+
7
+ // lib/utils/url.ts
8
+ import parse from "url-parse";
9
+ function pathQuery(url) {
10
+ const { pathname, query } = new parse(url, {});
11
+ return pathname + query;
12
+ }
13
+ function pathQueryHash(url) {
14
+ const { pathname, query, hash } = new parse(url, {});
15
+ return pathname + query + hash;
16
+ }
17
+ function hasPropsAt(url) {
18
+ const parsed = new parse(url, {}, true);
19
+ const query = parsed.query;
20
+ return !!query["props_at"];
21
+ }
22
+ function withFormatJson(url) {
23
+ const parsed = new parse(url, {}, true);
24
+ parsed.query["format"] = "json";
25
+ return parsed.toString();
26
+ }
27
+ function pathWithoutBZParams(url) {
28
+ const parsed = new parse(url, {}, true);
29
+ const query = parsed.query;
30
+ delete query["props_at"];
31
+ delete query["format"];
32
+ parsed.set("query", query);
33
+ return pathQueryHash(parsed.toString());
34
+ }
35
+ function removePropsAt(url) {
36
+ const parsed = new parse(url, {}, true);
37
+ const query = parsed.query;
38
+ delete query["props_at"];
39
+ parsed.set("query", query);
40
+ return parsed.toString();
41
+ }
42
+ function urlToPageKey(url) {
43
+ const parsed = new parse(url, {}, true);
44
+ const query = parsed.query;
45
+ delete query["props_at"];
46
+ delete query["format"];
47
+ parsed.set("query", query);
48
+ return pathQuery(parsed.toString());
49
+ }
50
+ function withoutHash(url) {
51
+ const parsed = new parse(url, {}, true);
52
+ parsed.set("hash", "");
53
+ return parsed.toString();
54
+ }
55
+ function withoutBusters(url) {
56
+ const parsed = new parse(url, {}, true);
57
+ const query = parsed.query;
58
+ delete query["format"];
59
+ parsed.set("query", query);
60
+ return pathQuery(parsed.toString());
61
+ }
62
+ function formatForXHR(url) {
63
+ const formats = [withoutHash, withFormatJson];
64
+ return formats.reduce((memo, f) => f(memo), url);
65
+ }
66
+
67
+ // lib/utils/helpers.ts
68
+ function argsForHistory(path) {
69
+ const pageKey = urlToPageKey(path);
70
+ return [
71
+ path,
72
+ {
73
+ superglue: true,
74
+ pageKey,
75
+ posX: 0,
76
+ posY: 0
77
+ }
78
+ ];
79
+ }
80
+
81
+ // lib/utils/immutability.ts
82
+ var canLookAhead = /^[\da-zA-Z\-_]+=[\da-zA-Z\-_]+$/;
83
+ var KeyPathError = class extends Error {
84
+ constructor(message) {
85
+ super(message);
86
+ this.name = "KeyPathError";
87
+ }
88
+ };
89
+ function getIn(node, path) {
90
+ const keyPath = normalizeKeyPath(path);
91
+ let result = node;
92
+ let i;
93
+ for (i = 0; i < keyPath.length; i++) {
94
+ const key = keyPath[i];
95
+ if (typeof result === "object" && result !== null) {
96
+ if (!Array.isArray(result) && canLookAhead.test(key)) {
97
+ throw new KeyPathError(
98
+ `Expected to find an Array when using the key: ${key}`
99
+ );
100
+ }
101
+ result = atKey(result, key);
102
+ } else {
103
+ throw new KeyPathError(
104
+ `Expected to traverse an Array or Obj, got ${JSON.stringify(result)}`
105
+ );
106
+ }
107
+ }
108
+ if (i === keyPath.length) {
109
+ return result;
110
+ } else {
111
+ return void 0;
112
+ }
113
+ }
114
+ function clone(node) {
115
+ return Array.isArray(node) ? [].slice.call(node) : { ...node };
116
+ }
117
+ function getKey(node, key) {
118
+ if (Array.isArray(node) && Number.isNaN(Number(key))) {
119
+ const key_parts = Array.from(key.split("="));
120
+ const attr = key_parts[0];
121
+ const id = key_parts[1];
122
+ if (!id || !attr) {
123
+ return key;
124
+ }
125
+ let i;
126
+ let child;
127
+ for (i = 0; i < node.length; i++) {
128
+ child = node[i];
129
+ if (typeof child === "object" && !Array.isArray(child) && child !== null) {
130
+ const val = child[attr];
131
+ if (val && val.toString() === id) {
132
+ break;
133
+ }
134
+ } else {
135
+ throw new KeyPathError(`Could not look ahead ${key} at ${child}`);
136
+ }
137
+ }
138
+ if (i === node.length) {
139
+ throw new KeyPathError(`Could not find ${key} while looking ahead`);
140
+ }
141
+ return i;
142
+ } else {
143
+ return key;
144
+ }
145
+ }
146
+ function atKey(node, key) {
147
+ const actualKey = getKey(node, key);
148
+ if (Array.isArray(node)) {
149
+ return node[actualKey];
150
+ } else {
151
+ return node[actualKey];
152
+ }
153
+ }
154
+ function normalizeKeyPath(path) {
155
+ if (typeof path === "string") {
156
+ path = path.replace(/ /g, "");
157
+ if (path === "") {
158
+ return [];
159
+ }
160
+ return path.split(".");
161
+ } else {
162
+ return path;
163
+ }
164
+ }
165
+ function setIn(object, path, value) {
166
+ const keypath = normalizeKeyPath(path);
167
+ const results = { 0: object };
168
+ const parents = { 0: object };
169
+ let i;
170
+ for (i = 0; i < keypath.length; i++) {
171
+ const parent = parents[i];
172
+ if (!(typeof parent === "object" && parent !== null)) {
173
+ throw new KeyPathError(
174
+ `Expected to traverse an Array or Obj, got ${JSON.stringify(parent)}`
175
+ );
176
+ }
177
+ const child = atKey(parent, keypath[i]);
178
+ parents[i + 1] = child;
179
+ }
180
+ results[keypath.length] = value;
181
+ for (i = keypath.length - 1; i >= 0; i--) {
182
+ const target = clone(parents[i]);
183
+ results[i] = target;
184
+ const key = getKey(results[i], keypath[i]);
185
+ if (Array.isArray(target)) {
186
+ target[key] = results[i + 1];
187
+ } else {
188
+ target[key] = results[i + 1];
189
+ }
190
+ }
191
+ return results[0];
192
+ }
193
+
194
+ // lib/utils/react.ts
195
+ function mapStateToProps(state, ownProps) {
196
+ let pageKey = ownProps.pageKey;
197
+ const params = ownProps;
198
+ const csrfToken = state.superglue.csrfToken;
199
+ pageKey = urlToPageKey(pageKey);
200
+ const { data, fragments } = state.pages[pageKey] || {
201
+ data: {},
202
+ fragments: []
203
+ };
204
+ return { ...data, ...params, pageKey, csrfToken, fragments };
205
+ }
206
+ var mapDispatchToProps = {
207
+ saveAndProcessPage,
208
+ copyPage
209
+ };
210
+
211
+ // lib/utils/request.ts
212
+ import parse2 from "url-parse";
213
+
214
+ // lib/config.ts
215
+ var config = {
216
+ baseUrl: "",
217
+ maxPages: 20
218
+ };
219
+
220
+ // lib/utils/request.ts
221
+ function isValidResponse(xhr) {
222
+ return isValidContent(xhr) && !downloadingFile(xhr);
223
+ }
224
+ function isValidContent(rsp) {
225
+ const contentType = rsp.headers.get("content-type");
226
+ const jsContent = /^(?:application\/json)(?:;|$)/;
227
+ return !!(contentType && contentType.match(jsContent));
228
+ }
229
+ function downloadingFile(xhr) {
230
+ const disposition = xhr.headers.get("content-disposition");
231
+ return !!(disposition && disposition.match(/^attachment/) !== null);
232
+ }
233
+ var SuperglueResponseError = class extends Error {
234
+ constructor(message) {
235
+ super(message);
236
+ this.name = "SuperglueResponseError";
237
+ }
238
+ };
239
+ function validateResponse(args) {
240
+ const { rsp } = args;
241
+ if (isValidResponse(rsp)) {
242
+ return args;
243
+ } else {
244
+ const error = new SuperglueResponseError("Invalid Superglue Response");
245
+ error.response = rsp;
246
+ throw error;
247
+ }
248
+ }
249
+ function handleServerErrors(args) {
250
+ const { rsp } = args;
251
+ if (!rsp.ok) {
252
+ if (rsp.status === 406) {
253
+ console.error(
254
+ "Superglue encountered a 406 Not Acceptable response. This can happen if you used respond_to and didn't specify format.json in the block. Try adding it to your respond_to. For example:\n\nrespond_to do |format|\n format.html\n format.json\n format.csv\nend"
255
+ );
256
+ }
257
+ const error = new SuperglueResponseError(rsp.statusText);
258
+ error.response = rsp;
259
+ throw error;
260
+ }
261
+ return args;
262
+ }
263
+ function argsForFetch(getState, pathQuery2, { method = "GET", headers = {}, body = "", signal } = {}) {
264
+ method = method.toUpperCase();
265
+ const currentState = getState().superglue;
266
+ const nextHeaders = { ...headers };
267
+ nextHeaders["x-requested-with"] = "XMLHttpRequest";
268
+ nextHeaders["accept"] = "application/json";
269
+ nextHeaders["x-superglue-request"] = "true";
270
+ if (method != "GET" && method != "HEAD") {
271
+ nextHeaders["content-type"] = "application/json";
272
+ }
273
+ if (body instanceof FormData) {
274
+ delete nextHeaders["content-type"];
275
+ }
276
+ if (currentState.csrfToken) {
277
+ nextHeaders["x-csrf-token"] = currentState.csrfToken;
278
+ }
279
+ const fetchPath = new parse2(
280
+ formatForXHR(pathQuery2),
281
+ config.baseUrl || {},
282
+ true
283
+ );
284
+ const credentials = "same-origin";
285
+ if (!(method == "GET" || method == "HEAD")) {
286
+ nextHeaders["x-http-method-override"] = method;
287
+ method = "POST";
288
+ }
289
+ const options = {
290
+ method,
291
+ headers: nextHeaders,
292
+ body,
293
+ credentials,
294
+ signal
295
+ };
296
+ if (currentState.currentPageKey) {
297
+ const referrer = new parse2(
298
+ currentState.currentPageKey,
299
+ config.baseUrl || {},
300
+ false
301
+ ).href;
302
+ options.referrer = referrer;
303
+ }
304
+ if (method == "GET" || method == "HEAD") {
305
+ if (options.body instanceof FormData) {
306
+ const allData = new URLSearchParams(
307
+ options.body
308
+ );
309
+ const nextQuery = { ...fetchPath.query, ...Object.fromEntries(allData) };
310
+ fetchPath.set("query", nextQuery);
311
+ }
312
+ delete options.body;
313
+ }
314
+ return [fetchPath.toString(), options];
315
+ }
316
+ function extractJSON(rsp) {
317
+ return rsp.json().then((json) => {
318
+ return { rsp, json };
319
+ }).catch((e) => {
320
+ e.response = rsp;
321
+ throw e;
322
+ });
323
+ }
324
+ function parseResponse(prm) {
325
+ return Promise.resolve(prm).then(extractJSON).then(handleServerErrors).then(validateResponse);
326
+ }
327
+
328
+ // lib/utils/ujs.ts
329
+ var HandlerBuilder = class {
330
+ constructor({
331
+ ujsAttributePrefix,
332
+ visit: visit2,
333
+ remote: remote2
334
+ }) {
335
+ this.attributePrefix = ujsAttributePrefix;
336
+ this.isUJS = this.isUJS.bind(this);
337
+ this.handleSubmit = this.handleSubmit.bind(this);
338
+ this.handleClick = this.handleClick.bind(this);
339
+ this.visit = visit2;
340
+ this.remote = remote2;
341
+ this.visitOrRemote = this.visitOrRemote.bind(this);
342
+ }
343
+ retrieveLink(target) {
344
+ const link = target.closest("a");
345
+ if (link && link.href.length !== 0) {
346
+ return link;
347
+ }
348
+ }
349
+ isNonStandardClick(event) {
350
+ return event.which > 1 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey;
351
+ }
352
+ isUJS(node) {
353
+ const hasVisit = !!node.getAttribute(this.attributePrefix + "-visit");
354
+ const hasRemote = !!node.getAttribute(this.attributePrefix + "-remote");
355
+ return hasVisit || hasRemote;
356
+ }
357
+ handleSubmit(event) {
358
+ const form = event.target;
359
+ if (!(form instanceof HTMLFormElement)) {
360
+ return;
361
+ }
362
+ if (!this.isUJS(form)) {
363
+ return;
364
+ }
365
+ event.preventDefault();
366
+ let url = form.getAttribute("action");
367
+ if (!url) {
368
+ return;
369
+ }
370
+ const method = (form.getAttribute("method") || "POST").toUpperCase();
371
+ url = withoutBusters(url);
372
+ this.visitOrRemote(form, url, {
373
+ method,
374
+ body: new FormData(form)
375
+ });
376
+ }
377
+ handleClick(event) {
378
+ if (!(event.target instanceof Element)) {
379
+ return;
380
+ }
381
+ const link = this.retrieveLink(event.target);
382
+ const isNonStandard = this.isNonStandardClick(event);
383
+ if (!link || isNonStandard || !this.isUJS(link)) {
384
+ return;
385
+ }
386
+ event.preventDefault();
387
+ let url = link.getAttribute("href");
388
+ if (!url) {
389
+ return;
390
+ }
391
+ url = withoutBusters(url);
392
+ this.visitOrRemote(link, url, { method: "GET" });
393
+ }
394
+ visitOrRemote(linkOrForm, url, opts) {
395
+ if (linkOrForm.getAttribute(this.attributePrefix + "-visit")) {
396
+ const nextOpts = { ...opts };
397
+ const placeholderKey = linkOrForm.getAttribute(
398
+ this.attributePrefix + "-placeholder"
399
+ );
400
+ if (placeholderKey) {
401
+ nextOpts.placeholderKey = urlToPageKey(placeholderKey);
402
+ }
403
+ return this.visit(url, { ...nextOpts });
404
+ }
405
+ if (linkOrForm.getAttribute(this.attributePrefix + "-remote")) {
406
+ return this.remote(url, opts);
407
+ }
408
+ }
409
+ handlers() {
410
+ return {
411
+ onClick: this.handleClick,
412
+ onSubmit: this.handleSubmit
413
+ };
414
+ }
415
+ };
416
+ var ujsHandlers = ({
417
+ ujsAttributePrefix,
418
+ visit: visit2,
419
+ remote: remote2
420
+ }) => {
421
+ const builder = new HandlerBuilder({
422
+ visit: visit2,
423
+ remote: remote2,
424
+ ujsAttributePrefix
425
+ });
426
+ return builder.handlers();
427
+ };
428
+
429
+ // lib/utils/window.ts
430
+ function needsRefresh(prevAssets, newAssets) {
431
+ if (prevAssets && newAssets) {
432
+ const hasNewAssets = !newAssets.every((asset) => prevAssets.includes(asset));
433
+ return hasNewAssets;
434
+ } else {
435
+ return false;
436
+ }
437
+ }
438
+
439
+ // lib/action_creators/index.ts
440
+ import parse3 from "url-parse";
441
+
442
+ // lib/actions.ts
443
+ var actions_exports = {};
444
+ __export(actions_exports, {
445
+ BEFORE_FETCH: () => BEFORE_FETCH,
446
+ BEFORE_REMOTE: () => BEFORE_REMOTE,
447
+ BEFORE_VISIT: () => BEFORE_VISIT,
448
+ COPY_PAGE: () => COPY_PAGE,
449
+ GRAFTING_ERROR: () => GRAFTING_ERROR,
450
+ GRAFTING_SUCCESS: () => GRAFTING_SUCCESS,
451
+ HANDLE_GRAFT: () => HANDLE_GRAFT,
452
+ HISTORY_CHANGE: () => HISTORY_CHANGE,
453
+ REMOVE_PAGE: () => REMOVE_PAGE,
454
+ SAVE_RESPONSE: () => SAVE_RESPONSE,
455
+ SET_CSRF_TOKEN: () => SET_CSRF_TOKEN,
456
+ SUPERGLUE_ERROR: () => SUPERGLUE_ERROR,
457
+ UPDATE_FRAGMENTS: () => UPDATE_FRAGMENTS
458
+ });
459
+ var BEFORE_FETCH = "@@superglue/BEFORE_FETCH";
460
+ var BEFORE_VISIT = "@@superglue/BEFORE_VISIT";
461
+ var BEFORE_REMOTE = "@@superglue/BEFORE_REMOTE";
462
+ var SAVE_RESPONSE = "@@superglue/SAVE_RESPONSE";
463
+ var HANDLE_GRAFT = "@@superglue/HANDLE_GRAFT";
464
+ var SUPERGLUE_ERROR = "@@superglue/ERROR";
465
+ var GRAFTING_ERROR = "@@superglue/GRAFTING_ERROR";
466
+ var GRAFTING_SUCCESS = "@@superglue/GRAFTING_SUCCESS";
467
+ var HISTORY_CHANGE = "@@superglue/HISTORY_CHANGE";
468
+ var SET_CSRF_TOKEN = "@@superglue/SET_CSRF_TOKEN";
469
+ var REMOVE_PAGE = "@@superglue/REMOVE_PAGE";
470
+ var COPY_PAGE = "@@superglue/COPY_PAGE";
471
+ var UPDATE_FRAGMENTS = "@@superglue/UPDATE_FRAGMENTS";
472
+
473
+ // lib/action_creators/requests.ts
474
+ function beforeVisit(payload) {
475
+ return {
476
+ type: BEFORE_VISIT,
477
+ payload
478
+ };
479
+ }
480
+ function beforeRemote(payload) {
481
+ return {
482
+ type: BEFORE_REMOTE,
483
+ payload
484
+ };
485
+ }
486
+ function beforeFetch(payload) {
487
+ return {
488
+ type: BEFORE_FETCH,
489
+ payload
490
+ };
491
+ }
492
+ function handleError(err) {
493
+ return {
494
+ type: SUPERGLUE_ERROR,
495
+ payload: {
496
+ message: err.message
497
+ }
498
+ };
499
+ }
500
+ function handleFetchErr(err, fetchArgs, dispatch) {
501
+ dispatch(handleError(err));
502
+ throw err;
503
+ }
504
+ function buildMeta(pageKey, page, state, rsp, fetchArgs) {
505
+ const { assets: prevAssets } = state;
506
+ const { assets: nextAssets } = page;
507
+ return {
508
+ pageKey,
509
+ page,
510
+ redirected: rsp.redirected,
511
+ rsp,
512
+ fetchArgs,
513
+ componentIdentifier: page.componentIdentifier,
514
+ needsRefresh: needsRefresh(prevAssets, nextAssets)
515
+ };
516
+ }
517
+ var remote = (path, {
518
+ method = "GET",
519
+ headers,
520
+ body,
521
+ pageKey: rawPageKey,
522
+ beforeSave = (prevPage, receivedPage) => receivedPage
523
+ } = {}) => {
524
+ path = withoutBusters(path);
525
+ rawPageKey = rawPageKey && urlToPageKey(rawPageKey);
526
+ return (dispatch, getState) => {
527
+ const fetchArgs = argsForFetch(getState, path, {
528
+ method,
529
+ headers,
530
+ body
531
+ });
532
+ if (rawPageKey === void 0) {
533
+ rawPageKey = getState().superglue.currentPageKey;
534
+ }
535
+ const pageKey = rawPageKey;
536
+ const currentPageKey = getState().superglue.currentPageKey;
537
+ dispatch(beforeRemote({ currentPageKey, fetchArgs }));
538
+ dispatch(beforeFetch({ fetchArgs }));
539
+ return fetch(...fetchArgs).then(parseResponse).then(({ rsp, json }) => {
540
+ const { superglue, pages = {} } = getState();
541
+ const meta = buildMeta(pageKey, json, superglue, rsp, fetchArgs);
542
+ const willReplaceCurrent = pageKey == currentPageKey;
543
+ const existingId = pages[currentPageKey]?.componentIdentifier;
544
+ const receivedId = json.componentIdentifier;
545
+ if (willReplaceCurrent && !!existingId && existingId != receivedId) {
546
+ console.warn(
547
+ `You're about replace an existing page located at pages["${currentPageKey}"]
548
+ that has the componentIdentifier "${existingId}" with the contents of a
549
+ received page that has a componentIdentifier of "${receivedId}".
550
+
551
+ This can happen if you're using data-sg-remote or remote but your response
552
+ redirected to a completely different page. Since remote requests do not
553
+ navigate or change the current page component, your current page component may
554
+ receive a shape that is unexpected and cause issues with rendering.
555
+
556
+ Consider using data-sg-visit, the visit function, or redirect_back.`
557
+ );
558
+ }
559
+ const page = beforeSave(pages[pageKey], json);
560
+ return dispatch(saveAndProcessPage(pageKey, page)).then(() => meta);
561
+ }).catch((e) => handleFetchErr(e, fetchArgs, dispatch));
562
+ };
563
+ };
564
+ var lastVisitController = {
565
+ abort: () => {
566
+ }
567
+ };
568
+ var visit = (path, {
569
+ method = "GET",
570
+ headers,
571
+ body,
572
+ placeholderKey,
573
+ beforeSave = (prevPage, receivedPage) => receivedPage,
574
+ revisit = false
575
+ } = {}) => {
576
+ path = withoutBusters(path);
577
+ let pageKey = urlToPageKey(path);
578
+ return (dispatch, getState) => {
579
+ placeholderKey = placeholderKey && urlToPageKey(placeholderKey);
580
+ const hasPlaceholder = !!(placeholderKey && getState().pages[placeholderKey]);
581
+ if (placeholderKey && hasPlaceholder) {
582
+ dispatch(copyPage({ from: placeholderKey, to: pageKey }));
583
+ }
584
+ if (placeholderKey && !hasPlaceholder) {
585
+ console.warn(
586
+ `Could not find placeholder with key ${placeholderKey} in state. The props_at param will be ignored`
587
+ );
588
+ path = removePropsAt(path);
589
+ }
590
+ if (!placeholderKey && hasPropsAt(path)) {
591
+ console.warn(
592
+ `visit was called with props_at param in the path ${path}, this will be ignore unless you provide a placeholder.`
593
+ );
594
+ path = removePropsAt(path);
595
+ }
596
+ const controller = new AbortController();
597
+ const { signal } = controller;
598
+ const fetchArgs = argsForFetch(getState, path, {
599
+ headers,
600
+ body,
601
+ method,
602
+ signal
603
+ });
604
+ const currentPageKey = getState().superglue.currentPageKey;
605
+ dispatch(beforeVisit({ currentPageKey, fetchArgs }));
606
+ dispatch(beforeFetch({ fetchArgs }));
607
+ lastVisitController.abort();
608
+ lastVisitController = controller;
609
+ return fetch(...fetchArgs).then(parseResponse).then(({ rsp, json }) => {
610
+ const { superglue, pages = {} } = getState();
611
+ const meta = buildMeta(pageKey, json, superglue, rsp, fetchArgs);
612
+ const isGet = fetchArgs[1].method === "GET";
613
+ meta.suggestedAction = "push";
614
+ if (!rsp.redirected && !isGet) {
615
+ meta.suggestedAction = "replace";
616
+ }
617
+ if (revisit && isGet) {
618
+ if (rsp.redirected) {
619
+ meta.suggestedAction = "replace";
620
+ } else {
621
+ meta.suggestedAction = "none";
622
+ }
623
+ }
624
+ pageKey = urlToPageKey(rsp.url);
625
+ if (!isGet && !rsp.redirected) {
626
+ pageKey = currentPageKey;
627
+ }
628
+ const contentLocation = rsp.headers.get("content-location");
629
+ if (contentLocation) {
630
+ pageKey = urlToPageKey(contentLocation);
631
+ }
632
+ const page = beforeSave(pages[pageKey], json);
633
+ return dispatch(saveAndProcessPage(pageKey, page)).then(() => {
634
+ meta.pageKey = pageKey;
635
+ return meta;
636
+ });
637
+ }).catch((e) => handleFetchErr(e, fetchArgs, dispatch));
638
+ };
639
+ };
640
+
641
+ // lib/action_creators/index.ts
642
+ function copyPage({
643
+ from,
644
+ to
645
+ }) {
646
+ return {
647
+ type: COPY_PAGE,
648
+ payload: {
649
+ from,
650
+ to
651
+ }
652
+ };
653
+ }
654
+ function saveResponse({
655
+ pageKey,
656
+ page
657
+ }) {
658
+ pageKey = urlToPageKey(pageKey);
659
+ return {
660
+ type: SAVE_RESPONSE,
661
+ payload: {
662
+ pageKey,
663
+ page
664
+ }
665
+ };
666
+ }
667
+ function handleGraft({
668
+ pageKey,
669
+ page
670
+ }) {
671
+ pageKey = urlToPageKey(pageKey);
672
+ return {
673
+ type: HANDLE_GRAFT,
674
+ payload: {
675
+ pageKey,
676
+ page
677
+ }
678
+ };
679
+ }
680
+ function fetchDeferments(pageKey, defers = []) {
681
+ pageKey = urlToPageKey(pageKey);
682
+ return (dispatch) => {
683
+ const fetches = defers.filter(({ type }) => type === "auto").map(function({
684
+ url,
685
+ successAction = GRAFTING_SUCCESS,
686
+ failAction = GRAFTING_ERROR
687
+ }) {
688
+ const parsedUrl = new parse3(url, true);
689
+ const keyPath = parsedUrl.query.props_at;
690
+ return dispatch(remote(url, { pageKey })).then(() => {
691
+ dispatch({
692
+ type: successAction,
693
+ payload: {
694
+ pageKey,
695
+ keyPath
696
+ }
697
+ });
698
+ }).catch((err) => {
699
+ dispatch({
700
+ type: failAction,
701
+ payload: {
702
+ url,
703
+ err,
704
+ pageKey,
705
+ keyPath
706
+ }
707
+ });
708
+ });
709
+ });
710
+ return Promise.all(fetches);
711
+ };
712
+ }
713
+ function updateFragmentsUsing(page) {
714
+ const changedFragments = {};
715
+ page.fragments.forEach((fragment) => {
716
+ const { type, path } = fragment;
717
+ changedFragments[type] = getIn(page, path);
718
+ });
719
+ return {
720
+ type: UPDATE_FRAGMENTS,
721
+ payload: { changedFragments }
722
+ };
723
+ }
724
+ function saveAndProcessPage(pageKey, page) {
725
+ return (dispatch, getState) => {
726
+ pageKey = urlToPageKey(pageKey);
727
+ const { defers = [] } = page;
728
+ if ("action" in page) {
729
+ dispatch(handleGraft({ pageKey, page }));
730
+ } else {
731
+ dispatch(saveResponse({ pageKey, page }));
732
+ }
733
+ const hasFetch = typeof fetch != "undefined";
734
+ if (hasFetch) {
735
+ return dispatch(fetchDeferments(pageKey, defers)).then(() => {
736
+ if (page.fragments.length > 0) {
737
+ const finishedPage = getState().pages[pageKey];
738
+ dispatch(updateFragmentsUsing(finishedPage));
739
+ return Promise.resolve();
740
+ }
741
+ });
742
+ } else {
743
+ return Promise.resolve();
744
+ }
745
+ };
746
+ }
747
+
748
+ export {
749
+ pathWithoutBZParams,
750
+ urlToPageKey,
751
+ argsForHistory,
752
+ KeyPathError,
753
+ getIn,
754
+ setIn,
755
+ BEFORE_FETCH,
756
+ BEFORE_VISIT,
757
+ BEFORE_REMOTE,
758
+ SAVE_RESPONSE,
759
+ HANDLE_GRAFT,
760
+ GRAFTING_ERROR,
761
+ GRAFTING_SUCCESS,
762
+ HISTORY_CHANGE,
763
+ SET_CSRF_TOKEN,
764
+ REMOVE_PAGE,
765
+ COPY_PAGE,
766
+ UPDATE_FRAGMENTS,
767
+ actions_exports,
768
+ remote,
769
+ visit,
770
+ copyPage,
771
+ saveResponse,
772
+ handleGraft,
773
+ saveAndProcessPage,
774
+ mapStateToProps,
775
+ mapDispatchToProps,
776
+ config,
777
+ ujsHandlers
778
+ };
779
+ //# sourceMappingURL=chunk-MNVGYKSD.mjs.map