@silexlabs/silex 3.5.1-1 → 3.5.1-2

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.
@@ -59,13 +59,27 @@ function clonePage(editor: Editor, page: Page) {
59
59
  while(pages.find(p => p.getName() === pageName)) {
60
60
  pageName = `${newPageName} ${idx++}`
61
61
  }
62
- // Clone components
63
- const body = page.getMainComponent().clone()
64
- // Add page
62
+
63
+ // Clone components using Backbone approach
64
+ const sourceBody = page.getMainComponent()
65
+ const clonedComponents = sourceBody.clone()
66
+
67
+ // Get custom props but exclude frames (Backbone collection) using toJSON and delete
68
+ const customProps = { ...page.toJSON() }
69
+ delete customProps.frames
70
+ delete customProps.id
71
+ delete customProps._undo
72
+
73
+ // Create new page with custom props (but not frames collection)
65
74
  const newPage = editor.Pages.add({
75
+ ...customProps,
66
76
  name: pageName,
67
- component: body.toJSON(),
68
77
  })
78
+
79
+ // Reset components with cloned ones
80
+ const targetBody = newPage.getMainComponent()
81
+ targetBody.components().reset(clonedComponents.components().models)
82
+
69
83
  // Select the new page
70
84
  editor.Pages.select(newPage)
71
85
  }
@@ -142,6 +156,92 @@ function renderPages(editor, config) {
142
156
  e.stopPropagation()
143
157
  return editor.Pages.get(el.getAttribute('data-page-id'))
144
158
  }
159
+
160
+ // Drag and drop handlers
161
+ let draggedPage: Page | null = null
162
+ let draggedPageElement: HTMLElement | null = null
163
+
164
+ const handleDragStart = (e: DragEvent, page: Page) => {
165
+ e.stopPropagation()
166
+ draggedPage = page
167
+ // Find the parent page element
168
+ draggedPageElement = (e.target as HTMLElement).closest('.pages__page') as HTMLElement
169
+ if (e.dataTransfer && draggedPageElement) {
170
+ e.dataTransfer.effectAllowed = 'move'
171
+ e.dataTransfer.setData('text/html', draggedPageElement.innerHTML)
172
+ draggedPageElement.classList.add('pages__page-dragging')
173
+ }
174
+ }
175
+
176
+ const handleDragEnd = (e: DragEvent) => {
177
+ if (draggedPageElement) {
178
+ draggedPageElement.classList.remove('pages__page-dragging')
179
+ }
180
+ draggedPage = null
181
+ draggedPageElement = null
182
+ }
183
+
184
+ const handleDragOver = (e: DragEvent) => {
185
+ if (!draggedPage) return
186
+ e.preventDefault()
187
+ e.stopPropagation()
188
+ if (e.dataTransfer) {
189
+ e.dataTransfer.dropEffect = 'move'
190
+ }
191
+ return false
192
+ }
193
+
194
+ const handleDragEnter = (e: DragEvent, page: Page) => {
195
+ if (draggedPage && draggedPage !== page) {
196
+ e.preventDefault()
197
+ e.stopPropagation()
198
+ }
199
+ }
200
+
201
+ const handleDragLeave = (e: DragEvent) => {
202
+ // No-op: visual indicator removed
203
+ }
204
+
205
+ const handleDrop = (e: DragEvent, targetPage: Page) => {
206
+ e.stopPropagation()
207
+ e.preventDefault()
208
+
209
+ if (draggedPage && draggedPage !== targetPage) {
210
+ const pages = editor.Pages.getAll()
211
+ const fromIndex = pages.indexOf(draggedPage)
212
+ const toIndex = pages.indexOf(targetPage)
213
+
214
+ if (fromIndex !== -1 && toIndex !== -1 && fromIndex !== toIndex) {
215
+ // Access the internal Backbone collection
216
+ const pagesCollection = (editor.Pages as any).pages
217
+
218
+ // Assign temporary order attributes for sorting
219
+ pages.forEach((page, idx) => {
220
+ let newOrder = idx
221
+ if (idx === fromIndex) {
222
+ newOrder = toIndex
223
+ } else if (fromIndex < toIndex && idx > fromIndex && idx <= toIndex) {
224
+ newOrder = idx - 1
225
+ } else if (fromIndex > toIndex && idx >= toIndex && idx < fromIndex) {
226
+ newOrder = idx + 1
227
+ }
228
+ page.set('_tempOrder', newOrder, { silent: true })
229
+ })
230
+
231
+ // Sort the collection by the temporary order
232
+ const originalComparator = pagesCollection.comparator
233
+ pagesCollection.comparator = (page: Page) => page.get('_tempOrder')
234
+ pagesCollection.sort()
235
+ pagesCollection.comparator = originalComparator
236
+
237
+ // Clean up temporary attributes
238
+ pages.forEach(page => page.unset('_tempOrder', { silent: true }))
239
+ }
240
+ }
241
+
242
+ return false
243
+ }
244
+
145
245
  return html`<section class="pages">
146
246
  <main class="pages__main ${pages.length === 1 ? 'pages__single-page' : ''}">
147
247
  <div class="pages__list">
@@ -150,8 +250,22 @@ function renderPages(editor, config) {
150
250
  const name = page.getName() || type
151
251
  // keep the same structure as the layers panel
152
252
  return html`
