@humandialog/forms.svelte 1.8.1 → 1.8.3

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.
@@ -11,11 +11,13 @@ import {
11
11
  informModification,
12
12
  pushChanges,
13
13
  startEditing,
14
- Ricon
14
+ Ricon,
15
+ focusEditable
15
16
  } from "../../..";
16
17
  import { FaRegFileAlt } from "svelte-icons/fa";
17
18
  import Properties from "./kanban.props.svelte";
18
19
  import { KanbanCardTop, KanbanCardMiddle, KanbanCardBottom } from "../Kanban";
20
+ import Editable from "../../r.editable.svelte";
19
21
  export let item;
20
22
  let definition = getContext("rKanban-definition");
21
23
  $:
@@ -82,43 +84,18 @@ function onSummaryChanged(text) {
82
84
  pushChanges();
83
85
  }
84
86
  }
85
- function setSelectionAtEnd(element) {
86
- const textNode = element.childNodes[0];
87
- const text = textNode.textContent;
88
- let range = document.createRange();
89
- let end_offset = text.length;
90
- let end_container = textNode;
91
- range.setStart(end_container, end_offset);
92
- range.setEnd(end_container, end_offset);
93
- let sel = window.getSelection();
94
- sel.removeAllRanges();
95
- sel.addRange(range);
96
- }
97
87
  let topProps;
98
88
  let middleProps;
99
89
  let bottomProps;
100
- let titleElement;
101
- let summaryElement;
102
90
  let summaryPlaceholder = false;
