Skip to content

Commit

Permalink
XbelSerializer: Use fast-xml-parser instead of DOMParser to allow it …
Browse files Browse the repository at this point in the history
…to function in service worker
  • Loading branch information
marcelklehr committed Aug 25, 2023
1 parent 57f760f commit 995a53b
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 75 deletions.
40 changes: 40 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
"cordova-plugin-foreground-service": "^1.1.3",
"cordova-plugin-inappbrowser": "^5.0.0",
"core-js": "3.x",
"fast-xml-parser": "^4.2.7",
"humanize-duration": "^3.25.1",
"intl-messageformat": "^9.9.1",
"js-base64": "^3.7.5",
Expand Down
29 changes: 20 additions & 9 deletions src/lib/adapters/WebDav.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,16 +145,27 @@ export default class WebDavAdapter extends CachingAdapter {
let res, lockFreed, i = 0
try {
do {
res = await Http.request({
url: fullUrl,
method: 'DELETE',
headers: {
Authorization: 'Basic ' + authString
},
webFetchExtra: {
if (Capacitor.getPlatform() === 'web') {
res = await fetch(fullUrl, {
method: 'DELETE',
credentials: 'omit',
}
})
headers: {
Authorization: 'Basic ' + authString
},
...(!this.server.allowRedirects && {redirect: 'manual'}),
})
} else {
res = await Http.request({
url: fullUrl,
method: 'DELETE',
headers: {
Authorization: 'Basic ' + authString
},
webFetchExtra: {
credentials: 'omit',
}
})
}
lockFreed = res.status === 200 || res.status === 204 || res.status === 404
if (!lockFreed) {
await this.timeout(1000)
Expand Down
123 changes: 59 additions & 64 deletions src/lib/serializers/Xbel.ts
Original file line number Diff line number Diff line change
@@ -1,95 +1,90 @@
import Serializer from '../interfaces/Serializer'
import { Bookmark, Folder, ItemLocation } from '../Tree'
import { XMLParser, XMLBuilder } from 'fast-xml-parser'

class XbelSerializer implements Serializer {
serialize(folder) {
return this._serializeFolder(folder, '')
serialize(folder: Folder) {
const xbelObj = this._serializeFolder(folder)
const xmlBuilder = new XMLBuilder({format: true, preserveOrder: true, ignoreAttributes: false})
return xmlBuilder.build(xbelObj)
}

deserialize(xbel) {
const xmlDoc = new DOMParser().parseFromString(
xbel,
'application/xml'
)
const nodeList = xmlDoc.getElementsByTagName('xbel')
if (!nodeList.length) {
deserialize(xbel: string) {
const parser = new XMLParser({preserveOrder: true, ignorePiTags: true, ignoreAttributes: false})
const xmlObj = parser.parse(xbel)

if (!Array.isArray(xmlObj[0].xbel)) {
throw new Error(
'Parse Error: ' + new XMLSerializer().serializeToString(xmlDoc)
'Parse Error: ' + xbel
)
}

const rootFolder = new Folder({ id: 0, title: 'root', location: ItemLocation.SERVER })
this._parseFolder(nodeList[0], rootFolder)
try {
this._parseFolder(xmlObj[0].xbel, rootFolder)
} catch (e) {
throw new Error(
'Parse Error: ' + e.message
)
}
return rootFolder
}

_parseFolder(xbelObj, folder) {
_parseFolder(xbelObj, folder: Folder) {
/* parse depth first */

xbelObj.childNodes.forEach(node => {
let item
if (node.tagName && node.tagName === 'bookmark') {
item = new Bookmark({
id: parseInt(node.id),
parentId: folder.id,
url: node.getAttribute('href'),
title: node.firstElementChild.textContent,
location: ItemLocation.SERVER,
})
} else if (node.tagName && node.tagName === 'folder') {
item = new Folder({
id: parseInt(node.getAttribute('id')),
title: node.firstElementChild.textContent,
parentId: folder.id,
location: ItemLocation.SERVER,
})
this._parseFolder(node, item)
} else {
return
}
xbelObj
.forEach(node => {
let item
if (typeof node.bookmark !== 'undefined') {
item = new Bookmark({
id: parseInt(node[':@']['@_id']),
parentId: folder.id,
url: node[':@']['@_href'],
title: node.bookmark[0]['#text'],
location: ItemLocation.SERVER,
})
} else if (typeof node.folder !== 'undefined') {
item = new Folder({
id: parseInt(node[':@']['@_id']),
title: node[':@']['@_title'],
parentId: folder.id,
location: ItemLocation.SERVER,
})
this._parseFolder(node.folder, item)
} else {
return
}

folder.children.push(item)
})
folder.children.push(item)
})
}

_serializeFolder(folder, indent) {
/* Dummy XML document so we can create XML Elements */
const xmlDocument = new DOMParser().parseFromString(
'<xml></xml>',
'application/xml'
)

_serializeFolder(folder: Folder) {
return folder.children
.map(child => {
if (child instanceof Bookmark) {
const bookmark = xmlDocument.createElement('bookmark')
bookmark.setAttribute('href', child.url)
bookmark.setAttribute('id', String(child.id))
const title = xmlDocument.createElement('title')
title.textContent = child.title
bookmark.appendChild(title)
return new XMLSerializer().serializeToString(
bookmark
)
return {
bookmark: [
{'#text': child.title}
],
':@': {
'@_href': child.url,
'@_id': String(child.id)
}
}
}

if (child instanceof Folder) {
const folder = xmlDocument.createElement('folder')
if ('id' in child) {
folder.setAttribute('id', String(child.id))
return {
folder: this._serializeFolder(child),
':@': {
...('id' in child && {'@_id': String(child.id)}),
'@_title': child.title,
}
}

const title = xmlDocument.createElement('title')
title.textContent = child.title
folder.appendChild(title)

folder.innerHTML += this._serializeFolder(child, indent + ' ')
return new XMLSerializer().serializeToString(
folder
)
}
})
.join('\r\n' + indent)
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,14 +100,14 @@ describe('Floccus', function() {
type: 'webdav',
url: `${SERVER}/remote.php/webdav/`,
bookmark_file: 'bookmarks.xbel',
bookmark_file_type: 'xml',
bookmark_file_type: 'xbel',
...CREDENTIALS
},
{
type: 'webdav',
url: `${SERVER}/remote.php/webdav/`,
bookmark_file: 'bookmarks.xbel',
bookmark_file_type: 'xml',
bookmark_file_type: 'xbel',
passphrase: random.float(),
...CREDENTIALS
},
Expand Down

0 comments on commit 995a53b

Please sign in to comment.