153
- <div class="pages__page ${selected === page ? 'pages__page-selected' : ''}" data-page-id=${page.id} @click=${e => selectPage(editor, getPageFromEvent(e))}>
253
+ <div
254
+ class="pages__page ${selected === page ? 'pages__page-selected' : ''}"
255
+ data-page-id=${page.id}
256
+ @click=${e => selectPage(editor, getPageFromEvent(e))}
257
+ @dragover=${handleDragOver}
258
+ @dragenter=${(e: DragEvent) => handleDragEnter(e, page)}
259
+ @dragleave=${handleDragLeave}
260
+ @drop=${(e: DragEvent) => handleDrop(e, page)}
261
+ >
154
262
  <div class="pages__page-name">
263
+ <i
264
+ class="pages__icon pages__drag-handle fa fa-grip-vertical"
265
+ draggable="true"
266
+ @dragstart=${(e: DragEvent) => handleDragStart(e, page)}
267
+ @dragend=${handleDragEnd}
268
+ ></i>
155
269
  ${ name }
156
270
  </div>
157
271
  <i class="pages__icon pages__remove-btn fa fa-trash" @click=${e => removePage(editor, getPageFromEvent(e))}></i>
@@ -39,6 +39,10 @@ const tagCategories = [
39
39
  label: 'Content grouping',
40
40
  tags: ['ADDRESS', 'BLOCKQUOTE', 'PRE'],
41
41
  },
42
+ {
43
+ label: 'Lists',
44
+ tags: ['UL', 'OL', 'LI'],
45
+ },
42
46
  {
43
47
  label: 'Interactive/form',
44
48
  tags: ['BUTTON', 'LABEL', 'DETAILS', 'SUMMARY'],
@@ -104,7 +104,11 @@ export const storagePlugin = (editor: PublishableEditor) => {
104
104
  if (firstPage) editor.Pages.select(firstPage)
105
105
  loader && render(getLoaderHtml('Starting', 1, 1), loader)
106
106
  await nextFrame()
107
- editor.once('canvas:frame:load', () => editor.stopCommand(cmdPauseAutoSave))
107
+ editor.once('canvas:frame:load', () => {
108
+ setTimeout(() => { // This is needed in chrome, otherwise a save is triggered
109
+ editor.stopCommand(cmdPauseAutoSave)
110
+ }, 500)
111
+ })
108
112
  return data
109
113
  }
110
114
  } catch (err) {
@@ -142,7 +146,7 @@ export const storagePlugin = (editor: PublishableEditor) => {
142
146
  },
143
147
 
144
148
  async doStore(data: WebsiteData, options: { id: WebsiteId, connectorId: ConnectorId }) {
145
- if (editor.PublicationManager.status === PublicationStatus.STATUS_PENDING) {
149
+ if (editor.PublicationManager?.status === PublicationStatus.STATUS_PENDING) {
146
150
  // Publication is pending, save is delayed
147
151
  return new Promise((resolve) => {
148
152
  editor.once(ClientEvent.PUBLISH_END, () => {