103
91
  export async function editProperty(field) {
104
92
  if (field == "Title") {
105
- if (isLinkLike) {
106
- startEditing(titleElement);
107
- } else {
108
- titleElement.focus();
109
- await tick();
110
- setSelectionAtEnd(titleElement);
111
- }
93
+ focusEditable("#__or_kanban_ctrl_Title");
112
94
  } else if (field == "Summary") {
113
- if (!!summaryElement) {
114
- summaryElement.focus();
115
- await tick();
116
- setSelectionAtEnd(summaryElement);
117
- } else {
95
+ if (!focusEditable("#__or_kanban_ctrl_Summary")) {
118
96
  summaryPlaceholder = true;
119
97
  await tick();
120
- if (!!summaryElement)
121
- summaryElement.focus();
98
+ focusEditable("#__or_kanban_ctrl_Summary");
122
99
  }
123
100
  } else {
124
101
  const property = definition.properties.find((p) => p.name == field);
@@ -209,23 +186,22 @@ function showAttachementIcon() {
209
186
  {@const showIcon = showAttachementIcon()}
210
187
  <!-- whitespace-nowrap overflow-clip -->
211
188
  <h4 class = "font-semibold relative"
212
- use:editable={{
213
- action: (text) => onTitleChanged(text),
214
- active: false,
215
- readonly: definition.titleReadOnly,
216
- onFinish: (d) => {titleElement.blur()},
217
- onSoftEnter: async (text) => { onTitleChanged(text); await editProperty('Summary') }
218
- }}
219
189
  use:conditionalClick={{
220
190
  condition: hasOpen,
221
- callback: performOpen}}
222
- bind:this={titleElement}>
191
+ callback: performOpen}}>
223
192
  {#if isLinkLike}
224
193
  <a class= "font-semibold" href={getHRef()} use:link>
225
- {item[definition.titleAttrib]}
194
+ <Editable self={item}
195
+ a={definition.titleAttrib}
196
+ readonly={definition.titleReadOnly}
197
+ focusOnClick={false}
198
+ id="__or_kanban_ctrl_Title"/>
226
199
  </a>
227
200
  {:else}
228
- {item[definition.titleAttrib]}
201
+ <Editable self={item}
202
+ a={definition.titleAttrib}
203
+ readonly={definition.titleReadOnly}
204
+ id="__or_kanban_ctrl_Title"/>
229
205
  {/if}
230
206
 
231
207
 
@@ -258,13 +234,9 @@ function showAttachementIcon() {
258
234
  {#if item[definition.summaryAttrib] || summaryPlaceholder}
259
235
  {#key item[definition.summaryAttrib]}
260
236
  {#if isCardActive}
261
- <figcaption use:editable={{
262
- action: (text) => onSummaryChanged(text),
263
- active: true,
264
- readonly: definition.summaryReadOnly,
265
- onFinish: (d) => {summaryPlaceholder = false}}}
266
- bind:this={summaryElement}>
267
- {item[definition.summaryAttrib]}
237
+ <figcaption><Editable self={item}
238
+ a={definition.summaryAttrib}
239
+ id="__or_kanban_ctrl_Summary"/>
268
240
  </figcaption>
269
241
  {:else}
270
242
  <figcaption>
@@ -145,7 +145,7 @@ export async function add(after = KanbanColumnTop) {
145
145
  if (detail.cancel)
146
146
  activateAfterDomUpdate = lastActivatedElement;
147
147
  else {
148
- if (detail.incremental) {
148
+ if (false) {
149
149
  let currentActive = activateAfterDomUpdate ?? getActive("props");
150
150
  if (currentActive)
151
151
  await add(currentActive);
@@ -8,7 +8,8 @@ import {
8
8
  editable,
9
9
  startEditing,
10
10
  addActiveItem,
11
- removeActiveItem
11
+ removeActiveItem,
12
+ focusEditable
12
13
  } from "../../../utils";
13
14
  import { showGridMenu, showMenu } from "../../menu";
14
15
  import { pushChanges, informModification } from "../../../updates";
@@ -16,12 +17,10 @@ import { isDeviceSmallerThan } from "../../../utils";
16
17
  import Circle from "../../ricons/circle.svelte";
17
18
  import CircleCheck from "../../ricons/circle-check.svelte";
18
19
  import Ricon from "../../r.icon.svelte";
19
- import Spinner from "../../delayed.spinner.svelte";
20
20
  import { rList_definition, rList_property_type } from "../List";
21
21
  import { push, link } from "svelte-spa-router";
22
- import { FaExternalLinkAlt, FaRegCircle, FaRegCheckCircle } from "svelte-icons/fa/";
23
- import Tags from "../../tags.svelte";
24
22
  import { ext } from "../../../i18n";
23
+ import Editable from "../../r.editable.svelte";
25
24
  export let item;
26
25
  export let element_title = "";
27
26
  export let list_properties = void 0;
@@ -188,33 +187,12 @@ export function editProperty(field) {
188
187
  }
189
188
  }
190
189
  async function force_editing(field) {
191
- let element_id = `__or_list_ctrl_${getItemKey(item)}_${field}`;
192
- let element_node = document.getElementById(element_id);
193
- if (!element_node) {
190
+ let element_id = `#__or_list_ctrl_${getItemKey(item)}_${field}`;
191
+ if (!focusEditable(element_id)) {
194
192
  placeholder = field;
195
193
  await tick();
196
- element_node = document.getElementById(element_id);
197
- if (!element_node)
198
- return;
194
+ focusEditable(element_id);
199
195
  }
200
- if (!element_node.classList.contains("editable")) {
201
- return;
202
- }
203
- startEditing(element_node, () => {
204
- placeholder = "";
205
- });
206
- }
207
- function setSelectionAtEnd(element) {
208
- const textNode = element.childNodes[0];
209
- const text = textNode.textContent;
210
- let range = document.createRange();
211
- let end_offset = text.length;
212
- let end_container = textNode;
213
- range.setStart(end_container, end_offset);
214
- range.setEnd(end_container, end_offset);
215
- let sel = window.getSelection();
216
- sel.removeAllRanges();
217
- sel.addRange(range);
218
196
  }
219
197
  let rootElement;
220
198
  export function scrollToView() {
@@ -408,36 +386,30 @@ async function onDownloadFile(e) {
408
386
  href={element_href}
409
387
  on:click={onDownloadFile}>
410
388
 
411
- <h4 class="-indent-8"
412
- id="__or_list_ctrl_{getItemKey(item)}_Title"
413
- use:editable={{
414
- action: (text) => {change_property(element_title, text)},
415
- active: false,
416
- readonly: title_readonly,
417
- onSoftEnter: (text) => {change_name(text); editProperty('Summary')}
418
- }}>
389
+ <h4 class="-indent-8">
419
390
  <div class="inline-block w-4 h-4 ml-0 mr-4 align-baseline
420
391
  text-stone-700 dark:text-stone-400 ">
421
392
  <Ricon icon={isDownloading ? 'loader-circle' : element_icon} />
422
- </div>{translated_element_title}
393
+ </div><Editable self={item}
394
+ a={element_title}
395
+ id="__or_list_ctrl_{getItemKey(item)}_Title"
396
+ readonly={title_readonly}
397
+ focusOnClick={false}/>
423
398
  </h4>
424
399
  </a>
425
400
  {:else if element_href}
426
401
  <a class="sm:hover:cursor-pointer"
427
402
  href={element_href} use:link>
428
403
 
429
- <h4 class="-indent-8 "
430
- id="__or_list_ctrl_{getItemKey(item)}_Title"
431
- use:editable={{
432
- action: (text) => {change_property(element_title, text)},
433
- active: false,
434
- readonly: title_readonly,
435
- onSoftEnter: (text) => {change_name(text); editProperty('Summary')}
436
- }}>
404
+ <h4 class="-indent-8 ">
437
405
  <div class="inline-block w-4 h-4 ml-0 mr-4 align-baseline
438
406
  text-stone-700 dark:text-stone-400 ">
439
407
  <Ricon icon={element_icon} />
440
- </div>{translated_element_title}
408
+ </div><Editable self={item}
409
+ a={element_title}
410
+ id="__or_list_ctrl_{getItemKey(item)}_Title"
411
+ readonly={title_readonly}
412
+ focusOnClick={false}/>
441
413
  </h4>
442
414
  </a>
443
415
  {:else if element_open_handler}
@@ -445,33 +417,26 @@ async function onDownloadFile(e) {
445
417
  href="/#"
446
418
  on:click|preventDefault={() => element_open_handler(item)}>
447
419
 
448
- <h4 class="-indent-8"
449
- id="__or_list_ctrl_{getItemKey(item)}_Title"
450
- use:editable={{
451
- action: (text) => {change_property(element_title, text)},
452
- active: false,
453
- readonly: title_readonly,
454
- onSoftEnter: (text) => {change_name(text); editProperty('Summary')}
455
- }}>
420
+ <h4 class="-indent-8">
456
421
  <div class="inline-block w-4 h-4 ml-0 mr-4 align-baseline
457
422
  text-stone-700 dark:text-stone-400 ">
458
423
  <Ricon icon={element_icon} />
459
- </div>{translated_element_title}
424
+ </div><Editable self={item}
425
+ a={element_title}
426
+ id="__or_list_ctrl_{getItemKey(item)}_Title"
427
+ readonly={title_readonly}
428
+ focusOnClick={false}/>
460
429
  </h4>
461
430
  </a>
462
431
  {:else}
463
- <h4 class="-indent-8 "
464
- id="__or_list_ctrl_{getItemKey(item)}_Title"
465
- use:editable={{
466
- action: (text) => {change_property(element_title, text)},
467
- active: false,
468
- readonly: title_readonly,
469
- onSoftEnter: (text) => {change_name(text); editProperty('Summary')}
470
- }}>
432
+ <h4 class="-indent-8">
471
433
  <div class="inline-block w-4 h-4 ml-0 mr-4 align-baseline
472
434
  text-stone-700 dark:text-stone-400 ">
473
435
  <Ricon icon={element_icon} />
474
- </div>{translated_element_title}
436
+ </div><Editable self={item}
437
+ a={element_title}
438
+ id="__or_list_ctrl_{getItemKey(item)}_Title"
439
+ readonly={title_readonly}/>
475
440
  </h4>
476
441
  {/if}
477
442
 
@@ -485,25 +450,14 @@ async function onDownloadFile(e) {
485
450
  </figcaption>
486
451
  -------------------------------->
487
452
 
488
- {#if summary && (item[summary])}
489
- <figcaption id="__or_list_ctrl_{getItemKey(item)}_Summary" use:editable={{
490
- action: (text) => {change_property(summary, text)},
491
- readonly: summary_readonly,
492
- onFinish: (d) => {placeholder='';},
493
- active: true
494
- }}>{item[summary]}
495
- </figcaption>
496
-
497
- {:else if placeholder=='Summary'}
498
- <figcaption id="__or_list_ctrl_{getItemKey(item)}_Summary"
499
- use:editable={{
500
- action: (text) => {change_property(summary, text)},
501
- readonly: summary_readonly,
502
- onFinish: (d) => {placeholder='';},
503
- active: true
504
- }}>&nbsp;
453
+ {#if (summary && (item[summary])) || (placeholder=='Summary')}
454
+ <figcaption><Editable self={item}
455
+ a={summary}
456
+ id="__or_list_ctrl_{getItemKey(item)}_Summary"
457
+ readonly={summary_readonly} />
505
458
  </figcaption>
506
459
  {/if}
460
+
507
461
  </figure>
508
462
  </div>
509
463
 
@@ -59,39 +59,3 @@ async function onSummaryChanged(text) {
59
59
  {/if}
60
60
  </figure>
61
61
 
62
-
63
- <!--section class=" my-1 w-full text-base text-stone-700 dark:text-stone-400 cursor-default rounded-md border border-transparent bg-stone-200 dark:bg-stone-700">
64
- <div class="flex flex-row">
65
- {#if icon}
66
-
67
- <div class="h-5 w-5 sm:h-4 sm:w-4 mt-2 sm:mt-1.5 ml-2"></div>
68
- {/if}
69
-
70
- <p class=" ml-3 py-1
71
- text-base font-semibold min-h-[1.75rem]
72
- sm:min-h-[1.25rem]
73
- whitespace-nowrap overflow-clip flex-none w-1/2 sm:w-1/3" tabindex="0"
74
- bind:this={titleElement}
75
- use:editable={{
76
- action: (text) => onInsert(text, ''),
77
- active: false,
78
- onSoftEnter: softEnter
79
- }} >
80
- </p>
81
- </div>
82
-
83
- {#if editSummary}
84
- <p bind:this={summaryElement}
85
- class=" ml-10 sm:ml-9
86
- sm:min-h-[1rem]
87
- text-sm min-h-[1.5rem]
88
- text-stone-400"
89
- use:editable={{
90
- action: onSummaryChanged,
91
- active: false,
92
- onFinish: (d) => {editSummary=false}
93
- }}>
94
- {summary}
95
- </p>
96
- {/if}
97
- </section-->
@@ -214,7 +214,7 @@ export async function addRowAfter(after = null) {
214
214
  if (detail.cancel)
215
215
  activate_after_dom_update = last_activated_element;
216
216
  else {
217
- if (detail.incremental && definition.insert_incremental) {
217
+ if (false) {
218
218
  let current_active = getActive(selectionKey);
219
219
  await addRowAfter(current_active);
220
220
  }
@@ -411,10 +411,7 @@ function read_from_def(propName) {
411
411
  {selectionKey}
412
412
  bind:this={rows[i]}
413
413
  >
414
-
415
- <span slot="left" let:element>
416
- <slot name="left" {element}/>
417
- </span>
414
+
418
415
  </ListElement>
419
416
 
420
417
  {#if show_insertion_row_after_element == element}
@@ -43,9 +43,6 @@ declare const __propDef: {
43
43
  };
44
44
  slots: {
45
45
  default: {};
46
- left: {
47
- element: any;
48
- };
49
46
  };
50
47
  };
51
48
  export type ListProps = typeof __propDef.props;
@@ -64,9 +64,7 @@
64
64
  }}
65
65
  on:focus={focus}
66
66
  on:blur={blur}
67
- >
68
- {ext(self[a])}
69
- </span>
67
+ >{ext(self[a])}</span>
70
68
 
71
69
  <!--style>
72
70
  span:empty:focus::before {
package/desk.svelte CHANGED
@@ -409,8 +409,8 @@
409
409
  overflow-auto" >
410
410
 
411
411
  <div class=" flex flex-row justify-between h-full
412
- text-stone-500 bg-stone-200/70 hover:bg-stone-200
413
- dark:text-orange-200 dark:bg-stone-700/70 dark:hover:bg-stone-700
412
+ text-stone-500 bg-stone-200/70
413
+ dark:text-orange-200 dark:bg-stone-700/70
414
414
  bg-stone-200 dark:bg-stone-800/70
415
415
  border-t border-stone-500 ">
416
416
  <HorizontalNavigatorTabs appConfig={layout}/>
@@ -430,12 +430,12 @@
430
430
  left-0 bottom-[50px]
431
431
  sm:left-[40px] sm:top-0
432
432
  w-full sm:w-[320px]
433
- h-[calc(100vh-100px)] sm:h-full
433
+ h-[calc(100svh-50px)] sm:h-full
434
434
 
435
435
  z-30 overflow-x-hidden
436
436
 
437
437
  bg-stone-50 dark:bg-stone-900
438
- border-2 sm:border-r border-stone-300 dark:border-stone-300/50
438
+ border-t sm:border-t-0 sm:border-r border-stone-300 dark:border-stone-300/50
439
439
  sm:shadow-lg sm:shadow-stone-500
440
440
  sm:dark:shadow-black">
441
441
 
package/index.d.ts CHANGED
@@ -71,7 +71,7 @@ export { default as Breadcrumb } from './components/breadcrumb.svelte';
71
71
  export { breadcrumbAdd, breadcrumbParse, breadcrumbStringify, breadcrumbClipName } from './components/breadcrumb_utils';
72
72
  export { default as EditableSpan } from './components/prose.editable.span.svelte';
73
73
  export { default as EditableParagraph } from './components/prose.editable.p.svelte';
74
- export { selectItem, activateItem, clearActiveItem, isActive, isSelected, getActive, getActiveItems, getActiveCount, addActiveItem, removeActiveItem, editable, startEditing, saveCurrentEditable, focusEditable, selectable, handleSelect, isDeviceSmallerThan, resizeImage, refreshToolbarOperations, reloadPageToolbarOperations, isOnScreenKeyboardVisible, randomString, UI, NAV_MODE_SIDEBAR, NAV_MODE_FULL_PAGE, navGetMode, navIsVisible, navGetKey, navShow, navHide, navToggle, navPrevVisibleKey, navAutoHide, insertAt, insertAfter, getPrev, getNext, getFirst, getLast, removeAt, remove, swapElements, setSelectionAtEnd, isValidEmail, localStorageSave, localStorageRead, sessionStorageSave, sessionStorageRead, hasLocalStorage, getCurrentGroupName, getGroupsMenu } from './utils';
74
+ export { selectItem, activateItem, clearActiveItem, isActive, isSelected, getActive, getActiveItems, getActiveCount, addActiveItem, removeActiveItem, editable, startEditing, saveCurrentEditable, focusEditable, selectable, handleSelect, isDeviceSmallerThan, resizeImage, refreshToolbarOperations, reloadPageToolbarOperations, isOnScreenKeyboardVisible, randomString, UI, NAV_MODE_SIDEBAR, NAV_MODE_FULL_PAGE, navGetMode, navIsVisible, navGetKey, navShow, navHide, navToggle, navPrevVisibleKey, navAutoHide, insertAt, insertAfter, getPrev, getNext, getFirst, getLast, removeAt, remove, swapElements, setSelectionAtEnd, isValidEmail, localStorageSave, localStorageRead, sessionStorageSave, sessionStorageRead, hasLocalStorage, getCurrentGroupName, getGroupsMenu, fetchHandlers } from './utils';
75
75
  export { getNiceStringDateTime, getFormattedStringDate, getNiceStringDate, dayName, monthName } from './components/date_utils';
76
76
  export { mainContentPageReloader, reloadMainContentPage, reloadWholeApp, wholeAppReloader, alerts, addAlert, onErrorShowAlert, main_sidebar_visible_store, navKey, tagsReloader, reloadVisibleTags, dark_mode_store, showFABAlways } from './stores.js';
77
77
  export { data_tick_store, // tmp
package/index.js CHANGED
@@ -77,7 +77,7 @@ export { default as Breadcrumb } from './components/breadcrumb.svelte';
77
77
  export { breadcrumbAdd, breadcrumbParse, breadcrumbStringify, breadcrumbClipName } from './components/breadcrumb_utils';
78
78
  export { default as EditableSpan } from './components/prose.editable.span.svelte';
79
79
  export { default as EditableParagraph } from './components/prose.editable.p.svelte';
80
- export { selectItem, activateItem, clearActiveItem, isActive, isSelected, getActive, getActiveItems, getActiveCount, addActiveItem, removeActiveItem, editable, startEditing, saveCurrentEditable, focusEditable, selectable, handleSelect, isDeviceSmallerThan, resizeImage, refreshToolbarOperations, reloadPageToolbarOperations, isOnScreenKeyboardVisible, randomString, UI, NAV_MODE_SIDEBAR, NAV_MODE_FULL_PAGE, navGetMode, navIsVisible, navGetKey, navShow, navHide, navToggle, navPrevVisibleKey, navAutoHide, insertAt, insertAfter, getPrev, getNext, getFirst, getLast, removeAt, remove, swapElements, setSelectionAtEnd, isValidEmail, localStorageSave, localStorageRead, sessionStorageSave, sessionStorageRead, hasLocalStorage, getCurrentGroupName, getGroupsMenu } from './utils';
80
+ export { selectItem, activateItem, clearActiveItem, isActive, isSelected, getActive, getActiveItems, getActiveCount, addActiveItem, removeActiveItem, editable, startEditing, saveCurrentEditable, focusEditable, selectable, handleSelect, isDeviceSmallerThan, resizeImage, refreshToolbarOperations, reloadPageToolbarOperations, isOnScreenKeyboardVisible, randomString, UI, NAV_MODE_SIDEBAR, NAV_MODE_FULL_PAGE, navGetMode, navIsVisible, navGetKey, navShow, navHide, navToggle, navPrevVisibleKey, navAutoHide, insertAt, insertAfter, getPrev, getNext, getFirst, getLast, removeAt, remove, swapElements, setSelectionAtEnd, isValidEmail, localStorageSave, localStorageRead, sessionStorageSave, sessionStorageRead, hasLocalStorage, getCurrentGroupName, getGroupsMenu, fetchHandlers } from './utils';
81
81
  export { getNiceStringDateTime, getFormattedStringDate, getNiceStringDate, dayName, monthName } from './components/date_utils';
82
82
  export { mainContentPageReloader, reloadMainContentPage, reloadWholeApp, wholeAppReloader, alerts, addAlert, onErrorShowAlert, main_sidebar_visible_store, navKey, tagsReloader, reloadVisibleTags, dark_mode_store, showFABAlways } from './stores.js';
83
83
  export { data_tick_store, // tmp
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@humandialog/forms.svelte",
3
- "version": "1.8.1",
3
+ "version": "1.8.3",
4
4
  "description": "Basic Svelte UI components for Object Reef applications",
5
5
  "devDependencies": {
6
6
  "@playwright/test": "^1.28.1",
@@ -27,7 +27,7 @@
27
27
  },
28
28
  "type": "module",
29
29
  "dependencies": {
30
- "@humandialog/auth.svelte": "^1.8.21",
30
+ "@humandialog/auth.svelte": "^1.9.2",
31
31
  "@tiptap/core": "^2.11.0",
32
32
  "@tiptap/extension-bullet-list": "^2.11.5",
33
33
  "@tiptap/extension-code-block": "^2.11.5",
package/updates.d.ts CHANGED
@@ -6,4 +6,5 @@ export function hasModifications(): boolean;
6
6
  export function informItem(itm: any, type_name?: undefined): boolean;
7
7
  export function pushChanges(afterPushCallback?: undefined): void;
8
8
  export function xpushChanges(afterPushCallback?: undefined): void;
9
+ export function pushChangesImmediately(): Promise<void>;
9
10
  export const unsavedModificationsTicket: import("svelte/store").Writable<number>;
package/updates.js CHANGED
@@ -11,6 +11,10 @@ const modified_item_store = writable(null);
11
11
  export function setjItemProperty(item, field_name, value)
12
12
  {
13
13
  console.log('setjItemProperty ' + field_name)
14
+
15
+ if(item[field_name] == value)
16
+ return
17
+
14
18
  let type_name = item.$type;
15
19
  item[field_name] = value;
16
20
  informModification(item, field_name, type_name);
@@ -118,6 +122,9 @@ export function pushChanges(afterPushCallback=undefined)
118
122
  {
119
123
  //console.trace()
120
124
 
125
+ if(!modified_items_map.size)
126
+ return;
127
+
121
128
  if(afterPushCallback)
122
129
  afterPushCallbacks.push(afterPushCallback);
123
130
 
@@ -154,9 +161,25 @@ modified_item_store.subscribe((mod_item) => {
154
161
  export const unsavedModificationsTicket = writable(0);
155
162
 
156
163
  update_request_ticket.subscribe(async (v) => {
157
- if(v != last_update_ticket)
164
+ flushChanges(v)
165
+ })
166
+
167
+ export async function pushChangesImmediately()
168
+ {
169
+ if(!modified_items_map.size)
170
+ return;
171
+
172
+ const ticket = get(update_request_ticket) + 1
173
+ update_request_ticket.set(ticket)
174
+
175
+ await flushChanges(ticket);
176
+ }
177
+
178
+ async function flushChanges(ticket)
179
+ {
180
+ if(ticket != last_update_ticket)
158
181
  {
159
- last_update_ticket = v;
182
+ last_update_ticket = ticket;
160
183
 
161
184
  if(!modified_items_map.size)
162
185
  return;
@@ -203,7 +226,7 @@ update_request_ticket.subscribe(async (v) => {
203
226
  {
204
227
  modified_items_map.clear();
205
228
  unsavedModificationsTicket.set( get(unsavedModificationsTicket) + 1 )
206
-
229
+
207
230
  afterPushCallbacks.forEach( cb => cb())
208
231
  afterPushCallbacks = []
209
232
  }
@@ -220,4 +243,4 @@ update_request_ticket.subscribe(async (v) => {
220
243
  }
221
244
 
222
245
  }
223
- })
246
+ }
package/utils.d.ts CHANGED
@@ -83,3 +83,7 @@ export namespace UI {
83
83
  export const NAVIGATION_PAGE_PATH: "/nav";
84
84
  export const NAV_MODE_SIDEBAR: 0;
85
85
  export const NAV_MODE_FULL_PAGE: 1;
86
+ export namespace fetchHandlers {
87
+ const onBefore: ((path: any) => void)[];
88
+ const onError: ((err: any, res: any) => void)[];
89
+ }
package/utils.js CHANGED
@@ -1,9 +1,10 @@
1
1
  import { getContext, tick } from "svelte";
2
2
  import {derived, get} from 'svelte/store'
3
- import { contextItemsStore, contextToolbarOperations, pageToolbarOperations, data_tick_store, main_sidebar_visible_store, show_sidebar, hide_sidebar, previously_visible_sidebar, auto_hide_sidebar, reloadWholeApp} from "./stores";
3
+ import { contextItemsStore, contextToolbarOperations, pageToolbarOperations, data_tick_store, main_sidebar_visible_store, show_sidebar, hide_sidebar, previously_visible_sidebar, auto_hide_sidebar, reloadWholeApp, onErrorShowAlert} from "./stores";
4
4
  import {location, push, pop} from 'svelte-spa-router'
5
5
  import {session, reef} from '@humandialog/auth.svelte'
6
6
  import { i18n } from "./i18n";
7
+ import {pushChangesImmediately} from './updates'
7
8
 
8
9
  export let icons = {symbols :null}
9
10
 
@@ -366,8 +367,8 @@ export function editable(node, params)
366
367
 
367
368
  let observer = null;
368
369
  let has_changed = false;
370
+ let org_text = '';
369
371
 
370
- const org_text = node.textContent;
371
372
  const blur_listener = async (e) =>
372
373
  {
373
374
  if(currentEditable == node)
@@ -403,13 +404,9 @@ export function editable(node, params)
403
404
  {
404
405
  case 'Esc':
405
406
  case 'Escape':
406
- if(!active)
407
- {
408
- e.stopPropagation();
409
- e.preventDefault();
410
-
411
- await finish_editing({ cancel: true });
412
- }
407
+ e.stopPropagation();
408
+ e.preventDefault();
409
+ await finish_editing({ cancel: true });
413
410
  break;
414
411
 
415
412
  case 'Enter':
@@ -447,16 +444,17 @@ export function editable(node, params)
447
444
  const cancel = params.cancel ?? false;
448
445
  const incremental = params.incremental ?? false;
449
446
 
447
+ node.removeEventListener("blur", blur_listener);
448
+ node.removeEventListener("keydown", key_listener);
449
+ node.removeEventListener("save", save_listener);
450
+
450
451
  if(!active)
451
- {
452
- node.removeEventListener("blur", blur_listener);
453
- node.removeEventListener("keydown", key_listener);
454
- node.removeEventListener("save", save_listener);
455
452
  node.contentEditable = "false"
453
+ else
454
+ node.blur()
456
455
 
457
- let sel = window.getSelection();
458
- sel.removeAllRanges();
459
- }
456
+ let sel = window.getSelection();
457
+ sel.removeAllRanges();
460
458
 
461
459
  if(cancel)
462
460
  {
@@ -468,17 +466,11 @@ export function editable(node, params)
468
466
  }
469
467
  else if(action)
470
468
  {
471
- if(active)
469
+ if(has_changed)
472
470
  {
473
- if(has_changed)
474
- {
475
- has_changed = false;
476
- await action(node.textContent)
477
- }
478
-
479
- }
480
- else
471
+ has_changed = false;
481
472
  await action(node.textContent)
473
+ }
482
474
  }
483
475
 
484
476
  const finish_event = new CustomEvent("finish", {
@@ -505,28 +497,23 @@ export function editable(node, params)
505
497
  const edit_listener = async (e) =>
506
498
  {
507
499
  node.contentEditable = "true"
508
- node.addEventListener("blur", blur_listener);
509
- node.addEventListener("keydown", key_listener);
510
-
511
- currentEditable = node;
512
- node.addEventListener("save", save_listener)
513
-
514
500
  node.focus();
515
501
 
516
- /*await tick();
502
+ await tick();
503
+
517
504
  let range = document.createRange();
518
505
  range.selectNodeContents(node);
519
506
  let end_offset = range.endOffset;
520
507
  let end_container = range.endContainer;
521
508
  range.setStart(end_container, 0)
522
- range.setEnd(end_container, end_offset)
509
+ range.setEnd(end_container, 0)
523
510
  //range.setStart(node, 0)
524
511
  //range.setEnd(node, 0)
525
512
  // console.log('range rect: ', range.getBoundingClientRect())
526
513
  let sel = window.getSelection();
527
514
  sel.removeAllRanges();
528
515
  sel.addRange(range);
529
- */
516
+
530
517
  }
531
518
 
532
519
  const focus_listener = async (e) =>
@@ -543,6 +530,8 @@ export function editable(node, params)
543
530
  onSingleChange(node.textContent)
544
531
  });
545
532
 
533
+ org_text = node.textContent;
534
+
546
535
  observer.observe( node, {
547
536
  childList: true,
548
537
  attributes: true,
@@ -553,28 +542,26 @@ export function editable(node, params)
553
542
  node.classList.add("editable")
554
543
  node.classList.add("focus:outline-none")
555
544
 
545
+ node.addEventListener('focus', focus_listener);
546
+ node.addEventListener("edit", edit_listener);
547
+
548
+ if(onFinish)
549
+ node.addEventListener("finish", (e) => { onFinish(e.detail) })
550
+
556
551
  if(active)
557
- {
558
552
  node.contentEditable = "true"
559
- node.addEventListener('focus', focus_listener);
560
-
561
- if(onFinish)
562
- {
563
- node.addEventListener("finish", (e) => { onFinish(e.detail) })
564
- }
565
- }
566
- else
567
- {
568
- node.addEventListener("edit", edit_listener);
553
+
554
+ return {
555
+ destroy() {
569
556
 
570
- return {
571
- destroy() {
557
+ node.removeEventListener("edit", edit_listener)
558
+ node.removeEventListener('focus', focus_listener);
559
+ if(onFinish)
560
+ node.removeEventListener("finish", (e) => { onFinish(e.detail) })
572
561
 
573
- node.removeEventListener("edit", edit_listener)
574
- node.classList.remove("editable")
575
- node.contentEditable = "false"
576
- }};
577
- }
562
+ node.classList.remove("editable")
563
+
564
+ }};
578
565
  }
579
566
 
580
567
  export function startEditing(element, finish_callback)
@@ -1289,4 +1276,17 @@ function launchNewGroupWizzard(afterGroupCreated=undefined)
1289
1276
  });
1290
1277
 
1291
1278
  dialog.show()
1279
+ }
1280
+
1281
+
1282
+
1283
+ export const fetchHandlers = {
1284
+ onBefore: [
1285
+ (path) => { pushChangesImmediately() }
1286
+ ],
1287
+
1288
+ //onAfter: [],
1289
+ onError: [
1290
+ (err, res) => onErrorShowAlert(err)
1291
+ ]
1292
1292
  }