Showing preview only (2,328K chars total). Download the full file or copy to clipboard to get everything.
Repository: floccusaddon/floccus
Branch: develop
Commit: ef25de4af696
Files: 268
Total size: 2.2 MB
Directory structure:
gitextract_bb9v7fk9/
├── .all-contributorsrc
├── .eslintrc.json
├── .github/
│ ├── FUNDING.yml
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.yml
│ │ ├── config.yml
│ │ └── feature_request.yml
│ ├── dependabot.yml
│ └── workflows/
│ ├── build.yml
│ ├── codeql-analysis.yml
│ ├── dependabot-approve.yml
│ ├── issues.yml
│ ├── lock-threads.yml
│ ├── stale.yml
│ └── tests.yml
├── .gitignore
├── .prettierrc
├── CHANGELOG.md
├── CONSIDERATIONS.md
├── LICENSE.txt
├── PRIVACY_POLICY.md
├── README.md
├── _locales/
│ ├── cs/
│ │ └── messages.json
│ ├── de/
│ │ └── messages.json
│ ├── el/
│ │ └── messages.json
│ ├── en/
│ │ └── messages.json
│ ├── es/
│ │ └── messages.json
│ ├── es_ES/
│ │ └── messages.json
│ ├── et/
│ │ └── messages.json
│ ├── fi/
│ │ └── messages.json
│ ├── fr/
│ │ └── messages.json
│ ├── gl/
│ │ └── messages.json
│ ├── it/
│ │ └── messages.json
│ ├── ja/
│ │ └── messages.json
│ ├── ko_KR/
│ │ └── messages.json
│ ├── nb/
│ │ └── messages.json
│ ├── nl_NL/
│ │ └── messages.json
│ ├── pl/
│ │ └── messages.json
│ ├── pt/
│ │ └── messages.json
│ ├── pt_BR/
│ │ └── messages.json
│ ├── pt_PT/
│ │ └── messages.json
│ ├── ro_RO/
│ │ └── messages.json
│ ├── ru/
│ │ └── messages.json
│ ├── sk/
│ │ └── messages.json
│ ├── sv/
│ │ └── messages.json
│ ├── tr/
│ │ └── messages.json
│ ├── tr_TR/
│ │ └── messages.json
│ ├── zh/
│ │ └── messages.json
│ ├── zh-Hans/
│ │ └── messages.json
│ ├── zh_CN/
│ │ └── messages.json
│ └── zh_TW/
│ └── messages.json
├── android/
│ ├── .gitignore
│ ├── app/
│ │ ├── .gitignore
│ │ ├── build.gradle
│ │ ├── capacitor.build.gradle
│ │ ├── proguard-rules.pro
│ │ └── src/
│ │ └── main/
│ │ ├── AndroidManifest.xml
│ │ ├── assets/
│ │ │ ├── capacitor.config.json
│ │ │ └── capacitor.plugins.json
│ │ ├── java/
│ │ │ └── org/
│ │ │ └── handmadeideas/
│ │ │ └── floccus/
│ │ │ └── MainActivity.java
│ │ └── res/
│ │ ├── drawable-v26/
│ │ │ ├── ic_launcher_foreground.xml
│ │ │ └── notification_icon.xml
│ │ ├── layout/
│ │ │ └── activity_main.xml
│ │ ├── mipmap-anydpi-v26/
│ │ │ ├── ic_launcher.xml
│ │ │ └── ic_launcher_round.xml
│ │ ├── values/
│ │ │ ├── ic_launcher_background.xml
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ │ └── xml/
│ │ ├── config.xml
│ │ ├── file_paths.xml
│ │ └── network_security_config.xml
│ ├── build.gradle
│ ├── capacitor.settings.gradle
│ ├── gradle/
│ │ └── wrapper/
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
│ ├── gradle.properties
│ ├── gradlew
│ ├── gradlew.bat
│ ├── settings.gradle
│ └── variables.gradle
├── capacitor.config.json
├── doc/
│ └── Adapters.md
├── doiuse-report.baseline.txt
├── dropbox-api.credentials.json
├── fastlane/
│ └── metadata/
│ └── android/
│ └── en-US/
│ ├── full_description.txt
│ └── short_description.txt
├── google-api.credentials.json
├── gulpfile.js
├── html/
│ ├── background.html
│ ├── index.html
│ ├── options.html
│ └── test.html
├── img/
│ ├── promotional-tile-medium.xcf
│ ├── promotional-tile-medium2.xcf
│ └── promotional-tile-small.xcf
├── ios/
│ ├── .gitignore
│ └── App/
│ ├── App/
│ │ ├── App.entitlements
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets/
│ │ │ ├── AppIcon.appiconset/
│ │ │ │ └── Contents.json
│ │ │ ├── Contents.json
│ │ │ └── Splash.imageset/
│ │ │ └── Contents.json
│ │ ├── Base.lproj/
│ │ │ ├── LaunchScreen.storyboard
│ │ │ └── Main.storyboard
│ │ ├── Info.plist
│ │ ├── capacitor.config.json
│ │ └── config.xml
│ ├── App.xcodeproj/
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace/
│ │ │ ├── contents.xcworkspacedata
│ │ │ └── xcshareddata/
│ │ │ └── IDEWorkspaceChecks.plist
│ │ └── xcshareddata/
│ │ └── xcschemes/
│ │ ├── Floccus New Bookmark.xcscheme
│ │ └── Floccus.xcscheme
│ ├── App.xcworkspace/
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata/
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── WorkspaceSettings.xcsettings
│ ├── Floccus New Bookmark/
│ │ ├── Base.lproj/
│ │ │ └── MainInterface.storyboard
│ │ ├── Floccus New Bookmark.entitlements
│ │ ├── Info.plist
│ │ └── ShareViewController.swift
│ ├── Floccus.entitlements
│ ├── Podfile
│ └── PrivacyInfo.xcprivacy
├── lib/
│ └── gulp-crx.js
├── manifest-firefox-override.sh
├── manifest.chrome.json
├── manifest.firefox.json
├── manifest.json
├── package.json
├── src/
│ ├── build-fixtures/
│ │ └── lazyLoadIntegration.js
│ ├── entries/
│ │ ├── background-script.js
│ │ ├── native.js
│ │ ├── options.js
│ │ └── test.js
│ ├── errors/
│ │ └── Error.ts
│ ├── lib/
│ │ ├── Account.ts
│ │ ├── AdapterFactory.ts
│ │ ├── CacheTree.ts
│ │ ├── CachingTreeWrapper.ts
│ │ ├── Controller.ts
│ │ ├── Crypto.ts
│ │ ├── DefunctCrypto.js
│ │ ├── Diff.ts
│ │ ├── LocalTabs.ts
│ │ ├── Logger.js
│ │ ├── Mappings.ts
│ │ ├── PathHelper.js
│ │ ├── Scanner.ts
│ │ ├── Tree.ts
│ │ ├── adapters/
│ │ │ ├── Caching.ts
│ │ │ ├── Dropbox.ts
│ │ │ ├── Fake.js
│ │ │ ├── Git.ts
│ │ │ ├── GoogleDrive.ts
│ │ │ ├── Karakeep.ts
│ │ │ ├── Linkwarden.ts
│ │ │ ├── NextcloudBookmarks.ts
│ │ │ └── WebDav.ts
│ │ ├── browser/
│ │ │ ├── BrowserAccount.ts
│ │ │ ├── BrowserAccountStorage.js
│ │ │ ├── BrowserController.js
│ │ │ ├── BrowserDetection.ts
│ │ │ └── BrowserTree.ts
│ │ ├── browser-api.js
│ │ ├── getFavicon.js
│ │ ├── interfaces/
│ │ │ ├── Account.ts
│ │ │ ├── AccountStorage.ts
│ │ │ ├── Adapter.ts
│ │ │ ├── Controller.ts
│ │ │ ├── Ordering.ts
│ │ │ ├── Resource.ts
│ │ │ └── Serializer.ts
│ │ ├── isTest.ts
│ │ ├── murmurhash3.js
│ │ ├── native/
│ │ │ ├── I18n.ts
│ │ │ ├── NativeAccount.ts
│ │ │ ├── NativeAccountStorage.js
│ │ │ ├── NativeController.js
│ │ │ └── NativeTree.ts
│ │ ├── on-wake-up.ts
│ │ ├── sentry.ts
│ │ ├── serializers/
│ │ │ ├── Html.ts
│ │ │ └── Xbel.ts
│ │ ├── statusCodes.ts
│ │ ├── strategies/
│ │ │ ├── Default.ts
│ │ │ ├── Merge.ts
│ │ │ └── Unidirectional.ts
│ │ └── yieldToEventLoop.ts
│ ├── test/
│ │ ├── index.js
│ │ ├── reporter.js
│ │ └── test.js
│ └── ui/
│ ├── App.vue
│ ├── NativeApp.vue
│ ├── NativeRouter.js
│ ├── components/
│ │ ├── AccountCard.vue
│ │ ├── NextcloudLogin.vue
│ │ ├── OptionAllowRedirects.vue
│ │ ├── OptionAutoSync.vue
│ │ ├── OptionClientCert.vue
│ │ ├── OptionDeleteAccount.vue
│ │ ├── OptionDownloadLogs.vue
│ │ ├── OptionExportBookmarks.vue
│ │ ├── OptionFailsafe.vue
│ │ ├── OptionFileType.vue
│ │ ├── OptionNestedSync.vue
│ │ ├── OptionPassphrase.vue
│ │ ├── OptionResetCache.vue
│ │ ├── OptionSyncFolder.vue
│ │ ├── OptionSyncInterval.vue
│ │ ├── OptionSyncIntervalEnabled.vue
│ │ ├── OptionSyncStrategy.vue
│ │ ├── OptionsDropbox.vue
│ │ ├── OptionsFake.vue
│ │ ├── OptionsGit.vue
│ │ ├── OptionsGoogleDrive.vue
│ │ ├── OptionsKarakeep.vue
│ │ ├── OptionsLinkwarden.vue
│ │ ├── OptionsNextcloudBookmarks.vue
│ │ ├── OptionsNextcloudLegacy.vue
│ │ ├── OptionsWebdav.vue
│ │ └── native/
│ │ ├── Breadcrumbs.vue
│ │ ├── DialogChooseFolder.vue
│ │ ├── DialogEditBookmark.vue
│ │ ├── DialogEditFolder.vue
│ │ ├── DialogImportBookmarks.vue
│ │ ├── Drawer.vue
│ │ ├── FaviconImage.vue
│ │ ├── Item.vue
│ │ └── OptionAllowNetwork.vue
│ ├── index.js
│ ├── native-public-path.js
│ ├── native.js
│ ├── plugins/
│ │ ├── capacitor.js
│ │ ├── i18n.js
│ │ └── vuetify.js
│ ├── router.js
│ ├── store/
│ │ ├── actions.js
│ │ ├── definitions.js
│ │ ├── index.js
│ │ ├── mutations.js
│ │ └── native/
│ │ ├── actions.js
│ │ ├── index.js
│ │ └── mutations.js
│ └── views/
│ ├── AccountOptions.vue
│ ├── Donate.vue
│ ├── Feedback.vue
│ ├── ImportExport.vue
│ ├── NewAccount.vue
│ ├── Overview.vue
│ ├── Telemetry.vue
│ ├── Update.vue
│ └── native/
│ ├── About.vue
│ ├── AddBookmarkIntent.vue
│ ├── Feedback.vue
│ ├── Home.vue
│ ├── ImportExport.vue
│ ├── NewAccount.vue
│ ├── Options.vue
│ ├── Telemetry.vue
│ ├── Tree.vue
│ └── Update.vue
├── supportedBrowsers.js
├── test/
│ ├── apache-vhost.conf
│ ├── apcu.ini
│ ├── save-stats.js
│ └── selenium-runner.js
├── transifex.yml
├── tsconfig.json
├── webpack.common.js
├── webpack.dev.js
└── webpack.prod.js
================================================
FILE CONTENTS
================================================
================================================
FILE: .all-contributorsrc
================================================
{
"projectName": "floccus",
"projectOwner": "floccusaddon",
"repoType": "github",
"repoHost": "https://github.com",
"files": [
"README.md"
],
"imageSize": 70,
"commit": true,
"contributors": [
{
"login": "bernd-wechner",
"name": "Bernd Wechner",
"avatar_url": "https://avatars2.githubusercontent.com/u/7296506?v=4",
"profile": "https://github.com/bernd-wechner",
"contributions": [
"bug",
"ideas",
"test"
]
},
{
"login": "jlbprof",
"name": "jlbprof",
"avatar_url": "https://avatars0.githubusercontent.com/u/9746421?v=4",
"profile": "https://github.com/jlbprof",
"contributions": [
"code",
"bug",
"test"
]
},
{
"login": "TeutonJon78",
"name": "TeutonJon78",
"avatar_url": "https://avatars2.githubusercontent.com/u/1771400?v=4",
"profile": "https://github.com/TeutonJon78",
"contributions": [
"bug",
"ideas"
]
},
{
"login": "skewty",
"name": "Scott P.",
"avatar_url": "https://avatars1.githubusercontent.com/u/9087223?v=4",
"profile": "https://github.com/skewty",
"contributions": [
"bug",
"ideas"
]
},
{
"login": "Lantizia",
"name": "Lantizia",
"avatar_url": "https://avatars1.githubusercontent.com/u/10448369?v=4",
"profile": "https://github.com/Lantizia",
"contributions": [
"bug",
"ideas"
]
},
{
"login": "TCB13",
"name": "TCB13",
"avatar_url": "https://avatars1.githubusercontent.com/u/6315832?v=4",
"profile": "https://iklive.eu",
"contributions": [
"code",
"ideas",
"plugin",
"translation"
]
},
{
"login": "gohrner",
"name": "gohrner ",
"avatar_url": "https://avatars0.githubusercontent.com/u/26199042?v=4",
"profile": "https://github.com/gohrner",
"contributions": [
"bug"
]
},
{
"login": "Tank-Missile",
"name": "Tank-Missile",
"avatar_url": "https://avatars0.githubusercontent.com/u/5893370?v=4",
"profile": "https://github.com/Tank-Missile",
"contributions": [
"bug"
]
},
{
"login": "tkurbad",
"name": "Torsten Kurbad",
"avatar_url": "https://avatars1.githubusercontent.com/u/158030?v=4",
"profile": "https://github.com/tkurbad",
"contributions": [
"bug"
]
},
{
"login": "gerroon",
"name": "gerroon",
"avatar_url": "https://avatars1.githubusercontent.com/u/8519469?v=4",
"profile": "https://github.com/gerroon",
"contributions": [
"bug"
]
},
{
"login": "mnalis",
"name": "Matija Nalis",
"avatar_url": "https://avatars.githubusercontent.com/u/156656?v=4",
"profile": "http://biciklijade.com/",
"contributions": [
"ideas",
"question",
"bug"
]
},
{
"login": "marcelklehr",
"name": "Marcel Klehr",
"avatar_url": "https://avatars.githubusercontent.com/u/986878?v=4",
"profile": "https://github.com/marcelklehr",
"contributions": [
"question",
"code",
"content",
"design",
"doc",
"infra",
"maintenance",
"projectManagement"
]
},
{
"login": "binsee",
"name": "binsee",
"avatar_url": "https://avatars.githubusercontent.com/u/5285894?v=4",
"profile": "https://github.com/binsee",
"contributions": [
"code"
]
},
{
"login": "mlshapiro",
"name": "Marc Shapiro",
"avatar_url": "https://avatars.githubusercontent.com/u/8190979?v=4",
"profile": "https://daitem.io/",
"contributions": [
"code"
]
},
{
"login": "marlluslustosa",
"name": "Marllus Lustosa",
"avatar_url": "https://avatars.githubusercontent.com/u/29416568?v=4",
"profile": "https://marllus.com/",
"contributions": [
"code"
]
},
{
"login": "IzzySoft",
"name": "Izzy",
"avatar_url": "https://avatars.githubusercontent.com/u/6781438?v=4",
"profile": "https://android.izzysoft.de/",
"contributions": [
"bug",
"ideas",
"infra"
]
},
{
"login": "sunjam",
"name": "sunjam",
"avatar_url": "https://avatars.githubusercontent.com/u/1787238?v=4",
"profile": "https://github.com/sunjam",
"contributions": [
"ideas",
"test"
]
},
{
"login": "dsiminiuk",
"name": "Danny Siminiuk",
"avatar_url": "https://avatars.githubusercontent.com/u/5713547?v=4",
"profile": "https://github.com/dsiminiuk",
"contributions": [
"test",
"ideas"
]
},
{
"login": "Seirade",
"name": "Seirade",
"avatar_url": "https://avatars.githubusercontent.com/u/45798662?v=4",
"profile": "https://github.com/Seirade",
"contributions": [
"ideas",
"bug"
]
},
{
"login": "pinpontitit",
"name": "pinpontitit",
"avatar_url": "https://avatars.githubusercontent.com/u/100489443?v=4",
"profile": "https://github.com/pinpontitit",
"contributions": [
"ideas",
"bug",
"code"
]
},
{
"login": "dmotte",
"name": "Motte",
"avatar_url": "https://avatars.githubusercontent.com/u/37443982?v=4",
"profile": "https://dmotte.github.io/",
"contributions": [
"code",
"bug"
]
},
{
"login": "macrogreg",
"name": "macrogreg",
"avatar_url": "https://avatars.githubusercontent.com/u/20691812?v=4",
"profile": "https://github.com/macrogreg",
"contributions": [
"code"
]
},
{
"login": "andybalaam",
"name": "Andy Balaam",
"avatar_url": "https://avatars.githubusercontent.com/u/76812?v=4",
"profile": "http://www.artificialworlds.net",
"contributions": [
"code",
"bug"
]
},
{
"login": "balthanon",
"name": "Balthanon",
"avatar_url": "https://avatars.githubusercontent.com/u/5367358?v=4",
"profile": "https://github.com/balthanon",
"contributions": [
"ideas",
"bug"
]
}
],
"skipCi": true,
"contributorsPerLine": 7,
"commitConvention": "none",
"commitType": "docs"
}
================================================
FILE: .eslintrc.json
================================================
{
"env": {
"browser": true,
"commonjs": true,
"es6": true,
"node": true,
"mocha": true
},
"parserOptions": {
"parser": "@typescript-eslint/parser",
"ecmaVersion": 6
},
"root": true,
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:import/errors",
"plugin:import/warnings",
"plugin:vue/recommended",
"plugin:mocha/recommended"
],
"settings": {
"import/resolver": {
"node": {
"paths": ["src"],
"extensions": [".js", ".vue", ".ts"]
}
}
},
"plugins": ["vue", "node", "mocha", "@typescript-eslint"],
"rules": {
"arrow-spacing": ["error", { "before": true, "after": true }],
"block-spacing": ["error", "always"],
"brace-style": ["error", "1tbs", { "allowSingleLine": true }],
"eqeqeq": ["error", "always", { "null": "ignore" }],
"func-call-spacing": ["error", "never"],
"indent": [
"error",
2,
{
"SwitchCase": 1,
"VariableDeclarator": 1,
"outerIIFEBody": 1,
"MemberExpression": 1,
"FunctionDeclaration": { "parameters": 1, "body": 1 },
"FunctionExpression": { "parameters": 1, "body": 1 },
"CallExpression": { "arguments": 1 },
"ArrayExpression": 1,
"ObjectExpression": 1,
"ImportDeclaration": 1,
"flatTernaryExpressions": false,
"ignoreComments": false
}
],
"key-spacing": ["error", { "beforeColon": false, "afterColon": true }],
"keyword-spacing": ["error", { "before": true, "after": true }],
"no-array-constructor": "error",
"no-caller": "error",
"no-class-assign": "error",
"no-compare-neg-zero": "error",
"no-cond-assign": "error",
"no-const-assign": "error",
"no-constant-condition": ["error", { "checkLoops": false }],
"no-control-regex": "error",
"no-debugger": "error",
"no-dupe-args": "error",
"no-dupe-class-members": "error",
"no-dupe-keys": "error",
"no-duplicate-case": "error",
"no-empty-character-class": "error",
"no-empty-pattern": "error",
"no-eval": "error",
"no-ex-assign": "error",
"no-extend-native": "error",
"no-extra-bind": "error",
"no-extra-boolean-cast": "error",
"no-extra-parens": ["error", "functions"],
"no-fallthrough": "error",
"no-floating-decimal": "error",
"no-func-assign": "error",
"no-global-assign": "error",
"no-implied-eval": "error",
"no-inner-declarations": ["error", "functions"],
"no-invalid-regexp": "error",
"no-irregular-whitespace": "error",
"no-iterator": "error",
"no-label-var": "error",
"no-labels": ["error", { "allowLoop": false, "allowSwitch": false }],
"no-lone-blocks": "error",
"no-mixed-operators": [
"error",
{
"groups": [
["==", "!=", "===", "!==", ">", ">=", "<", "<="],
["&&", "||"],
["in", "instanceof"]
],
"allowSamePrecedence": true
}
],
"no-mixed-spaces-and-tabs": "error",
"no-multi-spaces": "error",
"no-multi-str": "error",
"no-multiple-empty-lines": ["error", { "max": 1, "maxEOF": 0 }],
"no-negated-in-lhs": "error",
"no-new": "error",
"no-new-func": "error",
"no-new-object": "error",
"no-new-require": "error",
"no-new-symbol": "error",
"no-new-wrappers": "error",
"no-obj-calls": "error",
"no-octal": "error",
"no-octal-escape": "error",
"no-path-concat": "error",
"no-proto": "error",
"no-redeclare": "error",
"no-regex-spaces": "error",
"no-return-assign": ["error", "except-parens"],
"no-return-await": "error",
"no-self-assign": "error",
"no-self-compare": "error",
"no-sequences": "error",
"no-shadow-restricted-names": "error",
"no-sparse-arrays": "error",
"no-tabs": "error",
"no-template-curly-in-string": "error",
"no-this-before-super": "error",
"no-throw-literal": "error",
"no-trailing-spaces": "error",
"no-undef": "error",
"no-undef-init": "error",
"no-unexpected-multiline": "error",
"no-unmodified-loop-condition": "error",
"no-unneeded-ternary": ["error", { "defaultAssignment": false }],
"no-unreachable": "error",
"no-unsafe-finally": "error",
"no-unsafe-negation": "error",
"no-unused-expressions": [
"error",
{
"allowShortCircuit": true,
"allowTernary": true,
"allowTaggedTemplates": true
}
],
"no-unused-vars": [
"error",
{ "vars": "all", "args": "none", "ignoreRestSiblings": true }
],
"no-use-before-define": [
"warn",
{ "functions": false, "classes": false, "variables": false }
],
"no-useless-call": "error",
"no-useless-computed-key": "error",
"no-useless-constructor": "error",
"no-useless-escape": "error",
"no-useless-rename": "error",
"no-useless-return": "error",
"no-whitespace-before-property": "error",
"no-with": "error",
"object-property-newline": [
"error",
{ "allowMultiplePropertiesPerLine": true }
],
"operator-linebreak": [
"error",
"after",
{ "overrides": { "?": "before", ":": "before" } }
],
"padded-blocks": [
"error",
{ "blocks": "never", "switches": "never", "classes": "never" }
],
"prefer-promise-reject-errors": "error",
"quotes": [
"error",
"single",
{ "avoidEscape": true, "allowTemplateLiterals": true }
],
"rest-spread-spacing": ["error", "never"],
"semi": ["error", "never"],
"semi-spacing": ["error", { "before": false, "after": true }],
"space-before-blocks": ["error", "always"],
"space-before-function-paren": ["error", "never"],
"space-in-parens": ["error", "never"],
"space-infix-ops": "error",
"space-unary-ops": ["error", { "words": true, "nonwords": false }],
"spaced-comment": [
"error",
"always",
{
"line": { "markers": ["*package", "!", "/", ",", "="] },
"block": {
"balanced": true,
"markers": ["*package", "!", ",", ":", "::", "flow-include"],
"exceptions": ["*"]
}
}
],
"symbol-description": "error",
"template-curly-spacing": ["error", "never"],
"template-tag-spacing": ["error", "never"],
"unicode-bom": ["error", "never"],
"use-isnan": "error",
"valid-typeof": ["error", { "requireStringLiterals": true }],
"wrap-iife": ["error", "any", { "functionPrototypeMethods": true }],
"yield-star-spacing": ["error", "both"],
"yoda": ["error", "never"],
// PascalCase components names for vuejs
// https://vuejs.org/v2/style-guide/#Single-file-component-filename-casing-strongly-recommended
"vue/component-name-in-template-casing": ["error", "PascalCase"],
// force name
"vue/match-component-file-name": ["error", {
"extensions": ["jsx", "vue", "js"],
"shouldMatchCase": true
}],
// space before self-closing elements
"vue/html-closing-bracket-spacing": "error",
// no ending html tag on a new line
"vue/html-closing-bracket-newline": ["error", { "multiline": "never" }],
// expect.js...
"no-unused-expressions": ["off"],
"mocha/no-setup-in-describe": ["off"],
"mocha/no-skipped-tests": ["off"],
"vue/multi-word-component-names": ["off"],
"vue/no-mutating-props": ["off"]
}
}
================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms
github: marcelklehr # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: marcelklehr
open_collective: floccus
liberapay: marcelklehr
ko_fi: marcelklehr
custom: https://www.paypal.com/donate/?hosted_button_id=R3SDCC7AFSYZU
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.yml
================================================
name: Bug Report
description: Create a bug report for floccus
labels: ['bug']
body:
- type: markdown
attributes:
value: Thanks for taking the time to file a bug report! Please fill out this form as completely as possible.
- type: markdown
attributes:
value: If you leave out sections there is a high likelihood it will be moved to the GitHub Discussions.
- type: input
attributes:
label: Which version of floccus are you using?
description: 'Please specify the exact version instead of "latest". For example: 4.14.0'
validations:
required: true
- type: input
attributes:
label: How many bookmarks do you have, roughly?
description: 'e.g. 10, 300 or 12k'
validations:
required: true
- type: input
attributes:
label: Are you using other means to sync bookmarks in parallel to floccus?
description: 'e.g. "No" or "Yes, I also sync via Mozilla account"'
validations:
required: true
- type: dropdown
attributes:
label: Sync method
description: Which sync method are you using?
multiple: false
options:
- Nextcloud Bookmarks
- Linkwarden
- WebDAV
- Google Drive
- Dropbox
- Git
validations:
required: true
- type: input
attributes:
label: Which browser are you using? In case you are using the phone App, specify the Android or iOS version and device please.
description: 'Please specify the exact version instead of "latest". For example: Chrome 100.0.4878.0 or '
- type: input
attributes:
label: Which version of Nextcloud Bookmarks are you using? (if relevant)
description: 'For example: v10.1.0'
- type: input
attributes:
label: Which version of Nextcloud? (if relevant)
description: 'For example: v23.0.1'
- type: textarea
attributes:
label: What kind of WebDAV server are you using? (if relevant)
description: Describe the setup of your WebDAV server
- type: textarea
attributes:
label: Describe the Bug
description: A clear and concise description of what the bug is.
validations:
required: true
- type: textarea
attributes:
label: Expected Behavior
description: A clear and concise description of what you expected to happen.
validations:
required: true
- type: textarea
attributes:
label: To Reproduce
description: Steps to reproduce the behavior, please provide a clear number of steps that always reproduces the issue. Screenshots can be provided in the issue body below.
validations:
required: true
- type: markdown
attributes:
value: Before posting the issue go through the steps you've written down to make sure the steps provided are detailed and clear.
- type: markdown
attributes:
value: Contributors should be able to follow the steps provided in order to reproduce the bug.
- type: markdown
attributes:
value: It is often useful to provide a debug log file along with the issue. You can obtain a (redacted) debug log of the most recent sync run in the account settings of your floccus account.
- type: markdown
attributes:
value: You can also let floccus automatically redact your debug logs.
- type: checkboxes
attributes:
label: Debug log provided
options:
- label: I have provided a debug log file
required: false
- type: markdown
attributes:
value: "Please note: To continue development and maintenance of this project in a sustainable way, I ask that you donate to the project when opening a ticket (or at least once your issue is resolved), if you're not a donor already. You can find donation options at <https://floccus.org/donate/>. Thank you!"
================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: false
contact_links:
- name: Ask a question
url: https://github.com/floccusAddon/floccus/discussions
about: Ask questions and discuss with other community members
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.yml
================================================
name: Feature Request
description: Create a feature request for floccus
labels: ['enhancement']
body:
- type: markdown
attributes:
value: Thanks for taking the time to file a feature request! Please fill out this form as completely as possible.
- type: textarea
attributes:
label: Describe the feature you'd like to request
description: A clear and concise description of what you want and what your use case is.
validations:
required: true
- type: textarea
attributes:
label: Describe the solution you'd like
description: A clear and concise description of what you want to happen.
validations:
required: true
- type: textarea
attributes:
label: Describe alternatives you've considered
description: A clear and concise description of any alternative solutions or features you've considered.
validations:
required: true
================================================
FILE: .github/dependabot.yml
================================================
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
================================================
FILE: .github/workflows/build.yml
================================================
name: Build
on:
pull_request:
push:
branches:
- develop
- master
jobs:
js:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [20.x]
npm-version: [10.x]
name: js node${{ matrix.node-version }}
steps:
- uses: actions/checkout@v2
- name: Set up node ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: Set up npm ${{ matrix.npm-version }}
run: npm i -g npm@"${{ matrix.npm-version }}"
- name: Cache node modules
uses: actions/cache@v4
env:
cache-name: cache-node-modules
with:
path: ~/.npm # npm cache files are stored in `~/.npm` on Linux/macOS
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-build-${{ env.cache-name }}-
${{ runner.os }}-build-
${{ runner.os }}-
- name: Install dependencies
run: |
npm ci -f
- name: Install dependencies & build
run: |
npm run build-release --if-present
- name: Static check if sentry lazy loading is absent
run: |
grep -qvrni '"https://browser.sentry-cdn.com"' ./dist/js/ || (echo 'Problem: Build includes lazy-loading of components from sentry-cdn.com. This will get rejected by Chrome Webstore review!' && exit 1)
- name: Static check if css is compatible with the required browsers
run: |
npm run doiuse | sed 's/[^:]*:*//' | sed 's/> *//' > doiuse-report.txt
cat doiuse-report.txt
diff doiuse-report.txt doiuse-report.baseline.txt || (echo 'Problem: Build includes CSS that is not compatible with the required browsers. Please check the report above!' && exit 1)
- name: Save context
uses: actions/cache/save@v4
with:
key: build-context-${{ github.run_id }}
path: ./
android:
needs: js
runs-on: ubuntu-latest
strategy:
matrix:
java-version: [ 21 ]
name: android java${{ matrix.java-version }}
steps:
- uses: actions/setup-java@v4
with:
distribution: 'oracle'
java-version: ${{ matrix.java-version }}
- name: Restore context
uses: actions/cache/restore@v4
with:
fail-on-cache-miss: true
key: build-context-${{ github.run_id }}
path: ./
- name: Create JKS file from secrets
if: github.ref_name == 'develop' || github.ref_name == 'master'
env:
ANDROID_CERT: ${{ secrets.ANDROID_CERT }}
ANDROID_PRIV_KEY: ${{ secrets.ANDROID_PRIV_KEY }}
ANDROID_JKS_PASSWORD: ${{ secrets.ANDROID_JKS_PASSWORD }}
run: |
# Create temporary directory
mkdir -p keystore
# Combine certificate and private key into PEM format
echo "$ANDROID_CERT" > keystore/cert.pem
echo "$ANDROID_PRIV_KEY" > keystore/key.pem
# Combine certificate and private key into PKCS12 format
# Use a temporary password since we need to specify one
openssl pkcs12 -export -in keystore/cert.pem -inkey keystore/key.pem \
-out keystore/app.p12 -name key0 -password pass:temp-password
# Convert PKCS12 to JKS format
keytool -importkeystore -srckeystore keystore/app.p12 -srcstoretype PKCS12 \
-destkeystore keystore/app.jks -deststoretype JKS -srcstorepass temp-password \
-deststorepass "$ANDROID_JKS_PASSWORD" -destkeypass "$ANDROID_JKS_PASSWORD"
# Clean up temporary files
rm keystore/cert.pem keystore/key.pem keystore/app.p12
# Make sure the keystore file is not readable by others
chmod 600 keystore/app.jks
- name: Create gradle.properties file
if: github.ref_name == 'develop' || github.ref_name == 'master'
run: |
cat >> android/gradle.properties << EOF
FLOCCUS_STORE_FILE=../../keystore/app.jks
FLOCCUS_STORE_PASSWORD=${{ secrets.ANDROID_JKS_PASSWORD }}
FLOCCUS_KEY_ALIAS=key0
FLOCCUS_KEY_PASSWORD=${{ secrets.ANDROID_JKS_PASSWORD }}
EOF
- name: Prepare build
run: |
npx cap sync
cd android
chmod +x gradlew
- name: Build android release
if: github.ref_name == 'develop' || github.ref_name == 'master'
run: |
cd android
./gradlew assembleRelease
- name: Build android
if: github.ref_name != 'develop' && github.ref_name != 'master'
run: |
cd android
./gradlew assemble
- name: Upload build artifact
if: github.ref_name == 'develop' || github.ref_name == 'master'
uses: actions/upload-artifact@v4
with:
name: "floccus-build-${{ github.sha }}.apk"
path: android/app/build/outputs/apk/release/app-release.apk
retention-days: 7
ios:
needs: js
runs-on: macos-latest
name: ios
steps:
- name: Restore context
uses: buildjet/cache/restore@v3
with:
fail-on-cache-miss: true
key: build-context-${{ github.run_id }}
path: ./
- name: setup-cocoapods
uses: maxim-lobanov/setup-cocoapods@v1
with:
podfile-path: ios/App/Podfile.lock
- uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: latest-stable
- name: Install certificate and provisioning profile
env:
BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
BUILD_PROVISION_PROFILE_BASE64: ${{ secrets.BUILD_PROVISION_PROFILE_BASE64 }}
BUILD_PROVISION_PROFILE_NEW_BOOKMARK_BASE64: ${{ secrets.BUILD_PROVISION_PROFILE_NEW_BOOKMARK_BASE64 }}
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
run: |
# create variables
CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
PP_PATH=$RUNNER_TEMP/build_pp.mobileprovision
PP2_PATH=$RUNNER_TEMP/build_pp2.mobileprovision
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
# import certificate and provisioning profile from secrets
echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH
echo -n "$BUILD_PROVISION_PROFILE_BASE64" | base64 --decode -o $PP_PATH
echo -n "$BUILD_PROVISION_PROFILE_NEW_BOOKMARK_BASE64" | base64 --decode -o $PP2_PATH
# create temporary keychain
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
# import certificate to keychain
security import $CERTIFICATE_PATH -P "" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
security list-keychain -d user -s $KEYCHAIN_PATH
# apply provisioning profile
mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
cp $PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles
cp $PP2_PATH ~/Library/MobileDevice/Provisioning\ Profiles
- name: Capacitor sync
run: |
npx cap sync
- name: Build ios
env:
scheme: "Floccus"
run: |
cd ios/App
xcodebuild build-for-testing -scheme "$scheme" -workspace App.xcworkspace
summary:
runs-on: ubuntu-latest
needs: [ js, android, ios ]
if: always()
name: build-summary
steps:
- name: Summary status
run: if ${{ needs.js.result != 'success' || ( needs.android.result != 'success' && needs.selenium.result != 'skipped' ) || ( needs.ios.result != 'success' && needs.ios.result != 'skipped' ) }}; then exit 1; fi
================================================
FILE: .github/workflows/codeql-analysis.yml
================================================
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ develop, master ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ develop ]
schedule:
- cron: '37 13 * * 4'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'javascript' ]
node-versions: [14.x]
npm-versions: [8.x]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
steps:
- name: Checkout repository
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
- name: Set up node ${{ matrix.node-versions }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-versions }}
- name: Set up npm ${{ matrix.npm-version }}
run: npm i -g npm@"${{ matrix.npm-version }}"
# ℹ️ Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
# If the Autobuild fails above, remove it and uncomment the following three lines.
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
# - run: |
# echo "Run, Build Application using script"
# ./location_of_script_within_repo/buildscript.sh
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
================================================
FILE: .github/workflows/dependabot-approve.yml
================================================
name: Dependabot auto approve
on: pull_request
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: hmarr/auto-approve-action@v2.0.0
if: github.actor == 'dependabot[bot]' || github.actor == 'dependabot-preview[bot]'
with:
github-token: "${{ secrets.GITHUB_TOKEN }}"
================================================
FILE: .github/workflows/issues.yml
================================================
name: New issue workflow
on:
issues:
types: [opened]
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
jobs:
assign_one_project:
runs-on: ubuntu-latest
name: Assign to One Project
steps:
- name: Assign new issues and pull requests to project 1 Backlog
uses: srggrs/assign-one-project-github-action@1.2.0
with:
project: 'https://github.com/floccusaddon/floccus/projects/1'
column_name: 'Backlog'
first_comment:
runs-on: ubuntu-latest
name: Add first comment
steps:
- uses: ben-z/actions-comment-on-issue@1.0.3
with:
message: |
Hello! :wave:
Thank you for taking the time to open this issue with floccus. I know it's frustrating when software causes problems. You have made the right choice to come here and open an issue to make sure your problem gets looked at and if possible solved. Let me give you a short introduction on what to expect from this issue tracker to avoid misunderstandings. I'm Marcel. I created floccus a few years ago, and have been maintaining it since. I currently work for Nextcloud which leaves me with less time for side projects like this one than I used to have. I still try to answer all issues and if possible fix all bugs here, but it sometimes takes a while until I get to it. Until then, please be patient. It helps when you stick around to answer follow up questions I may have, as very few bugs can be fixed directly from the first bug report, without any interaction. If information is missing in your bug report and the issue cannot be solved without it, I will have to close the issue after a while. Note also that GitHub in general is a place where people meet to make software better *together*. Nobody here is under any obligation to help you, solve your problems or deliver on any expectations or demands you may have, but if enough people come together we can collaborate to make this software better. For everyone. Thus, if you can, you could also have a look at other issues to see whether you can help other people with your knowledge and experience. If you have coding experience it would also be awesome if you could step up to dive into the code and try to fix the odd bug yourself. Everyone will be thankful for extra helping hands! If you cannot lend a helping hand, to continue the development and maintenance of this project in a sustainable way, I ask that you donate to the project when opening an issue (or at least once your issue is solved), if you're not a donor already. You can find donation options at <https://floccus.org/donate/>. Thank you!
One last word: If you feel, at any point, like you need to vent, this is not the place for it; you can go to the Nextcloud forum, to twitter or somewhere else. But this is a technical issue tracker, so please make sure to focus on the tech and keep your opinions to yourself.
Thank you for reading through this primer. I look forward to working with you on this issue! Cheers! :blue_heart:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
================================================
FILE: .github/workflows/lock-threads.yml
================================================
name: 'Lock Threads'
on:
schedule:
- cron: '0 0 * * *'
workflow_dispatch:
permissions:
issues: write
pull-requests: write
concurrency:
group: lock
jobs:
action:
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@v4
with:
issue-comment: >
This issue has been automatically locked since there
has not been any recent activity after it was closed.
Please open a new issue for related bugs.
================================================
FILE: .github/workflows/stale.yml
================================================
name: 'Close stale issues and PRs'
on:
schedule:
- cron: '30 1 * * *'
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v8
with:
stale-issue-message: |
Hello :wave:
This issue appears to have had no activity for 3 months. We cannot keep track of whether individual issues
have resolved themselves or still require attention without user interaction. We're thus adding the stale label to this issue to schedule
it for getting closed in 5 days time. If you believe this issue is still valid and should be fixed, you can add a comment
or remove the label to avoid it getting closed.
Cheers :blue_heart:
close-issue-message: 'This issue was closed because it has been stalled for 5 days with no activity.'
days-before-issue-stale: 90
days-before-issue-close: 5
days-before-pr-close: -1
only-labels: 'waiting for more information'
exempt-issue-labels: 'enhancement'
================================================
FILE: .github/workflows/tests.yml
================================================
name: Tests
on:
pull_request:
push:
branches:
- master
- develop
paths:
- 'src/**'
- 'test/**'
- 'package.json'
- 'package-lock.json'
- 'webpack*'
- 'gulpfile.js'
env:
APP_NAME: bookmarks
concurrency:
group: floccus-tests-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
init:
runs-on: ubuntu-latest
strategy:
# do not stop on another job's failure
fail-fast: false
matrix:
node-version: [ 20.x ]
npm-version: [ 10.x ]
steps:
- name: Checkout floccus
uses: actions/checkout@v2
with:
path: floccus
- name: Set up node ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: Set up npm ${{ matrix.npm-version }}
run: npm i -g npm@"${{ matrix.npm-version }}"
- name: Cache node modules
uses: actions/cache@v4
env:
cache-name: cache-node-modules
with:
path: ~/.npm # npm cache files are stored in `~/.npm` on Linux/macOS
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-build-${{ env.cache-name }}-
${{ runner.os }}-build-
${{ runner.os }}-
- name: Install dependencies & build
working-directory: floccus
run: |
npm ci
npm run build-release --if-present
- name: Save context
uses: actions/cache/save@v4
with:
key: selenium-context-${{ github.run_id }}
path: ./
selenium:
runs-on: ubuntu-latest
needs: init
env:
SELENIUM_HUB_HOST: hub
TEST_HOST: nextcloud
SERVER_BRANCH: ${{ matrix.server-version }}
NC_APP_VERSION: ${{ matrix.app-version }}
MYSQL_PASSWORD: root
strategy:
# do not stop on another job's failure
fail-fast: false
matrix:
node-version: [20.x]
npm-version: [10.x]
server-version: ['32']
app-version: ['stable']
floccus-adapter:
- fake
- nextcloud-bookmarks
- webdav-xbel
- webdav-html
- webdav-html-encrypted
- webdav-xbel-encrypted
- git-xbel
- git-html
- google-drive
- google-drive-encrypted
- dropbox
- dropbox-encrypted
- linkwarden
- karakeep
test-name:
- test
browsers:
- firefox
- chrome
include:
- app-version: master
server-version: 32
floccus-adapter: nextcloud-bookmarks
test-name: test
browsers: firefox
node-version: 14.x
npm-version: 7.x
- app-version: master
server-version: 32
floccus-adapter: nextcloud-bookmarks
test-name: benchmark root
browsers: firefox
node-version: 14.x
npm-version: 7.x
- app-version: master
server-version: 32
floccus-adapter: nextcloud-bookmarks
test-name: benchmark root
browsers: chrome
node-version: 14.x
npm-version: 7.x
- app-version: stable
server-version: 32
floccus-adapter: fake-noCache
test-name: test
browsers: firefox
node-version: 14.x
npm-version: 7.x
- app-version: master
server-version: 32
floccus-adapter: fake
test-name: benchmark root
browsers: firefox
node-version: 14.x
npm-version: 7.x
- app-version: master
server-version: 32
floccus-adapter: fake
test-name: benchmark root
browsers: chrome
node-version: 14.x
npm-version: 7.x
name: ${{ matrix.browsers == 'firefox' && '🦊' || '🔵' }} ${{matrix.floccus-adapter}}:${{ matrix.test-name}} ⭐${{ matrix.app-version }}
services:
hub:
image: selenium/hub:4.34.0-20250717
ports:
- 4442:4442
- 4443:4443
- 4444:4444
firefox:
image: selenium/node-firefox:4.34.0-20250717
env:
SE_EVENT_BUS_HOST: hub
SE_EVENT_BUS_PUBLISH_PORT: 4442
SE_EVENT_BUS_SUBSCRIBE_PORT: 4443
options: --shm-size="2g"
chrome:
image: selenium/node-chrome:4.20.0-20240425
env:
SE_EVENT_BUS_HOST: hub
SE_EVENT_BUS_PUBLISH_PORT: 4442
SE_EVENT_BUS_SUBSCRIBE_PORT: 4443
options: --shm-size="2g"
nextcloud:
image: nextcloud:${{ matrix.server-version }}
env:
NEXTCLOUD_ADMIN_USER: admin
NEXTCLOUD_ADMIN_PASSWORD: admin
MYSQL_DATABASE: nextcloud
MYSQL_USER: root
MYSQL_PASSWORD: ${{env.MYSQL_PASSWORD}}
MYSQL_HOST: mysql
NEXTCLOUD_TRUSTED_DOMAINS: nextcloud
options: --name nextcloud
mysql:
image: mariadb:10.5 # see https://github.com/nextcloud/docker/issues/1536
env:
MYSQL_ROOT_PASSWORD: ${{env.MYSQL_PASSWORD}}
karakeep:
image: ghcr.io/karakeep-app/karakeep:release
ports:
- 3000:3000
volumes:
- data:/data
env:
NEXTAUTH_SECRET: super_random_string
NEXTAUTH_URL: http://localhost:3000
DATA_DIR: /data
steps:
- name: Restore context
uses: actions/cache/restore@v4
with:
fail-on-cache-miss: true
key: selenium-context-${{ github.run_id }}
path: ./
- name: Checkout bookmarks app
uses: actions/checkout@v2
with:
repository: nextcloud/${{ env.APP_NAME }}
ref: ${{ matrix.app-version }}
path: ${{ env.APP_NAME }}
if: matrix.floccus-adapter == 'nextcloud-bookmarks' || matrix.floccus-adapter == 'nextcloud-bookmarks-old'
- name: Install bookmarks app
shell: bash
run: |
cd ${{ env.APP_NAME }}
composer install --ignore-platform-req=php --no-dev
if: matrix.floccus-adapter == 'nextcloud-bookmarks' || matrix.floccus-adapter == 'nextcloud-bookmarks-old'
- name: Enable bookmarks app
shell: bash
run: |
docker cp ${{env.APP_NAME}} nextcloud:/var/www/html/apps/
NEXT_WAIT_TIME=0
until [ $NEXT_WAIT_TIME -eq 25 ] || docker exec --user www-data nextcloud php occ app:enable ${{ env.APP_NAME }}; do
sleep $(( NEXT_WAIT_TIME++ ))
done
[ $NEXT_WAIT_TIME -lt 25 ]
if: matrix.floccus-adapter == 'nextcloud-bookmarks' || matrix.floccus-adapter == 'nextcloud-bookmarks-old'
- name: Enable APCu
run: |
NEXT_WAIT_TIME=0
until [ $NEXT_WAIT_TIME -eq 25 ] || docker exec --user www-data nextcloud php occ config:system:set --value "\\OC\\Memcache\\APCu" memcache.local; do
sleep $(( NEXT_WAIT_TIME++ ))
done
[ $NEXT_WAIT_TIME -lt 25 ]
if: matrix.floccus-adapter != 'fake'
- name: Wait for Selenium
run: |
sudo apt install -y jq
while ! curl -sSL "http://localhost:4444/wd/hub/status" 2>&1 \
| jq -r '.value.ready' 2>&1 | grep "true" >/dev/null; do
echo 'Waiting for the Grid'
sleep 1
done
echo "Selenium Grid is up - executing tests"
- name: Setup git http server
run: |
mkdir __fixtures__
cd __fixtures__
git init --bare test.git -b main
npm i git-http-server
npx git-http-server &
npx htpasswd -cb test.git/.htpasswd admin admin
if: matrix.floccus-adapter == 'git-xbel' || matrix.floccus-adapter == 'git-html'
- name: Run git adapter tests
working-directory: floccus
env:
SELENIUM_BROWSER: ${{ matrix.browsers }}
FLOCCUS_TEST: ${{matrix.floccus-adapter}} ${{ matrix.test-name}}
FLOCCUS_TEST_SEED: ${{ github.sha }}
TEST_HOST: 172.17.0.1:8174
run: |
npm run test
if: matrix.floccus-adapter == 'git-xbel' || matrix.floccus-adapter == 'git-html'
- name: Run tests
working-directory: floccus
env:
SELENIUM_BROWSER: ${{ matrix.browsers }}
FLOCCUS_TEST: ${{matrix.floccus-adapter}} ${{ matrix.test-name}}
FLOCCUS_TEST_SEED: ${{ github.sha }}
GIST_TOKEN: ${{ secrets.GIST_TOKEN }}
GOOGLE_API_REFRESH_TOKEN: ${{ secrets.GOOGLE_API_REFRESH_TOKEN }}
DROPBOX_API_REFRESH_TOKEN: ${{ secrets.DROPBOX_API_REFRESH_TOKEN }}
LINKWARDEN_TOKEN: ${{ secrets.LINKWARDEN_TOKEN }}
APP_VERSION: ${{ matrix.app-version }}
KARAKEEP_TEST_HOST: 172.17.0.1:3000
run: |
npm run test
if: matrix.floccus-adapter != 'git-xbel' && matrix.floccus-adapter != 'git-html'
# - name: Cancelling parallel jobs
# if: failure() && matrix.floccus-adapter == 'fake' && matrix.test-name == 'test'
# uses: andymckay/cancel-action@0.2
summary:
runs-on: ubuntu-latest
needs: [ init, selenium ]
if: always()
name: selenium-summary
steps:
- name: Summary status
run: if ${{ needs.init.result != 'success' || ( needs.selenium.result != 'success' && needs.selenium.result != 'skipped' ) }}; then exit 1; fi
================================================
FILE: .gitignore
================================================
.*.sw*
dist
node_modules
builds
key.pem
.idea
.DS_STORE
# Sentry Config File
.env.sentry-build-plugin
================================================
FILE: .prettierrc
================================================
{
"semi": false,
"singleQuote": true,
"jsxBracketSameLine": true
}
================================================
FILE: CHANGELOG.md
================================================
# Changelog
## [5.8.6] - 2026-01-23
### Fixed
- fix(Tree): Revert incremental index updates (Would break initial sync on Chrome)
## [5.8.5] - 2026-01-20
### Fixed
- [native] fix: Properly serialize cache
## [5.8.4] - 2026-01-19
* feat(Logger): Persist logs intermittently
* feat(NewAccount): Add predefined webdav service URLs
* fix(Controller): Only schedule sync if current error is transient
* fix: Display allowRedirects option on mobile
* fix(SyncProcess): Fix serialization for continuation persistence
* Fix: Reduce memory pressure by reducing ACTION_CONCURRENCY
* fix(Unidirectional): Only do a single Scanner pass to improve performance
* fix(childrenSimilarity): Make O(n) instead of O(n²)
* fix: Fix typeof undefined checks to handle null
* fix(Diff): Do not call .toString on null
* fix(Folder#toJSON): Make sure children are properly serialized
* fix(BrowserAccountStorage): Use setEntry instead of changeEntry
* fix(Caching#orderFolder): Fix orderFolder algorithm
* fix(LocalTabs): Properly distinguish between window IDs and group IDs
* fix(continuation): Fix continuation loading
* fix(index): Update index incrementally instead of recreating it every time
* fix(SyncProcess): Reduce size of continuation on disk to prevent breaking sync with large amounts of bookmarks
* fix(CachingAdapter): Whitelist more browser-specific URL schemes
* fix(Non-Atomic adapters): Reduce HTTP request parallelism for better throughput
* fix(Account): Add log statement for continuation loading error
* fix(Mappings#remove): Correct logic to always handle both remote and local IDs
* chore: Update dependencies
## [5.8.3] - 2025-12-20
### Fixed
fix(Logger): Trim logs regularly to avoid memory leak
fix(Scanner): Remove Log spam
fix(LocalTabs): Fix dummyTab workaround for tab group creation on firefox
fix(LocalTabs): Do not parseInt(windowId)
fix(css): Use proper css
fix(Account#progressCallback): Prevent errors getting mappings after sync has finished
fix: Multiple small hardenings
fix(Account#sync): Do not re-init account if failsafe triggers
fix: show warning on mobile if browser doesn't match
fix(failsafe): be more precise about where bookmarks are added/deleted
fix(WebDAV): Use includeCredentials option again
fix(Chrome): Prevent chrome from killing our worker while it's syncing
[native] fix: Make breadcrumbs clickable again
## [5.8.2] - 2025-12-07
### Fixed
- fix: Resume sync with reset cache after MappingFailure
- fix(DescriptionAccountcreated): Mention that combining floccus with browser sync doesn't work
- fix: Introduce proper XbelParseError
- fix: Introduce proper error for invalid URL
- fix: Try to fix 'Calling getCacheTree() of undefined' error
- fix: Make Caching#orderFolder behave like BrowserTree#orderFolder to avoid ordering mistakes
- fix: Implement GC for mappings
## [5.8.1] - 2025-11-22
### Fixed
* [native] fix: Don't allow import of git profiles
* fix: Make cancelSync work more immediately on Firefox
* fix: Don't get stuck on syncing in firefox
## [5.8.0] - 2025-11-16
### New
- enh: Remember last used account
- enh(GoogleDrive): Add a HTTP request timeout
- feat: Split interval based sync and change-based sync into two options
### Fixed
* [native] fix(NativeApp): Don't use css inset property
* [native] fix: Refuse to import gdrive profiles, because it doesn't work anymore
* fix(CachingAdapter): set initialTreeHash after getBookmarksTree
* fix(browser-api): Do not carry context into each callback (Improves memory consumption)
* fix: Remove confusing detail from E020 message Marcel Klehr 11/14/25, 9:33 AM
* fix(Folder#inspect): Make hash visible again
* Fix DialogChooseFolder2: keep header fixed, make treeview scrollable with dynamic max-height unknown
* fix(SyncProcess): Catch throttledCb cancelled error
* fix(Nextcloudbookmarks): Fix 404 error on capabilities endpoint
## [5.7.0] - 2025-08-24
### Summary
* Sync notifications – You’ll now see “sync in progress” and “sync complete” alerts on Android and iOS
* Search improvements – The app remembers the last folder you searched in, shows folder paths in results and lets you search for folders.
* Feedback – Submit one‑off feedback directly from the app.
* Messaging – TLS is now mentioned in the E017 explanation.
* Sync logic – Fixed issues with reorders, concurrency and continuation handling during interrupted syncs.
* Account progress – Cache and mappings now persist for atomic backends.
* Browser tree – Concurrency limited to 1 to avoid race conditions.
* Localization – Added translations for many languages (ro_RO, el, it, fi, cs, pl, sv, tr, et, ko_KR, ru, de, ja, pt, zh_CN, fr, es).
* Scrolling – Capacitor status bar plugin now prevents content from scrolling under the status bar.
* Local tabs – New tab groups stay alive long enough for tabs to be added.
* General – Cancelled local tree operations, ensured skipped reorders are retracted and cleared continuations properly.
* Overall sync performance has been optimized, reducing wait times and resource usage.
### New
* [native] feat(notifications): Send 'sync in progress' and 'sync complete' notifications
* [native] feat(search): Remember last used folder across app starts
* [native] feat(search): Display folder path for folder search results
* [native] feat(search): Allow searching for folders
* feat(BrowserController): setUninstallURL
* [native] feat(search): display folder path for search results
* feat(hashing): Add support for xxhash3
* feat: Optionally support murmur3 + implement capabilities negotiation
* feat(BrowserController): Listen to tab events
* feat(AccountCard): Mention FAQ when errors occur
* feat(telemetry): send used adapter along with error events to sentry, if enabled (opt-in)
* feat(Feedback form): Allow submitting one-off feedback
* feat(HtmlSerializer): Use auto-inc IDs as a fallback when parsing
### Fixed
* fix(messages): Mention TLS in E017 explanation
* fix(reconcileDiffs): Don't throw away REORDERs if concurrent reorder is empty
* fix(Account#progressCallback): persist cache and mappings for atomic backends
* fix({Default,Merge}SyncProcess#reconcileDiffs): Restrict concurrency
* fix(DefaultSyncProcess#reconcileDiffs): Use the right findChainCache
* fix(MergeSyncProcess): reconcileDiffs was outdated
* fix(BrowserTree): Set concurrency to 1
* Translate messages.json in ro_RO,el,it,fi,cs,pl,sv,tr,et,ko_KR,ru,de,de,ja,pt,zh_CN,fr,es
* [native] fix: added the capacitor status bar plugin to fix scrolling content over the status bar (Thanks to @yougotwill)
* fix(SyncProcess): Make sure to cancel progress callback throttling in the end
* fix(continuations): Set current continuation to null at the very end
* fix(SyncProcess): Make sure skipped reorders are retracted
* fix: Allow cancelling local tree operations as well
* fix(interrupted sync): Allow storing + restart of stage 3 to/from continuation
* fix(interrupted sync): Set back old cacheTree upon loading pending continuation
* fix(SyncStrategy): Fix Continuation loading
* perf: Improve overall sync performance
* fix(NextcloudBookmarks): Fix ticket failure retry mechanism
* fix(NextcloudBookmarks): Improve ticket failure retry mechanism
* feat(NextcloudBookmarks): Support ticket authentication
* fix(NextcloudBookmarks): Fix checkFeatureJavascriptLinks
* feat(NextcloudBookmarks): Use negotiated hash function from hashSettings
* feat(NextcloudBookmarks): Use capabilities for feature detection
* fix(LocalTabs): Make sure new groups live long enough for tabs to be added to them
* fix(GoogleDrive): Improve error handling
## [5.6.0] - 2025-08-02
### New
- New backend: KaraKeep
- Support syncing tab groups
- [Native app] Improved handling of share intents
### Fixed
* Make syncing with Linkwarden work again: Switch to new search endpoint
* Improve syncing correctness: Fix ID comparisons
* Improve syncing correctness: reconcileReorderings based on both donePlans
* Improve syncing correctness: Fix mappable() function
* Improve syncing correctness: Do not move items across folders in orderFolder()
* fix: Fix "failed to map parentId" errors
* Ignore permissions when using Orion
* Improve Description for Bookmarksfile
* Display more meaningful explanation for server target
* Never force-push when syncing via git
* Catch errors when parsing XML
* Allow syncing root folder in chrome again
* catch errors from git.push operations
## [5.5.6] - 2025-06-29
### Fixed
* Remove all traces of IndexedDB usage
## [5.5.5] - 2025-06-01
### Fixed
* Removed the use of Dexie as it doesn't play nice with Sentry and causes crashes
## [5.5.4] - 2025-05-30
### Fixed
* fix(build): Transpile async to generators to avoid Crashing Chrome and Edge due to leaking transactions
* fix(NextcloudBookmarks): Do not remember result of checkFeatureJavascriptLinks() across syncs
* fix(NextcloudBookmarks): Fix checkFeatureJavascriptLinks()
* fix(BrowserController): set syncing to false onLoad
* fix(GoogleDrive): Set acknowledge abuse parameter to avoid failing syncs
* fix(Bookmark#clone): reset hashValue correctly
* fix(WebDAV): Fix file size check
* fix(messages): Improve Linkwarden serverfolder explanation
## [5.5.3] - 2025-04-27
### Fixed
* perf(GoogleDrive): Speed up "no changes" code path
* perf(Folder#clone): Make Folder#clone use prototype inheritance to save ALOT of memory
* perf(BrowserAccount): Don't use browser.bookmarks.getTree() if avoidable
* refactor(isUsingBrowserTabs): Expose Resource#isUsingBrowserTabs
* fix(CachingTreeWrapper): Allow changes to the live tree without disturbing the cache
* fix(App#openInNewTab): Use browser.tabs to open new tab instead of window.open (Didn't work in Edge for Android)
* fix(Default#applyAdditionFailsafe): Only kick in if at least 20 bookmarks are being added
* fix(WebDAV): Add Depth header to PROPFIND for getting filesize
## [5.5.2] - 2025-04-16
### Fixed
* fix(IndexedDB): Delete up to the last hour of logs
* fix(storage): Add checkStorage method to freeStorage regularly
* fix(IndexedDB): Don't store more than 50MB of logs
## [5.5.1] - 2025-04-09
### Fixed
* Fixed build
## [5.5.0] - 2025-04-09
### New
* feat(Logger): Use IndexedDB to store logs in order to store more
* feat(AdditionFailsafe): Extend failsafe mechanism to prevent creation of excessive amounts of bookmarks
* fix(failsafe): Reduce threshold to 20% OR 1k bookmarks
### Fixed
* fix(Controller): Do not run scheduleSync concurrently for all accounts
* fix(failsafe): Also apply failsafe on upstream changes
* fix(NewAccount): Disable git backend on android/ios
* fix(GoogleDrive): fix "T.includes is not a function" error
* fix(webdav): Validate filesize via PROPFIND to detect partial downloads
## [5.4.5] - 2025-03-20
### Fixed
* Upgrade to capacitor 7 and Java 21
* fix(Tree#search): Harden search
* fix(Controller): Cap exponential backoff at 1h
* fix(Account): Don't call onSyncFail twice if onSyncStart failed
* fix: Reduce intervention frequency to avoid annoying users
* fix(App): Allow opening any view in a new tab
* fix(Git): Make sure foreign locks are freed when forceLock is set
* fix(NextcloudBookmarks): Make sure lock is freed when forceLock is set
* fix(LocalTabs): Speed up tabs updated callback
## [5.4.4]
### Fixed
* fix(SyncProcess): When creating dummy bookmarks representing separators, make sure to use vertical lines on the Toolbar, and horizontal lines otherwise. (thanks to @macrogreg)
* fix(Xbel): Don't parse tag values
* fix: Throw nice error for when gdrive search fails
* fix: Clean up dependencies (#1851)
* fix(messages): Specify that the file path doesn't matter for Google Drive
## [5.4.3]
### Fixed
* fix(OptionsLinkwarden): Allow changing server folder
* fix(Storage): Don't give up when storage entry can not be parsed
* refactor(Account#setData): Accept partial data and use lock to set data (fixes hanging sync on iOS)
* fix(README): Add APK cert fingerprint
* fix(GoogleDrive|WebDAV): Try to catch more errors when file is encrypted
* enh(AutoSync): Add an explantion in settings
* [native] Try to find a valid URL when an app shares title+URL stuffed together (thanks to Andy Balaam)
* [native] Check that a URL is valid as soon as we load the Add Bookmark dialog (thanks to Andy Balaam)
* [native] Prevent saving a newly-added bookmark if the URL is bad (thanks to Andy Balaam)
* [native] Catch and log any errors we encounter when parsing a URL to display its hostname (thanks to Andy Balaam)
## [5.4.2]
(aka 5.4.2.1)
### New
* [native] enh(Search): Match partial words
* enh(Caching): Add edge:// to supported schemes
* enh: Don't produce UPDATE actions when URLs change
### Fixed
* fix(SyncProcess): Refactor mergeable functions
* fix(SyncProcess): Fix URL collisions on NC Bookmarks
* fix(SyncProcess): Shorten excessive logging of REORDER actions
* fix(Logger): Improve log redaction
* fix(NextcloudBookmarks): More info in log when requests fail
* fix(NextcloudBookmarks): Better error message when UPDATE fails
* fix(OptionsWebDAV): re-init file when bookmark_file option is changed
* fix(WebDAV): Fail when trying to sync to XBEL file with html setting and vice versa
* fix(stringifyError): inspect bookmark to avoid [object Object]
* Fix copy/paste typos for E037 & E038 error messages. (Thanks to John Hein)
* fix(WebDAV): Fix "includes is not a function" error
* fix(GoogleDrive): Log response on auth failure
## [5.4.2-alpha.1]
### New
* [native] enh(Search): Match partial words
* enh(Caching): Add edge:// to supported schemes
* enh: Don't produce UPDATE actions when URLs change
### Fixed
* fix(SyncProcess): Refactor mergeable functions
* fix(SyncProcess): Fix URL collisions on NC Bookmarks
* fix(SyncProcess): Shorten excessive logging of REORDER actions
* fix(Logger): Improve log redaction
* fix(NextcloudBookmarks): More info in log when requests fail
* fix(NextcloudBookmarks): Better error message when UPDATE fails
* fix(OptionsWebDAV): re-init file when bookmark_file option is changed
* fix(WebDAV): Fail when trying to sync to XBEL file with html setting and vice versa
* fix(stringifyError): inspect bookmark to avoid [object Object]
* Fix copy/paste typos for E037 & E038 error messages. (Thanks to John Hein)
## [5.4.1]
### Fixed
* [native] fix(AddBookmarkIntent): Folder selector was broken
* [ios] fix(design): Make top bar dark when in dark mode
* fix(NewAccount): Don't refresh page on enter in accountlable field
* fix(Bookmark): Accept url = null
* fix(NextcloudBookmarks): Remove unnecessary code
* fix(Linkwarden): Ignore bookmarks with url = null
## [5.4.0] - 2024-11-30
### New
* enh(Tree): Add confirmation before deleting items
* enh(tabs): Make merge strategy work with tabs
* [native] enh(DialogChooseFolder): Allow creating folders
* [native] enh(Drawer): Add github issues link
* [native] enh(search): Show search results from other folders
* [native] enh: Allow selecting up down sync by long press on sync button
* [native] enh: Remember sort option & sort folders first
* [native] enh: Improve search by ranking better matches higher
* enh(Account#sync): Allow forcing sync when profile is scheduled
### Fixed
* [native] fix(DialogChooseFolder): Sort folders according to sort order setting
* [native] fix(newbookmark): Use neutral user agent to get correct title
* [native] fix(Tree): Sorting by link
* [native] fix: Properly reset accounts on load
* fix(Scanner): Improve move stability with same-titled folders
* fix(GoogleDrive|WebDAV): fix _.includes is not a function error
* fix(Account#sync): Do not break lock automatically
## [5.3.4] - 2024-11-17
### Fixed
* fix(NativeTree): Set location to Local (fixes "Failed to map parentId: 0" error)
* fix(Linkwarden): Set Folder#isRoot
* fix(Linkwarden): Correctly update bookmarks on the server
## [5.3.3] - 2024-11-09
### New
* enh(Git): Mention profile label in commit message
### Fixed
* fix(ios/sharing-extension): Add compat for newer ios versions
* fix(GoogleDrive): includes is not a function
* fix(Update): Fix visual glitch
## [5.3.2] - 2024-11-01
### Fixed
* [iOS] Attempt to fix inbound sharing
## [5.3.1] - 2024-10-09
### Fixed
* [native] fix(Linkwarden): Remove dispatch of REQUEST_NETWORK_PERMISSIONS
* [native] fix(Linkwarden): Options were not showing
* fix: Don't break if browser doesn't implement permissions API
* fix(GoogleDrive): Try to delete superfluous files
* fix(NextcloudBookmarks): Run javascript feature detection earlier to avoid losing javascript bookmarks upon browser start
* fix(Html): Only escape unsafe characters in HTML
## [5.3.0] - 2024-09-28
(aka v5.3.0.2)
### New
* Add support for Linkwarden
### Fixed
* fix(GoogleDrive): Sort files by modified date
## [5.3.0-beta.1] - 2024-09-12
(aka v5.3.0.1)
### New
* Add support for Linkwarden
## [5.2.7] - 2024-09-03
### Fixed
* fix: Filter out "file:" URLs when syncing tabs on firefox
* fix: Log error from google API when retrieving access token
* [native] fix: Tree comparison on RELOAD_TREE_FROM_DISK was broken
* [native] fix: make builds reproducible again
* fix(Html): Encode unsafe characters as HTML entities
## [5.2.6] - 2024-08-11
### Fixed
* chore: update capacitor/core
* fix(Update): Show floccus logo on update page
* fix: Refactor sync algorithm introducing location types (fixed 6 correctness bugs along the way)
## [5.2.5] - 2024-07-25
### Fixed
* [native] feat: warn user if URL is already bookmarked
* [native] fix: small visual fixes
* [native] fix: Automatically reload from disk when resuming app
* [native] fix: replace cordova-inappbrowser with capacitor/browser
* [native] chore: Upgrade capacitor to v6
* feat(AccountCard): Link to github issues on error
* perf(GoogleDrive, WebDav): Don't loop through all lines when finding highest ID
* feat(Telemetry): Add report problem button to Telemetry page
* feat(AccountCard): Link to github issues on error
* fix(Cancel): Improve cancel UX
* fix(NextcloudBookmarks): Increase timeout
* fix(Git): Clean up used indexedDB instances
* fix(Controller logic): Catch all 'Receiving end does not exist' errors
* fix(Account): Don't compile logs for each error
* fix(Xbel): Don't attempt to parse numbers
* fix(GoogleDrive,WebDAV): Allow passing salt in file contents
* fix(GoogleDrive): Don't free lock if it wasn't locked
* fix(Cancel): Improve cancel UX
* fix(NextcloudBookmarks): Increase timeout
* chore(package.json): Add necessary NODE_OPTIONS to scripts
* chore(ios): Update ios assets
## [5.2.4] - 2024-07-02
### Fixed
* fix(Account): Use exponential backoff instead of disabling profile after 10 errors
* [native] fix(font-size): set default font-size using cm
* fix(imports): Don't allow importing actions definitions from store/index
* [native] fix(Options): Avoid importing browser-only module
* fix(Folder#traverse)
* fix typo in README.md in git repos
* fix(Default#executeAction): fix ordering when doing bulkImport in Unidirectional strategy
* fix(NextcloudBookmarks): Make sure folder exists before appending children
## [5.2.3] - 2024-06-21
### Fixed
* fix(AccountCard): mention if profile was disabled after error
* fix(OptionsGit): Branch option didn't propagate new value
## [5.2.2] - 2024-06-16
### Fixed
* iOS: Fix sharing from apps other than Safari
## [5.2.1] - 2024-06-15
### Fixed
* fix: make history permission optional and request on demand only
## [5.2.0] - 2024-06-11
### New
* feat: Allow custom labels for profiles
* feat: Allow counting clicks with Nextcloud Bookmarks
* feat: Add some UI interventions asking for donations
* feat: Opt-in automated error reporting using Sentry
### Fixed
* fix: Don't sync scheduled profiles if they're disabled
* fix: Don't show update notification if the user doesn't use floccus
* fix: Do not run two scanners at the same time
* fix: Improve build script to avoid faulty builds
* fix: Give browser more time to breathe to avoid freezing browser
* fix: Disable profile after 10 errors in a row
## [5.1.7] - 2024-05-28
### Fixed
* [native] Don't reload tree in TREE_LOAD
## [5.1.5] - 2024-05-28
### Fixed
* [native] fix tree loading mechanism that would cause issues with syncing
## [5.1.4] - 2024-05-21
### Fixed
* [native] fix(Drawer): Add icon for git profiles
* fix: Improve locking logic
* fix(BrowserController): Don't spam setIcon warnings
* fix(Account): call onSyncFail if onSyncStart fails
## [5.1.3] - 2024-05-18
### Fixed
* [native] fix: set largeHeap to true on android + fix git settings
* fix: Improve locking logic
* fix(NextcloudBookmarks#getExistingBookmarks): Don't use search-by-url for javascript links
* fix: Make Diff#inspect() output more readable
* fix: Limit concurrency for reorderings
* fix: Improve bulkImport performance by chunking
* fix: Unhandled error "Receiving end does not exist"
## [5.1.2] - 2024-05-14
### Fixed
* fix(GoogleDrive): Catch 500 errors
* [native] fix: Reload tree on app resume
* fix(NextcloudBookmarks): Remove feature detection of 5yo features
* [native] fix(intent): Register intent activity properly
* feat(NextcloudBookmarks): Accept javascript: links
* fix(webpack): Don't set DEBUG to true in production
* fix(BrowserController#setStatusBadge): Don't throw when setting icon
* fix(Account#progressCallback): Don't error if syncProcess is not defined yet
* fix: Don't error in old Chrome versions if browser.permissions.contains fails
* fix: Wrap local tree fetch error
* fix(webpack): Split initial chunks to avoid AMO review complaining
## [5.1.1] - 2024-05-10
### Fixed
* fix(SyncProcess): Do not serialize all trees each progress tick
* fix(SyncProcess): Call progressCb 2x less
* fix(Account): Extract and unify progressCallback
* fix(SyncProcess): Limit action execution concurrency to 12
* fix(Account): Properly declare DEBUG the typescript way
* fix(syncProcess): Properly count planned actions
* fix(Git): On init don't use force push
* fix(Git): Only bulldoze the repository if HEAD or branch cannot be found
* Add optional automatic error reporting to discover dormant bugs
* fix(Unidirectional): Scanner should use mappings if possible
* fix({html,xbel} parsers): Don't replace '0' by ''
* fix: Don't set lock after freeing it
* Fix(BrowserTree): Don't load full Tree on startup
## [5.1.0] - 2024-05-05
### New
- enh(ui): Add git adapter: You can now sync via git
### Fixed
* fix(GoogleDrive): Don't pollute console
* fix(BrowserController#getStatus): Show error icon if an account hasn't been synced in two days
* fix: Ignore errors from browser.permissions.contains
* fix: Ignore errors in REQUEST_NET_PERMS
* fix: Replace node.js' url with whatwg URL
* fix(browserslist): support and_chr >=60
* fix: Don't sync tabs if floccus' browser profile is not active
* fix(performance): Turn parallel processing back on Marcel Klehr 03.05.24, 19:30
* fix(Account#sync): Don't store continuation if the adapter is caching changes internally
## [5.0.12] - 2024-04-26
### Fixed
- fix(tests/gdrive): Don't derive file name from seed
- chore: Allow fuzzed testing with interrupts on nextcloud-bookmarks
- enh(ci/tests); Use github sha as seed
- fix: Store continuation while sync is running to be able to resume after interrupts
- chore: Update donation methods Marcel Klehr 21.04.24, 20:57
- fix: Distinguish between InterruptedSyncError and CancelledSyncError
- [android] Include dependenciesInfo in gradle file
- [native] fix(Account): Don't try to load LocalTabs resource
## [5.0.11] - 2024-03-09
### Fixed
* fix: Android app stuck on splash screen
## [5.0.10] - 2024-03-08
### Fixed
* fix(Account#sync): Break lock after 2h
* bookmarks folder selection: Select sub folder in Vivaldi
## [5.0.9] - 2024-01-08
### Fixed
* [chrome] fix(background sync): Apply hack to keep service worker alive
## [5.0.8] - 2024-01-07
### Fixed
* fix(nextcloud login flow): Use standalone browser on iOS
* fix(manifest.firefox.json): Make sure host permission matches the one in the code
## [5.0.7] - 2024-01-04
### Fixed
* [native] Fix hanging splash screen
* fix(Controller): Remember strategy when scheduling sync after lock error
* Complete translations for Japanese, Spanish and German
## [5.0.6] - 2023-12-31
### Fixed
* fix(background sync): Move back to manifest v2 for firefox
* fix(Account#setData): re-init if localRoot is changed
* fix(Options): Fix v-switch input
* fix(Controller#scheduleSync): Allow syncing if account is disabled and scheduled
## [5.0.5] - 2023-12-20
### Fixed
* Fix: Move waiting for lock out of adapters into controller
* fix(NextcloudBookmarks): Use CapacitorHttp to avoid cors errors in capacitor 5
* fix(native/START_LOGIN_FLOW): migrate to new capacitor http API
## [5.0.4] - 2023-12-15
### Fixed
* [native] upgrade capacitor-oauth2
* [native] fix(GoogleDrive): CapacitorHttp no longer encodes x-form-urlencoded
* fix(Import): Request network permissions before import
* fix(GoogleDrive): Request network permissions before login
## [5.0.3] - 2023-12-12
### Fixed
- [native] Remove capacitor community http Marcel Klehr 36 minutes ago
- [native] fix(DialogImportBookmarks): accept="text/html"
- [android] fix(webdav): Use new builtin CapacitorHttp
- fix(Unlock with credentials): Missing await 🙈
- fix(Profile import)
- fix(options): Auto-sync option was not saved
- fix(GoogleDrive): Fix permissions.contains syntax
- fix: Always cast to string before comparing item ids
- fix(HtmlSerializer): Try to fix ordering test
- fix(HtmlSerializer): Use Cheerio.text() for getting title
## [5.0.2] - 2023-12-09
### Fixed
- Fix another XBEL parser bug
- Fix HTML parser
## [5.0.1] - 2023-12-09
### Fixed
- Fixes XBEL parser
## [5.0.0] - 2023-12-09
## New
- Avoid syncing private tabs
- Add a 'Sync all' button
- Overhaul profile overview UI
## Changed
- [browser] Migrate to Manifest v3
- [browser] remove unlock passphrase feature
- [native] Remove background mode because it was buggy
- Sync 3s after startup
- Upgrade to capacitor 5
- Upgrade to gradle 8
- "Accounts" are now called "Profiles"
## Fixed
- [native] Reset profile syncing state on app start
- [native] Allow turning auto-sync back on
- [native] fix(AddBookmarkIntent): Close intent after saving bookmark
- [ios] fix(sharing) Fix share target
- Allow setting sync interval to 5min
- Local folder option: Make more clear what each option does and the implications of that
- Store passphrase for google-drive encryption correctly
- NextcloudBookmarks: Do not write lock after onSyncCompleted
- Fix bookmarks change detection
- Fix BrowserController#onchange: Don't error out on deleted items
- fix(FileUnreadableError): Make error message more clear
- fix(downloadLogs): Add redacted/full to file name
- fix(messages): Make it more clear that people need to install Nextcloud Bookmarks to use it
- fix(BrowserController): Set unlocked to true by default
- fix(LocalTabs): Don't activate all tabs upon creating them
- fix(ImportExport): Trigger alert when import is done
- fix(OptionsWebdav): properly import OptionsPassphrase component
- fix(OptionsSyncFolder): show spinner while running getTree
- fix(HtmlSerializer): Make html output compatible with common browsers while maintaining backward compatibility
## v4.19.1
### Fixed
- Fix Scanner ignore logic for root folders
## v4.19.0
### New
- Implement share extension for iOS
- [native] Allow sharing bookmarks to other apps
- [native] Implement bookmarks export
- [native] Allow exporting accounts
- [native] Download logs like in browser instead of sharing them as text
### Fixed
- OptionSyncInterval: Allow setting 5min
- Avoid generating diff for local absolute root folders
- fix(Default#executeAction): Prepapre subOrder Diff correctly
- Allow syncing bookmarks with file: protocol via WebDAV and GDrive
- Update dependencies
## v4.18.1
### Fixed
- Update cordova-plugin-background-mode to fix frequent crashes
- OptionSyncInterval: Allow setting 5minutes interval
- DialogEditBookmark: Don't allow submitting empty URL
- Unidirectional: ignore errors when mapping reorders
## v4.18.0
### New
- [native] Display breadcrumbs when not in root folder
- [native] Implement bookmarks import
### Fixed
- NextcloudBookmarks: Improve error message when bookmark creation fails
- [native] Log in production
- [native] NewAccount: Show IMPORTEXPORT button
- [native] Remove pull-to-refresh for now as it's buggy
- [native] Home#checkForIntent: Fix share routine
- Don't cast item IDs to boolean inside if statements
- NextcloudBookmarks: Report all statuses > 400 as HttpError
- [native] Options & NewAccount: Allow setting sync interval on android
- AccountCard: Display last sync time on error
- TEST_WEBDAV_SERVER: Improve error message
## v4.17.1
### Fixed
- Fix selecting HTML at setup (#1247)
- Fix Google Drive on native (#1246)
## v4.17.0
### New
- WebDav: Allow syncing via HTML file
- Tab Sync: Name folders by window number
- NewAccount: Add back buttons
- Options{GoogleDrive, WebDAV}: Allow removing passphrase
### Fixed
- Fixed Google Drive integration on iOS
- Fix Sync with caching-enabled WebDAV servers
- [native] Use themed background for body
- Fix Nextcloud login flow for 2FA
- [android] Fix share intent for unreachable URLs
## v4.16.0
### New
- Performance improvements
- Improve speed for Nextcloud Bookmarks
### Fixed
- SyncProcesses: Remove superfluous awaits that would stall the whole app
- a11y: improve syncing icon in browser
- ios: Hide status bar
- Fix InAppBrowser usage to comply with Apple policies
- getFavicon: Load /favicon.ico as a fallback
- UX: Remove min-width on #app
- Replace merge icon to avoid confusion with sync icon (#1198)
- OptionSyncStrategy: Improve wording
- Options: Do not show strategy if isBrowser
- [native] Fix Alphabetical sorting
## v4.15.0
### New
- [Native] AddBookmarkIntent: Autodetect page title
- NewAccount: Allow setting enabled account config
- NewAccount: Allow setting XBEL passphrase for GoogleDrive and WebDAV
-
### Fixed
- Fix order corruption of localRoot folder
- Tabs: Fix syncing multiple windows
- NewAccount: Warn user when using server without https
- Improve UI so there's space for translations
- NewAccount: Remove stepper headings so the whole stepper fits
- Failsafe: added Math.ceil to only allow integers
- New translations for Polish, French and Chinese
## v4.14.0
### New
- New stepwise account setup flow
- NewAccount: Trigger sync after completion
- Improve progress bar behavior
- Allow more than one separator per Folder on Nc Bookmarks
- [Native] Allow sorting bookmarks
- [Native] Background sync while on wifi
### Fixed
- [Native] Fix splash screen aspect ratio
- [Native] Make app-bar absolute instead of hide on scroll
- Improve wording around sync strategies
- BrowserController: Don't get stuck in sync loop
- GoogleDrive: Add cancel method
- Fix transifex integration
- UI: Do not show passwords in new options session
- Inactivity timeout := 7s
- [Native] Add allowNetwork to default settings
- Fix Tab sync order on firefox
## v4.13.1
### New
- [Native] Implement about page
### Fixed
- UI: Re-add accidentally removed actions
## v4.13.0
### New
- [native] Implement pull-to-refresh
- [native] Implement ImportExport (without export for now)
- Detect machine suspend during sync and cancel
### Fixed
- Performance: Do not query root bookmarks folder excessively
- [Android] Fix app label
- [Android] Fix Nextcloud Login flow
- Locking: Adjust LOCK_INTERVAL
- Locking: Fix wrong usage of {set,clear}Timeout
- Fix lock-file being locked in GoogleDrive and WebDAV
- Fix "failed to map parentId" in Unidirectional strategy
- Unidirectional: Fix typo
- Unidirectional: Fix progress bar
- Adjust lock override strategy
## v4.12.0
### New
- [Native] Schedule sync automatically after local edits
- [native] Implement Update screen
- Implement support for separators
- More beautiful status indicators
- Sync chrome:// URLs (but not on Firefox and not with Nextcloud bookmarks)
- Implement timed locks for GoogleDrive and WebDAV to reduce waiting time
- Reduce inactivity timeout to 20s
### Fixed
- [Native] Fix broken favicons
- [Native] speed-up tree navigation
- [native] Performance improvements
- [native] UX: Allow pressing BACK when adding/editing items
- UX: Improve progress bar feedback during syncing
- UX: Improve wording around sync strategies
- Performance: Avoid loading all of lodash
- Google Drive: Force upload when new account or new encryption
- Do not delete duplicate bookmarks anymore
- Tab sync: Do not remove duplicated tabs on sync and sync tab order
- Fix Unidirectional sync
- Unidirectional: Fix ordering
- LocalTabs: Implement set order
- Improve order reconciliation
- Keep local sort order of ignored items
- GoogleDrive: Fix locking
- WebDAV: Don't lock if using slave strategy
## v4.11.0
### New
- [Android] Implement allowNetwork option
- Tab sync: Sync tabs with names
- Overview: Sort disabled accounts last
- WebDAV: Reduce lock timeout to 15min
- GoogleDrive: Reduce lock timeout to 15min
### Fixes
- Fix UX: Have two "download logs" buttons instead of "anonymous" checkbox
- Fix tab sync
- Logger: Fix log redaction
- OptionsGoogleDrive: Don't show passphrase by default
- Do not reset cache after interrupted sync
- Do not reset cache after network error
- Test and fix complex move-remove interactions
- Update deps and install dark mode fix for android
- [Native] DialogEdit{Folder,Bookmark}: Use current folder
## v4.10.1
### Fixes
- [Android] Fix WebDAV and FaviconImage
## v4.10.0
### New
- Allow producing anonymized logs
- [Android] Allow moving items and choosing parent upon creation
- [Android] Allow Logs download
- [Android] SendIntent: Allow receiving title + fix cold start intent
### Fixes
- Get rid of capacitor-community/http (Fixes many unforeseen sync problems both on Android and Desktop)
- [Android] Clean up boilerplate clutter and update deps
- Styles: Add more spacing between option entries
- Fix load languages with hyphens (Thanks to @binsee)
## v4.9.0
### New
- [Android] Implement Google Auth
### Fixes
- [Browser] Fix i18n for displaying error messages
- OptionResetCache: Fix description l10n id
- NextcloudBookmarks: Fix getLabel to avoid 'n@d@d' labels
- UI: Validate URLs to be http(s)
## v4.8.7
### Fixes
- [Android] UI: Polish active syncing state
- [Android] Implement Nextcloud Login flow
- [Android] Don't display irrelevant options
- GoogleDrive: Harden OAuth using CSRF and PKCE Marcel Klehr Yesterday 13:13
- Allow making passwords visible
## v4.8.6
### Fixes
- build.gradle: Fix version
- NewAccount: Link to importexport view for better discovery (only in browser)
- [Android] Allow self-signed certificates added to the Android user cert store
## v4.8.5
### Fixes
- [Native] Add FundDevelopment link target
- [Native] Fix exit on back button
- Account: Fix cancelSync
- AccountCard: Remove indeterminate loading bar animation
## v4.8.4
### Fixes
- Implement sync cancellation properly
- [Android app] Enable webdav
- Browser: Display badge when all accounts are disabled
- Don't poll sync status
- Fix $store.secured: Take into account empty strings passphrases
- SetKey: Don't allow setting empty passphrase
- Allow unlocking by pressing enter after passphrase
- Build: Update browser targets
- NextcloudBookmarks: Don't wait for lock forever in case of unexpected status codes
- WebDAV: Catch redirect errors by default and add allowRedirects option
- Fix Error class inheritance
- WebDAV: Properly throw FileUnreadableError
- [Android app] Update gradle
- Update dependencies and fix security issues
- Upgrade webpack
- Update typescript compiler
## v4.8.3
### Fixes
- Fix Account#init: Don't override sync tabs setting
- NextcloudBookmarks: Fix acquireLock: Error on 404
## v4.8.2
### Fixes
- Fix i18n
## v4.8.1
### Fixes
- AccountCard: Fix spinner direction
- Mesages: Note which bookmark types are supported
- Update clientcert option description
- NextcloudBookmarks: Catch auth errors on locking mechanism
- Messages: Clarify wording of nested accounts setting
- Messages: Add note about root folder problems
- Sync: Recover from root folder CREATE actions
- Try to handle Mobile bookmarks folder
- [Android] i18n
- [Android] Fix tree loading
- [Android] Fix account deletion UX
- [Android] Override back button
## v4.8.0
### Fixes
- GoogleDrive: Save & display google username after login
- Unidirectional: Do not apply failsafe when overriding server
- Don't remove items added *during* a sync run
- NextcloudBookmarks: Implement locking
- NextcloudBookmarks: Only query all bookmarks if necessary
- NextcloudBookmarks: fix BulkImport
- LocalTabs#create: Don't load all tabs at once, set new ones as discarded
- Fix isInitialized for tab sync accounts
## v4.7.0
### New
- Sync root folder by default
- NextcloudFolders: Add option to allow redirects
- New settings UI
- New error: Trying to read encrypted file without passphrase
- UX: Make AccountCard expandable and hide all non-essential stuff
- UI: Add donate page with link to it in overview
- UI: Support system dark theme
- UI: Reduce scrollbar size
- UX: Polish folder picker
-
### Fixes
- Various syncing correctness fixes
- Rename NextcloudFolders to NextcloudBookmarks
- Fix cancel sync: Cancel sync by reloading background page
- OptionSyncInterval: Don't allow choosing 0
- OptionDeleteAccount: Ask for confirmation fist
- Fix tab sync: tab and window IDs are integers
- Controller: Reset cache after interrupted sync
- Only remove duplicates for Nextcloud
- Sync: Invalidate cache after sync error
- Performance: Always createIndex when cloning in Scanner
- Fix UnidirectionalMerge: Allow reorders
- Controller: Fix sync interval on first run
- Fix debug logs in Firefox
- Speedup loading new folders in NextcloudFolders
- ImportExport: Select all accounts by default
## v4.6.4
### Fixed
A few fixes to improve syncing accuracy:
- Unidirectional: Don't map UPDATEs to old IDs, but to newly reinserted IDs
- Scanner: Don't generate UPDATEs for items that have been MOVEd
- DefaultSyncStrategy: Fix UPDATE vs REMOVE condition
## v4.6.3
Broken release.
## v4.6.2
### Fixed
- One-time strategy change: Don't get stuck on the wrong sync strategy
- UX: Highlight default strategy in AccountCards
## v4.6.1
### Fixed
UX: NextcloudFolders: Detect HTTP redirects
Improve import/export UX
messages: Fix sync{Down,Up} wording
Reimplement Unidirectional strategy
WebDAV: Accept non-encrypted file in encryption mode
GoogleDrive: Accept non-encrypted file in encryption mode
## v4.6.0
### New
- Sync via Google Drive
- Optionally encrypt your sync file
- Allow sending client certificates
### Fixed
- Fix Crypto module
## v4.5.0
### New
- Implement failsafe to prevent data loss
### Fixed
- WebDAV: Clear cache on 404
- UI: Improve options UX by opening folder settings by default as well
- Sync: Fix "Cannot find folder to move into"
## v4.4.10
### Fixed
- Diff#findChain: Prevent infinite recursions
- Fix Logger
- executeReorderings: Don't fail sync process if REORDER fails
- executeReorderings: Make sure items are unique
## v4.4.9
### Fixed
- Sync: Fix concurrentSourceTargetRemoval case
- Sync: Filter out undefined order items
- Logger#persist: Only save last sync run
- Update chrome screenshots
- Controller: Fix link to update page
- l10n: Translate extension description
## v4.4.8
### Fixed
- Fix SyncFolder Option
- NextcloudFolders: Don't throw when failing to delete a folder or bookmark
- Sync: A lot of fixes for deletions mixed with moves
- LocalTree: Don't throw when trying to remove a non-existent item
- Fix log rotation
- Fix Scanner#addReorders in case a MOVE's old parent was removed
- Sync: Don't execute REORDERs when length <= 1
- Non-merge Sync: Only compare with cache hash, not directly in order to merge concurrent on par changes
## v4.4.7
### Fixed
- UI: NewAccount: Remove nextcloud legacy option
- NextcloudFolders: Fix sparse trees
- NextcloudFolders#updateBookmark: preserve intention when moving bookmarks
- Scanner: Clone with Hash
- Sync: Move canMergeWith detection to Scanner mergeable
- Sync: Fix race conditions
- Sync: Simplify scanner
- Sync: Avoid artificial Cycles in Toposort
- Sync: Avoid duplicate REORDERs
- Sync: Filter out REORDERs that are invlidated from hierarchy reversal remediation
- Sync: Avoid duplicates in concurrent hierarchy reversal detection
- Sync: Extend detection for concurrent hierarchy reversals
- Fix reconcileReorders
- Fix Scanner: Account for reorders at the end
## v4.4.6
### Fixed
- NextcloudFolders: Remove webdav locking
## v4.4.5
### Fixed
- Fix: Ignore changes to browser root folder
- Fix mapping in SlaveMerge strategy
## v4.4.4
### Fixed
- Fix: Ignore changes to browser root folder
## v4.4.3
### Fixed
- Fix lock timeout to 0.5h
- Detect moves of bookmarks even when ID changed
- Fix unidirectional sync strategies when no cache is available
- NextcloudFolders: Fix _getChildren for old APIs
- Fix Merge strategy
- NextcloudFolders: Performance improvements
- Add 403 to auth fail message
## v4.4.2
### Fixed
- Update some unclear wording in i18n strings
- Fix "sync up" and "sync down" buttons
- Reset cache on update to fix issues from v4.4.0
## v4.4.1
### Fixed
- Fix sync cache
- Fix: Don't touch root folders
- Fix NexcloudFolders: Use lock for getBookmarkslist
## v4.4.0
### New
- New Sync algorithm
- Implement option to sync tabs
### Fixed
- Fixed problems with old sync algorithm
- Display loading indicator for accounts overview
- Don't fail loading account if folder doesn't exist anymore
- Fix server URL validation
### Changed
- Drop support for legacy nextcloud bookmarks sync method. (Please see README for ways to migrate)
## v4.4.0-rc1
### New
- New Sync algorithm
### Fixed
- Fixed problems with old sync algorithm
- Display loading indicator for accounts overview
- Don't fail loading account if folder doesn't exist anymore
## v4.3.0
### New
- Implement import/export of accounts
### Fixed
- UI: Account card button alignment fix
- Fix OrderTracker bug (#598)
## v4.2.6
### New
- Add option for nested accounts
- Revert "Allow syncing the same folder with multiple accounts"
### Fixed
- Try to fix unmapped children error
- Sync algorithm: XOR createdUpstream with existingChildren
- Update dependencies
- NextcloudFolders: Improve error message on non-200 response
- Update screenshots
- SyncProcess: Fix concurrency for merging
- NestedSync: Fix WebDAV and NextcloudLegacy
- WebDAV: Give up faster when lock doesn't unlock
- Permissions: We may need unlimited storage
## v4.2.5
### Fixed
WebDAV adapter: Fix bookmarks_file option
## v4.2.4
### Fixed
Refactor options event handling to fix options UX
## v4.2.3
### Fixed
87ec04ed3f92706749599502ef8fd0439cb710fe Options: Fix folder picker
a9beccedffc8d585201691a16298192fc5e98884 Fix Nextcloudlogin
d84e0e1ee5288769db9c7f220b1db72bd16b5d6a Do not auto-enable accounts on udpate
### Changed
4fa192b5b06f547ea07653a3cae28d8bc2aec396 Improve styling of ADD ACCOUNT button
a759c439483c9eab8781fede148478abc14f11eb Controller: Only display update screen for non-patch updates
## v4.2.2
### Fixed
6c1b6f5200ba4c6a25585313ab847755d24d368e Sync: Fix undefined id in folder ordering
53daaebbcd37a372a79bf9795db899899e8aec4c Fixes #557: Save options on account creation
### Changed
7b737d29951ec0707af1d249398cb39fe27dc8af OrderTracker: Throw error when invariants are violated
## v4.2.1
## Fixed
- Fix "Cannot add new accounts"
- Fix disabling accounts
## v4.2.0
### Added
28573b69f81b704df2b83e25bf37f2863546ffe7 Implement nextcloud flow login
316b69cd36e78471c148e5e973090e5a5abafbd8 Add an update screen
Lots of new translations
### Fixed
4bf16e25d4e0b6f5386adb56614eb245599ec5e0 Fix for separator lines with webdav
5655e81753c13d9b94b8f6c08bdc1c74949eb569 NextcloudFolders fix non-getChildren algorithm
### Changed
a658fd02f67335b3c73b3b69e6a3bd7ac456f365 New UI using Vue.js
85c9caeb9714dc1dfdc5f8164949b9c3346c5b55 Allow syncing the same folder with multiple accounts
92bc583877359b65153a19c2c55f56ff41f99802 Don't sync immediately on startup
b7eee8e14534838f875350897576abe01a839b02 Offline Performance: Only poll status every 10s -- real updates will be on demand
454b8066ffe096c4cb264683adaf09d5c2ad7d17 NextcloudFolders: getSparseBookmarksTree: Don't load too many layers initially
2758f17fe74d8bb6603a6e674dc31d8e37ec271a Messages: Clarify DescriptionLocalfolder
956a2b6d22a5023110d5fce4063064c4a54597b9 Improve progress bar update during loadChildren
## v4.1.0
- FIX AccountStorage: Use JSON
- FIX Sync: Fix null pointer
- FIX Sync: Handle creations inside deletions gracefully
- NEW: NextcloudFolders: Speedup
## v4.0.4
- FIX: account migration code
## v4.0.3
- FIX: Add support for permanent private mode in firefox
- FIX: Remove a possible performance restriction
## v4.0.2
- FIX root folder synchronization
## v4.0.1
- FIX storage access error
## v4.0.0
- FIX: Stop sync if user is making changes
- FIX: NetxcloudFolders: Refactor sparse tree loading
- FIX: Performance optimizations
- NEW: Deprecate NextcloudLegacy adapter
- NEW: Build process: Switch to webpack
- NEW: Migrate account data from extension storage to indexedDB for faster access
- NEW: Refactor sync algorithm
## v3.5.3
- FIX: Stop sync if user is making changes
- FIX: Speed up sparse tree loading
- FIX: Refactor sparse tree loading
## v3.5.2
- FIX: Performance optimization: Only retry sparse trees if server allows hashing
- FIX: Simplify getBookmarksList
- FIX: NextcloudFolders: Increase timeout to 3min
- FIX: webdav lock acquisition mechanism
- FIX: Strategies: Refactor syncTree + always abort on cancel
- FIX: Controller: Disable account on cancelSync to avoid auto-restart
## v3.5.1
- FIX: UI: Input fields were broken
## v3.5.0
- NEW: UX: Improve "new account" flow
- NEW: UX: Make it more clear which adapter is being used in options
- NEW: Improve funding UX
- FIX: Logger: Add timestamps
## v3.4.2
- Roll back v3.4.1 due to UI issues
## v3.4.1
- NEW: Overhaul build process
- NEW: UX: Improve "new account" flow
- NEW: UX: Make it more clear which adapter is being used in options
- FIX: Logger: Add timestamps
- FIX: Translate sync duration
## v3.4.0
- NEW: Automated testing in firefox (#353)
- NEW: Add emojis to various options
- NEW: Implement cancel sync button
- NEW: Sync strategies (default/merging, slave / override browser, master / override server)
- NEW: Bulk upload for faster syncing
- FIX Account: Set rootPath on init
- FIX: Unlock enter press
- FIX: Use whatwg URL normalization
## v3.3.1
- FIX: Don't load all parts of the sparse tree in parallel
## v3.3.1
- FIX: Don't load all parts of the sparse tree in parallel
## v3.3.0
- FIX: Update conservative-normalize-url
- FIX: UI: Split path correctly to display full folder name
- FIX: NextcloudFolders: Fix Updating a bookmark that has no parent folders
- NEW: Translations
- NEW: Sparse tree syncing using hash trees
- NEW: Add option to set sync interval
- NEW: Caching adapter: Add acceptor method
- NEW: UI: Polish footer + add logo + Improve mobile support
## v3.2.16
- FIX: Don't schedule sync jobs while syncing
## v3.2.15
- FIX: URL normalizer would break some URLs with fragments
## v3.2.14
- FIX: Unlock input field
## v3.2.13
- FIX: Unlock input field
## v3.2.12
- FIX: Sync: Clear status update interval on error
- FIX: Fix form inputs
## v3.2.11
- NEW: Progress bar
- NEW: Add LoFloccus companion app (thanks to @TCB13)
- FIX: UI: Add a link to open options in new tab
- FIX: Added default font color as black to avoid issues with dark browser themes
- FIX: Tree: URL normalization: Add more strange protocols to the blacklist
## v3.2.10
- FIX: Various crucial fixes for edge cases of the sync algorithm
## v3.2.9
- FIX: Improve normalization algorithm
- FIX: Clean up duplicates caused by switching to a different normalization algorithm
## v3.2.8
- Fix: XBEL parser didn't retain ordering
- FIX: Request bookmarks in smaller chunks to avoid causing a timeout
## v3.2.7
- FIX: Fix orderPreservation algorithm
- FIX: SyncProcess: Increase performance of initial filtering
- FIX: Options UI: Rename "reset cache" option
- FIX: Fix order preservation on WebDAV
- FIX: Sync on startup if necessary
## v3.2.6
- FIX: Fix "Failed to construct 'URL'" Error
## v3.2.5
- FIX: Solve some UX issues regarding disabled accounts
- FIX: Clean up duplicates caused by switching normalization algorithm
## v3.2.4
- FIX: Use a different URL normalization library
- FIX: Correctly pass through sync effects to folder traversal logic
## v3.2.3
- FIX: Don't normalize the URLs of separators and js bookmarks to avoid deduplicating them
- FIX: Make mappings thread safe to avoid race conditions in parallel mode
- FIX: Ensure all folders are traversed when cache is empty
- FIX: Log error message to debug log on sync fail
- NEW: Add description for sync methods in UI
## v3.2.2
- FIX: Issues with syncing to nextcloud on Postgres
- FIX: Normalize webdav server URL
## v3.2.1
- FIX: Folder ordering would cause issues in some situations
## v3.2.0
- NEW: Overhaul UI
- NEW: Allow sync speedup by syncing in parallel
- FIX: Update dependencies to mitigate some minor security issues
- FIX: Speed up folder order fetching if the server supports it
- FIX a bug involving the deletion of local bookmarks
## v3.1.15
- FIX: Automatically local-only deduplicate bookmarks within local folders
- FIX: Unicode characters in passwords would cause errors
## v3.1.14
- FIX: nextcloud-folders tree construction was still broken
- FIX: Index creation was broken
## v3.1.13
- FIX: Removing folders on the server would fail
## v3.1.12
- FIX: Initial tree construction would mess up IDs of server bookmarks in nextcloud-folders adapter
## v3.1.11
- FIX: Deduplication wouldn't work reliably
## v3.1.10
- FIX NextcloudFolders adapter: Duplicates in different folders on the server would cause trouble
## v3.1.9
- FIX: Deduplication wouldn't work in all cases as URLs weren't normalized
## v3.1.8
- Roll back parallelization to mitigate issues that came up
## v3.1.7
- Various performance improvements
- FIX: Leave alone unaccepted bookmarks (e.g. bookmarklets and RSS bookmarks)
## v3.0.10
- Fix syncing moved folders
## v3.0.9
- Various UX improvements
## v3.0.8
- FIX: Fix WebDAV adapter
## v3.0.7
- FIX: Various XML parse and serialization issues have been fixed
## v3.0.6
- FIX: Properly decode titles in .xbel file
## v3.0.5
- FIX: Don't write account password to debug log
- FIX: Properly decode titles in .xbel file
## v3.0.4
- FIX: Root folder normalization in chrome wasn't working
## v3.0.3
- FIX: Securing accounts was broken
## v3.0.2
- NC bookmarks adapter: Discern folders and bookmarks when building initial tree
- WebDAV adapter: Don't continue with empty tree after error in onSyncStart
## v3.0.1
- nothing changed
## v3.0.0
- NEW: Rewritten sync algorithm allowing faster syncing and better extensibility with adapters
- NEW: Bookmarks app adapter can now handle duplicate URLs in different folders
- NEW: WebDAV adpater
- NEW: Refactored UI code and cleaner interface design
- NEW: 1-click Debug logs :tada:
- NEW: Bookmarks app adapter doesn't automatically tag untagged upstream bookmarks anymore
- NEW: Streamlined "sync everything" use case
- NEW: More explanations in the UI for people who don't read the manual
- FIX: Various UX improvements
## v2.2.9
- FIX: Adjust usage of fetch API to specification update
## v2.2.8
- FIX: recover account after error
## v2.2.7
- FIX: Pick up sync again after error
## v2.2.6
- FIX: Prevent parallel sync race condition
## v2.2.5
- FIX: Account cache was broken
## v2.2.4
- FIX: options wouldn't store values
## v2.2.3
- FIX: Debounce sync task to avoid peculiar failures
## v2.2.2
- FIX: Overtake canonical URLs from server
## v2.2.1
- FIX: Add default value for server path setting
## v2.2.0
- NEW: Map local sync folder to a specific server-side folder
- FIX: Performance improvements for Firefox
- FIX: Race condition removed that would cause issues because same account would be synced twice in parallel
## v2.1.0
- NEW: Allow using an extension key to secure entered credentials
- FIX: Various fixes for Firefox
## v2.0.6
- FIX: Correctly escape paths in tags
- FIX: Wait a certain time before starting sync when detecting changes
- FIX: first run routine was called on every startup
## v2.0.5
- FIX: Display sync folder path
## v2.0.4
- FIX: getAllAccounts didn't have a fallback for the initial loading of the extension
## v2.0.3
- FIX: Display error messages of multiple errors
- FIX: Add resource locking to fix race conditions and allow more concurrency (should fix remaining issues related to creation of duplicates)
- FIX: Refactor to only read from tree once
## v2.0.2
- FIX: Add write lock for account storage
- FIX: Refactor sync process to avoid creating duplicates
- FIX: mkdirpPath: Fix break condition
- FIX: Speed up initial tag population
- FIX: Use more stable parallel execution helper tool
## v2.0.1
- FIX: Don't remove folders beyond the sync folder when the last bookmark is remove
- FIX: Declare incompatibility with Fx < v57
- FIX: Improve error reporting
## v2.0.0
- NEW: Sync folder hierarchy
- NEW: Allow custom folders to be chosen for syncing
- NEW: Allow nesting synced folders
- NEW: Remember last sync time per account
- NEW: Overhauled user interface
- NEW: Identify local duplicates and throw an error
- FIX: Address performance problems
- FIX: Allow deleting account when syncing
- FIX: Ignore bookmarks with unsupported protocols
- FIX: Sync more often (every 15min instead of 25min)
- FIX: Call removeFromMappings on LOCALDELETE
- FIX: Improve logging and error messages
- FIX: Stop tracking bookmarks when they're moved outside the account scope
## v1.3.4
- Fix normalizeURL: The relevant commit somehow didn't make it into the release builds
## v1.3.3
- Fix normalizeUrl: Automatically add trailing slash
## v1.3.2
- Remove automated options validation (much better to just try force sync and see the error)
- Fix options rendering
- Fix bookmarks not showing up on the server in some situations
## v1.3.1
- Options panel: Fix automated connectivity check
## v1.3.0
- Major Refactoring by modularizing code base
- UI polishing
- Add 'force sync' feature
- Add account status indicator
- Fix nc url normalization
- Trigger sync on local changes
- Fix floccus fodler naming
## v1.2.0
- Switched to the new nc-bookmarks v2 API
- Increased sync interval, to reduce cpu load
## v1.1.2
- Recover if root bookmarks folder is gone
================================================
FILE: CONSIDERATIONS.md
================================================
# Considerations aka. Is this a good idea?
As there have been debates about whether this software product is a good idea, I've made a little section here with my considerations.
### Goals
The goals of this piece of software
- provide an open cross-platform sync solution for browser data with a self-hosted server
- performance is a plus, but not necessary
- (eventual) consistency is more important than intention preservation (i.e. when ever a mistake happens during sync, it's guaranteed to be eventually consistent on all sites)
### Current status and Limitations
The WebExtensions bookmarks API has a few limitations:
1. No support for batching or transactions
2. Record GUIDs can change, but are only known to change when Firefox Sync is used.
3. The data format doesn't represent descriptions, tags or separators
4. No way to create a per-device folder
5. It's impossible to express safe operations, because there are no compare-and-set primitives.
6. Triggering a sync after the first change, causing repeated syncs and inconsistency to spread to other devices.
Nonetheless, I've chosen to utilize the WebExtensions API for implementing this sync client. As I'm aware, this decision has (at least) the following consequences:
1. No transaction support (\#1) leads to bad performance
2. No support for transactions (\#1) also can potentially cause intermediate states to be synced. However, all necessary precautions are taken to prevent this and even in the case that this happens, all sites will be eventually consistent, allowing you to manually resolve possible problems after the fact.
3. Due to the modification of GUIDs (\#2), usage of Firefox Sync along with Floccus is discouraged.
4. The incomplete data format (\#3) is an open problem, but doesn't impact the synchronization of the remaining accessible data.
5. The inability to exclude folders from sync in 3rd-party extensions (\#4) is a problem, but manageable when users are able to manually choose folders to ignore. (Currently not implemented)
6. The lack of safe write operations (\#5) can be dealt with similarly to the missing transaction support: Changes made during sync could lead to an unintended but consistent state, which can be resolved manually. Additionally, precautions are taken to prevent this.
7. In order to avoid syncing prematurely (\#6) floccus employs a timeout to wait until all pending bookmarks operations are done.
================================================
FILE: LICENSE.txt
================================================
Floccus
Copyright (c) 2016 by Marcel Klehr <mklehr@gmx.net>
Mozilla Public License, version 2.0
1. Definitions
1.1. Contributor
means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software.
1.2. Contributor Version
means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributors Contribution.
1.3. Contribution
means Covered Software of a particular Contributor.
1.4. Covered Software
means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof.
1.5. Incompatible With Secondary Licenses
means
that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or
that the Covered Software was made available under the terms of version 1.1 or earlier of the License, but not also under the terms of a Secondary License.
1.6. Executable Form
means any form of the work other than Source Code Form.
1.7. Larger Work
means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software.
1.8. License
means this document.
1.9. Licensable
means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License.
1.10. Modifications
means any of the following:
any file in Source Code Form that results from an addition to, deletion from, or modification of the contents of Covered Software; or
any new file in Source Code Form that contains any Covered Software.
1.11. Patent Claims of a Contributor
means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version.
1.12. Secondary License
means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses.
1.13. Source Code Form
means the form of the work preferred for making modifications.
1.14. You (or Your)
means an individual or a legal entity exercising rights under this License. For legal entities, You includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, control means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity.
2. License Grants and Conditions
2.1. Grants
Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license:
under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and
under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version.
2.2. Effective Date
The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution.
2.3. Limitations on Grant Scope
The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor:
for any code that a Contributor has removed from Covered Software; or
for infringements caused by: (i) Your and any other third partys modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or
under Patent Claims infringed by Covered Software in the absence of its Contributions.
This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4).
2.4. Subsequent Licenses
No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3).
2.5. Representation
Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License.
2.6. Fair Use
This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents.
2.7. Conditions
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1.
3. Responsibilities
3.1. Distribution of Source Form
All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients rights in the Source Code Form.
3.2. Distribution of Executable Form
If You distribute Covered Software in Executable Form then:
such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and
You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients rights in the Source Code Form under this License.
3.3. Distribution of a Larger Work
You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s).
3.4. Notices
You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies.
3.5. Application of Additional Terms
You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction.
4. Inability to Comply Due to Statute or Regulation
If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it.
5. Termination
5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice.
5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate.
5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination.
6. Disclaimer of Warranty
Covered Software is provided under this License on an as is basis, without warranty of any kind, either expressed, implied, or statutory, including, without limitation, warranties that the Covered Software is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire risk as to the quality and performance of the Covered Software is with You. Should any Covered Software prove defective in any respect, You (not any Contributor) assume the cost of any necessary servicing, repair, or correction. This disclaimer of warranty constitutes an essential part of this License. No use of any Covered Software is authorized under this License except under this disclaimer.
7. Limitation of Liability
Under no circumstances and under no legal theory, whether tort (including negligence), contract, or otherwise, shall any Contributor, or anyone who distributes Covered Software as permitted above, be liable to You for any direct, indirect, special, incidental, or consequential damages of any character including, without limitation, damages for lost profits, loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses, even if such party shall have been informed of the possibility of such damages. This limitation of liability shall not apply to liability for death or personal injury resulting from such partys negligence to the extent applicable law prohibits such limitation. Some jurisdictions do not allow the exclusion or limitation of incidental or consequential damages, so this exclusion and limitation may not apply to You.
8. Litigation
Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a partys ability to bring cross-claims or counter-claims.
9. Miscellaneous
This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor.
10. Versions of the License
10.1. New Versions
Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number.
10.2. Effect of New Versions
You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward.
10.3. Modified Versions
If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License).
10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses
If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached.
Exhibit A - Source Code Form License Notice
> This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.
You may add additional accurate notices of copyright ownership.
Exhibit B - Incompatible With Secondary Licenses Notice
> This Source Code Form is Incompatible With Secondary Licenses, as defined by the Mozilla Public License, v. 2.0.
================================================
FILE: PRIVACY_POLICY.md
================================================
# Privacy policy
The Floccus browser extension ("Floccus") provides browser bookmarks synchronization functionality (“Functionality”) that works with privately controlled or otherwise accessible servers ("Third-party services") to store your bookmarks for synchronization. Your bookmarks are as secure as the Third-party Services you choose to store them on.
## Information you provide
**Account Information.** You provide usernames and credentials to Third-party Services for all accounts you create.
**Bookmarks.** All bookmarks that are stored in your browser are accessible to Floccus in order to provide the Functionality. Any third-party services you choose to store your bookmarks on will have access to your bookmarks.
## Information floccus collects
**Debug log.** Floccus creates a debug log of all its actions, which is only accessible to you and may be shared by you at your sole discretion with the authors in order to aid in debugging.
## Information shared with others
Neither the authors of Floccus nor the publisher receive any of the data you provide to Floccus. The authors cannot make any assurances about how the Third-party services you choose to store your bookmarks on will handle the data you provide.
## License
Please also read the License which also governs the use of floccus as well as liability of its authors.
## Contact Us
If you have questions about this Privacy Policy please contact me at mklehr@gmx.net.
Marcel Klehr
Natruper Straße 211A
49090
Germany
Effective as of Sep 28, 2018
================================================
FILE: README.md
================================================
#  Floccus

> Sync your bookmarks privately across browsers and devices
[](https://github.com/marcelklehr/floccus/actions?query=workflow%3ATests) <img src="https://img.shields.io/chrome-web-store/users/fnaicdffflnofjppbagibeoednhnbjhg.svg"> <img src="https://img.shields.io/amo/users/floccus.svg">
- 🔖 Syncs your real, native browser bookmarks directly
- ☸ Sync via [Nextcloud Bookmarks](https://github.com/nextcloud/bookmarks), [Linkwarden](https://linkwarden.app/), [KaraKeep](https://karakeep.app/), Google Drive, Dropbox, any Git server (like GitHub, Gitlab, Gitea, etc.) or [any WebDAV-compatible service](https://community.cryptomator.org/t/webdav-urls-of-common-cloud-storage-services/75)
- ⚛ Use any browser that supports Web extensions (e.g. Firefox, Chrome, Edge, Opera, Brave, Vivaldi, ...; Safari [not yet](https://github.com/floccusaddon/floccus/issues/23))
- 📲 Install the floccus Android/iOS app to access your bookmarks on your phone (Most mobile browsers do not support floccus, sadly)
- 💼 Create as many sync profiles as you need
- 🚚 Control sync strategy (i.e. uni- or bidirectional), ⏳ sync interval and 📂 synced folder
- 📦 Easily export your configuration
[](https://floccus.org/download)
This is the SHA-256 fingerprint of the certificate used to sign the floccus APKs:
```
ffed2778ff07371e6367b6dcf5d7c1327c57ff7158b8444029182a9aa2dd7085
```
If you'd like to support the creation and maintenance of this software, please consider donating. :)
| [<img src="https://img.shields.io/badge/Open%20Collective-sponsor-lightblue.svg?logo=opencollective&style=for-the-badge" alt="Open Collective">](https://opencollective.com/floccus) | [<img src="https://img.shields.io/badge/github-sponsor-violet.svg?logo=github&style=for-the-badge">](https://github.com/sponsors/marcelklehr) | [<img src="https://img.shields.io/badge/LiberaPay-sponsor-yellow.svg?logo=liberapay&style=for-the-badge">](https://liberapay.com/marcelklehr/donate) | [<img src="https://img.shields.io/badge/paypal-donate-blue.svg?logo=paypal&style=for-the-badge">](https://www.paypal.me/marcelklehr1) |
|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:| :-------------------------------------------------------------------------------------------------------------------------------------------------: |:--:|:---:|
## 🎬 Getting started
If you don't know how to start with Floccus, [read these guides](https://floccus.org/guides).
If you need help, talk to us on [gitter](https://gitter.im/marcelklehr/floccus), matrix ([`#marcelklehr_floccus:gitter.im`](https://matrix.to/#/#marcelklehr_floccus:gitter.im?utm_source=gitter)), in the [official Nextcloud Bookmarks talk channel](https://cloud.nextcloud.com/call/u52jcby9) or on [r/floccus on reddit](https://reddit.com/r/floccus) :wave:
### Troubleshooting
- **Emojis**: MySQL doesn't support emojis out of the box, so if you're syncing to nextcloud and getting Error code 500 from nextcloud, check the nextcloud log for SQL errors and [proceed as explained in the nextcloud docs if you get charset errors](https://docs.nextcloud.com/server/stable/admin_manual/configuration_database/mysql_4byte_support.html).
If you need help sorting out problems, try the gitter chat room: <https://gitter.im/marcelklehr/floccus>
## Considerations
Is this a good idea? I think so. If you'd like to know more, check out [the considerations file](./CONSIDERATIONS.md)
## What's with the name?
[Cirrus floccus](https://en.wikipedia.org/wiki/Cirrus_floccus) is a type of cloud, that <del>can sync your browser data</del> looks very nice.
## Contributors
This project exists thanks to all the people who contribute.
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<table>
<tbody>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/bernd-wechner"><img src="https://avatars2.githubusercontent.com/u/7296506?v=4?s=70" width="70px;" alt="Bernd Wechner"/><br /><sub><b>Bernd Wechner</b></sub></a><br /><a href="https://github.com/floccusaddon/floccus/issues?q=author%3Abernd-wechner" title="Bug reports">🐛</a> <a href="#ideas-bernd-wechner" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/floccusaddon/floccus/commits?author=bernd-wechner" title="Tests">⚠️</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jlbprof"><img src="https://avatars0.githubusercontent.com/u/9746421?v=4?s=70" width="70px;" alt="jlbprof"/><br /><sub><b>jlbprof</b></sub></a><br /><a href="https://github.com/floccusaddon/floccus/commits?author=jlbprof" title="Code">💻</a> <a href="https://github.com/floccusaddon/floccus/issues?q=author%3Ajlbprof" title="Bug reports">🐛</a> <a href="https://github.com/floccusaddon/floccus/commits?author=jlbprof" title="Tests">⚠️</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/TeutonJon78"><img src="https://avatars2.githubusercontent.com/u/1771400?v=4?s=70" width="70px;" alt="TeutonJon78"/><br /><sub><b>TeutonJon78</b></sub></a><br /><a href="https://github.com/floccusaddon/floccus/issues?q=author%3ATeutonJon78" title="Bug reports">🐛</a> <a href="#ideas-TeutonJon78" title="Ideas, Planning, & Feedback">🤔</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/skewty"><img src="https://avatars1.githubusercontent.com/u/9087223?v=4?s=70" width="70px;" alt="Scott P."/><br /><sub><b>Scott P.</b></sub></a><br /><a href="https://github.com/floccusaddon/floccus/issues?q=author%3Askewty" title="Bug reports">🐛</a> <a href="#ideas-skewty" title="Ideas, Planning, & Feedback">🤔</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Lantizia"><img src="https://avatars1.githubusercontent.com/u/10448369?v=4?s=70" width="70px;" alt="Lantizia"/><br /><sub><b>Lantizia</b></sub></a><br /><a href="https://github.com/floccusaddon/floccus/issues?q=author%3ALantizia" title="Bug reports">🐛</a> <a href="#ideas-Lantizia" title="Ideas, Planning, & Feedback">🤔</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://iklive.eu"><img src="https://avatars1.githubusercontent.com/u/6315832?v=4?s=70" width="70px;" alt="TCB13"/><br /><sub><b>TCB13</b></sub></a><br /><a href="https://github.com/floccusaddon/floccus/commits?author=TCB13" title="Code">💻</a> <a href="#ideas-TCB13" title="Ideas, Planning, & Feedback">🤔</a> <a href="#plugin-TCB13" title="Plugin/utility libraries">🔌</a> <a href="#translation-TCB13" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/gohrner"><img src="https://avatars0.githubusercontent.com/u/26199042?v=4?s=70" width="70px;" alt="gohrner "/><br /><sub><b>gohrner </b></sub></a><br /><a href="https://github.com/floccusaddon/floccus/issues?q=author%3Agohrner" title="Bug reports">🐛</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Tank-Missile"><img src="https://avatars0.githubusercontent.com/u/5893370?v=4?s=70" width="70px;" alt="Tank-Missile"/><br /><sub><b>Tank-Missile</b></sub></a><br /><a href="https://github.com/floccusaddon/floccus/issues?q=author%3ATank-Missile" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/tkurbad"><img src="https://avatars1.githubusercontent.com/u/158030?v=4?s=70" width="70px;" alt="Torsten Kurbad"/><br /><sub><b>Torsten Kurbad</b></sub></a><br /><a href="https://github.com/floccusaddon/floccus/issues?q=author%3Atkurbad" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/gerroon"><img src="https://avatars1.githubusercontent.com/u/8519469?v=4?s=70" width="70px;" alt="gerroon"/><br /><sub><b>gerroon</b></sub></a><br /><a href="https://github.com/floccusaddon/floccus/issues?q=author%3Agerroon" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://biciklijade.com/"><img src="https://avatars.githubusercontent.com/u/156656?v=4?s=70" width="70px;" alt="Matija Nalis"/><br /><sub><b>Matija Nalis</b></sub></a><br /><a href="#ideas-mnalis" title="Ideas, Planning, & Feedback">🤔</a> <a href="#question-mnalis" title="Answering Questions">💬</a> <a href="https://github.com/floccusaddon/floccus/issues?q=author%3Amnalis" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/marcelklehr"><img src="https://avatars.githubusercontent.com/u/986878?v=4?s=70" width="70px;" alt="Marcel Klehr"/><br /><sub><b>Marcel Klehr</b></sub></a><br /><a href="#question-marcelklehr" title="Answering Questions">💬</a> <a href="https://github.com/floccusaddon/floccus/commits?author=marcelklehr" title="Code">💻</a> <a href="#content-marcelklehr" title="Content">🖋</a> <a href="#design-marcelklehr" title="Design">🎨</a> <a href="https://github.com/floccusaddon/floccus/commits?author=marcelklehr" title="Documentation">📖</a> <a href="#infra-marcelklehr" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#maintenance-marcelklehr" title="Maintenance">🚧</a> <a href="#projectManagement-marcelklehr" title="Project Management">📆</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/binsee"><img src="https://avatars.githubusercontent.com/u/5285894?v=4?s=70" width="70px;" alt="binsee"/><br /><sub><b>binsee</b></sub></a><br /><a href="https://github.com/floccusaddon/floccus/commits?author=binsee" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://daitem.io/"><img src="https://avatars.githubusercontent.com/u/8190979?v=4?s=70" width="70px;" alt="Marc Shapiro"/><br /><sub><b>Marc Shapiro</b></sub></a><br /><a href="https://github.com/floccusaddon/floccus/commits?author=mlshapiro" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://marllus.com/"><img src="https://avatars.githubusercontent.com/u/29416568?v=4?s=70" width="70px;" alt="Marllus Lustosa"/><br /><sub><b>Marllus Lustosa</b></sub></a><br /><a href="https://github.com/floccusaddon/floccus/commits?author=marlluslustosa" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://android.izzysoft.de/"><img src="https://avatars.githubusercontent.com/u/6781438?v=4?s=70" width="70px;" alt="Izzy"/><br /><sub><b>Izzy</b></sub></a><br /><a href="https://github.com/floccusaddon/floccus/issues?q=author%3AIzzySoft" title="Bug reports">🐛</a> <a href="#ideas-IzzySoft" title="Ideas, Planning, & Feedback">🤔</a> <a href="#infra-IzzySoft" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/sunjam"><img src="https://avatars.githubusercontent.com/u/1787238?v=4?s=70" width="70px;" alt="sunjam"/><br /><sub><b>sunjam</b></sub></a><br /><a href="#ideas-sunjam" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/floccusaddon/floccus/commits?author=sunjam" title="Tests">⚠️</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/dsiminiuk"><img src="https://avatars.githubusercontent.com/u/5713547?v=4?s=70" width="70px;" alt="Danny Siminiuk"/><br /><sub><b>Danny Siminiuk</b></sub></a><br /><a href="https://github.com/floccusaddon/floccus/commits?author=dsiminiuk" title="Tests">⚠️</a> <a href="#ideas-dsiminiuk" title="Ideas, Planning, & Feedback">🤔</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Seirade"><img src="https://avatars.githubusercontent.com/u/45798662?v=4?s=70" width="70px;" alt="Seirade"/><br /><sub><b>Seirade</b></sub></a><br /><a href="#ideas-Seirade" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/floccusaddon/floccus/issues?q=author%3ASeirade" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/pinpontitit"><img src="https://avatars.githubusercontent.com/u/100489443?v=4?s=70" width="70px;" alt="pinpontitit"/><br /><sub><b>pinpontitit</b></sub></a><br /><a href="#ideas-pinpontitit" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/floccusaddon/floccus/issues?q=author%3Apinpontitit" title="Bug reports">🐛</a> <a href="https://github.com/floccusaddon/floccus/commits?author=pinpontitit" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://dmotte.github.io/"><img src="https://avatars.githubusercontent.com/u/37443982?v=4?s=70" width="70px;" alt="Motte"/><br /><sub><b>Motte</b></sub></a><br /><a href="https://github.com/floccusaddon/floccus/commits?author=dmotte" title="Code">💻</a> <a href="https://github.com/floccusaddon/floccus/issues?q=author%3Admotte" title="Bug reports">🐛</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/macrogreg"><img src="https://avatars.githubusercontent.com/u/20691812?v=4?s=70" width="70px;" alt="macrogreg"/><br /><sub><b>macrogreg</b></sub></a><br /><a href="https://github.com/floccusaddon/floccus/commits?author=macrogreg" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://www.artificialworlds.net"><img src="https://avatars.githubusercontent.com/u/76812?v=4?s=70" width="70px;" alt="Andy Balaam"/><br /><sub><b>Andy Balaam</b></sub></a><br /><a href="https://github.com/floccusaddon/floccus/commits?author=andybalaam" title="Code">💻</a> <a href="https://github.com/floccusaddon/floccus/issues?q=author%3Aandybalaam" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/balthanon"><img src="https://avatars.githubusercontent.com/u/5367358?v=4?s=70" width="70px;" alt="Balthanon"/><br /><sub><b>Balthanon</b></sub></a><br /><a href="#ideas-balthanon" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/floccusaddon/floccus/issues?q=author%3Abalthanon" title="Bug reports">🐛</a></td>
</tr>
</tbody>
</table>
<!-- markdownlint-restore -->
<!-- prettier-ignore-end -->
<!-- ALL-CONTRIBUTORS-LIST:END -->
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification.
## Contribute
All contributions, code, feedback and strategic advice, are welcome. If you have a question you can [open an issue](https://github.com/marcelklehr/floccus/issues/new) on the repository, talk to us on [gitter](https://gitter.im/marcelklehr/floccus), matrix ([`#marcelklehr_floccus:gitter.im`](https://matrix.to/#/#marcelklehr_floccus:gitter.im?utm_source=gitter)), in the [official Nextcloud Bookmarks talk channel](https://cloud.nextcloud.com/call/u52jcby9) or on [r/floccus on reddit](https://reddit.com/r/floccus). I'm also always happy for people helping me test new features -- see the issues for announcements of beta versions.
### Translating
Translations can now be provided over at [transifex](https://www.transifex.com/floccus/floccus/).

### Development
#### Setting up a dev environment
- Clone this repository.
- Install the [latest LTS version of node.js](https://nodejs.org/en/download/).
- In the root of your floccus repo, run `npm install`.
- Run `npm run build` to build.
- Find out more on how to develop browser extensions here: <https://extensionworkshop.com/>.
For building the android app you'll need Android Studio
- Open the `android/` folder in Android studio and build the App like any other Android app.
- `npm run build` and `npm run watch` will push changes to `android/` as necessary.
#### Building
- `npm run build`
Run the following to automatically compile changes as you make them:
- `npm run watch`
#### Releasing
- `npm run build-release`
#### Windows-specific considerations
Follow the above general guidance on setting up a dev environment.
There are Windows-specific versions of some npm scripts:
- build: `npm run build-win`
- build-release: `npm run build-release-win`
- watch: `watch-win`
When building for the first time you may get an error about `gulp` not being found.
You can install gulp globally on your system by executing `npm install -g gulp` from your repo root.
It is recommended that you do this proactively after executing `npm install` in the repo root for the first time.
#### Running the browser extension and corresponding tests locally
- Build the browser extension:
`npm run build-release`
(`npm run build-release-win` if you use Windows)
- After a successful build, the extension package will be found in:
`RepoRoot/builds/`
- The following steps use _Firefox_ as an example; other browsers work similarly.
The Firefox extension package is a file with an `.xpi`-extension. It is a simple archive. To modify it, you can rename it to `.zip`, make the changes, and then rename it back to `.xpi`. Many archive-related tools know this and allow you to work with the `.xpi`-file directly (e.g. [Total Commander](https://www.ghisler.com/download.htm)).
- Enable the extension package for local testing:
By default, tests are not included into the release archive. To run tests in your local browser, copy the file
`RepoRoot/dist/js/test.js`
into the release package, so that it is located at
`FloccusPackage.xpi/dist/js/test.js`
- Open Firefox using a dedicated test-profile:
**If you use your main profile for testing, the test scripts will likely destroy your existing bookmarks and open tabs!**
To interact with profiles, go to this address:
`about:profiles`
- Load the extension:
In the a dedicated Firefox profile window, go to
`about:debugging`
Select "This Firefox", and then under "Temporary Extensions", select "Load Temporary Add-on...". Then select the `.xpi`-file you prepared earlier.
(Remember to unload the extension if you need to modify/rebuild the extension package.)
- The extension is now loaded. You can access it via the browser's extensions menu.
- Run tests:
After loading the extension, click on "Manifest URL". It will open a new tab with the URL
`moz-extension://SomeGuid/manifest.json`
Modify the URL to read
`moz-extension://SomeGuid/dist/html/test.html`
, keeping the same GUID and press enter. The test run should start automatically.
- Debug or pause tests:
Press `F12` to open developer tools.
On the "Debugger" tab, you can pause the execution, set breakpoints and step through the code.
Happy developing and thank you for your contributions!
## Backers
Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/floccus#backer)]
<a href="https://opencollective.com/floccus#backers" target="_blank"><img src="https://opencollective.com/floccus/backers.svg?width=890"></a>
## Sponsors
Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/floccus#sponsor)]
<a href="https://opencollective.com/floccus/sponsor/0/website" target="_blank"><img src="https://opencollective.com/floccus/sponsor/0/avatar.svg"></a>
<a href="https://opencollective.com/floccus/sponsor/1/website" target="_blank"><img src="https://opencollective.com/floccus/sponsor/1/avatar.svg"></a>
<a href="https://opencollective.com/floccus/sponsor/2/website" target="_blank"><img src="https://opencollective.com/floccus/sponsor/2/avatar.svg"></a>
<a href="https://opencollective.com/floccus/sponsor/3/website" target="_blank"><img src="https://opencollective.com/floccus/sponsor/3/avatar.svg"></a>
<a href="https://opencollective.com/floccus/sponsor/4/website" target="_blank"><img src="https://opencollective.com/floccus/sponsor/4/avatar.svg"></a>
<a href="https://opencollective.com/floccus/sponsor/5/website" target="_blank"><img src="https://opencollective.com/floccus/sponsor/5/avatar.svg"></a>
<a href="https://opencollective.com/floccus/sponsor/6/website" target="_blank"><img src="https://opencollective.com/floccus/sponsor/6/avatar.svg"></a>
<a href="https://opencollective.com/floccus/sponsor/7/website" target="_blank"><img src="https://opencollective.com/floccus/sponsor/7/avatar.svg"></a>
<a href="https://opencollective.com/floccus/sponsor/8/website" target="_blank"><img src="https://opencollective.com/floccus/sponsor/8/avatar.svg"></a>
<a href="https://opencollective.com/floccus/sponsor/9/website" target="_blank"><img src="https://opencollective.com/floccus/sponsor/9/avatar.svg"></a>
## License
(c) Marcel Klehr
MPL-2.0 (see LICENSE.txt)
================================================
FILE: _locales/cs/messages.json
================================================
{
"Error001": {
"message": "E001: Složka k vytvoření neexistuje"
},
"Error002": {
"message": "E002: Záložka, která má být aktualizována, už neexistuje"
},
"Error003": {
"message": "E003: Složka, ze které přesunout, neexistuje. Toto je anomálie. Gratulujeme."
},
"Error004": {
"message": "E004: Složka, do které přesunout, neexistuje"
},
"Error005": {
"message": "E005: Složka, ve které vytvořit, neexistuje"
},
"Error006": {
"message": "E006: Složka, která má být aktualizována, neexistuje"
},
"Error007": {
"message": "E007: Složka, která má být přesunuta, neexistuje"
},
"Error008": {
"message": "E008: Složka, ze které přesunout, neexistuje"
},
"Error009": {
"message": "E009: Složka, do které přesunout, neexistuje"
},
"Error010": {
"message": "E010: Nedaří se nalézt složku, kterou seřadit"
},
"Error011": {
"message": "E011: Položka v seřazení složky není skutečně podřazená: {0}"
},
"Error012": {
"message": "E012: Řazení složky postrádá některé z potomků složky"
},
"Error013": {
"message": "E013: Složka, která má být odstraněna, neexistuje"
},
"Error014": {
"message": "E014: Nadřazená složka, ze které složku odstranit, neexistuje"
},
"Error015": {
"message": "E015: Neočekávaná data v odpovědi ze serveru"
},
"Error016": {
"message": "E016: Překročen časový limit na vyřízení požadavku. Zkontrolujte nastavení pro vámi využívaný server"
},
"Error017": {
"message": "E017: Chyba sítě: Zkontrolujte síťové připojení, údaje o účtu a nastavení TLS/SSL."
},
"Error018": {
"message": "E018: Nepodařilo se ověřit vůči serveru."
},
"Error019": {
"message": "E019: HTTP status {0}. Selhalo {1} požadavků. Zkontrolujte vaše nastavení serveru a záznam událostí."
},
"Error020": {
"message": "E020: Nelze analyzovat odpověď serveru."
},
"Error021": {
"message": "E021: Nekonzistentní stav serveru. Složka je přítomná v seznamu pořadí potomků ale už ne ve stromu složek"
},
"Error022": {
"message": "E022: Složka {0} údajně obsahuje neexistující záložku {1}"
},
"Error023": {
"message": "E023: Nelze odebrat soubor zámku, zvažte ruční odstranění {0}."
},
"Error024": {
"message": "E024: HTTP stav {0} při pokusu o určení stavu souboru zámku {1}"
},
"Error025": {
"message": "E025: Je třeba, aby nastavení pro soubor se záložkami nezačínalo na dopředné lomítko: „/“"
},
"Error026": {
"message": "E026: Proces synchronizace byl zrušen"
},
"Error027": {
"message": "E027: Proces synchronizace byl přerušen"
},
"Error028": {
"message": "E028: Nepodařilo se ověřit vůči serveru."
},
"Error029": {
"message": "E029: Zabezpečení proti selhání: Aktuální běh synchronizace by smazal {0}% vašich odkazů na serveru. Odmítá se provést. Pokud chcete přesto pokračovat, zakažte tuto pojistku proti selhání v nastavení profilu."
},
"Error030": {
"message": "E030: Dešifrování souboru záložek selhalo. Heslo může být špatně, nebo soubor poškozený."
},
"Error031": {
"message": "E031: Nelze se ověřit s Google Drive. Prosíme, připojte znovu floccus s vaším Google účtem."
},
"Error032": {
"message": "E032: Chyba OAuth. Chyba ověření tokenu. Prosíme, připojte znovu svůj Google účet."
},
"Error033": {
"message": "E033: Zjištěno přesměrování. Prosíme, ujistěte se, že server podporuje vybranou synchronizační metodu a zadaná URL je správně. Pokud je přesměrování součást vašeho nastavení, můžete zakázat ověření přesměrování v nastavení."
},
"Error034": {
"message": "E034: Vzdálený soubor záložek je nečitelný. Možná jste zapomněli nastavit heslo pro šifrování nebo jste nastavili špatný formát souboru."
},
"Error035": {
"message": "E035: Na serveru se nepodařilo vytvořit následující záložku: {0} -- Je aplikace záložek aktuální?"
},
"Error036": {
"message": "E036: Chybějící oprávnění na přístup k serveru"
},
"Error037": {
"message": "E037: Zdroj je uzamčen"
},
"Error038": {
"message": "E038: Nepodařilo se najít místní složku"
},
"Error039": {
"message": "E039: Nezdařilo se aktualizovat následující záložku na serveru: {0}"
},
"Error040": {
"message": "E040: Na Disku Google se nepodařilo vyhledat název souboru."
},
"Error041": {
"message": "E041: Velikost souboru vzdálených záložek se liší od obsahu, který byl skutečně stažen ze serveru. Může se jednat o dočasný problém v síti. Pokud tato chyba přetrvává, obraťte se na správce serveru."
},
"Error042": {
"message": "E042: Nelze načíst velikost souboru vzdálených záložek. Nelze ověřit, zda byl soubor záložek stažen celý. Pokud tato chyba přetrvává, obraťte se na správce serveru."
},
"Error043": {
"message": "E043: Zabezpečení proti selhání: Aktuální spuštění synchronizace by zvýšilo počet vašich odkazů na serveru o {0}%. Odmítá se provést. Pokud chcete přesto pokračovat, zakažte tuto pojistku proti selhání v nastavení profilu."
},
"Error044": {
"message": "E044: Operace Git push selhala: {0}"
},
"Error045": {
"message": "E045: Neočekávaná cesta ke složce. Místní synchronizační složka pro tento profil se dříve nacházela na adrese `{0}`, ale nyní se nachází na adrese `{1}`. Ujistěte se, že je to záměr, a v nastavení profilu znovu nastavte místní synchronizační složku."
},
"Error046": {
"message": "E046: Neplatná adresa URL. `{0}` není platná adresa URL."
},
"Error047": {
"message": "E047: Nepodařilo se analyzovat soubor XBEL. Data XBEL jsou zřejmě poškozená nebo neúplná. Můžete zkusit soubor na serveru odstranit, aby jej floccus mohl znovu vytvořit. Nezapomeňte si nejprve vytvořit zálohu."
},
"Error049": {
"message": "E049: Zabezpečení proti selhání: Aktuální spuštění synchronizace by zvýšilo počet místních odkazů v tomto profilu o {0}%. Odmítá se provést. Pokud chcete přesto pokračovat, zakažte tuto pojistku proti selhání v nastavení profilu."
},
"Error050": {
"message": "E050: Failsafe: Aktuální běh synchronizace by smazal {0}% vašich místních odkazů v tomto profilu. Odmítá se provést. Pokud chcete přesto pokračovat, zakažte tuto pojistku proti selhání v nastavení profilu."
},
"LabelWebdavurl": {
"message": "WebDAV URL"
},
"DescriptionWebdavurl": {
"message": "např. s nextcloud: https://example.com/remote.php/webdav/"
},
"LabelNextcloudurl": {
"message": "Nextcloud URL"
},
"LabelUsername": {
"message": "Uživatelské jméno"
},
"LabelPassword": {
"message": "Heslo"
},
"LabelBookmarksfile": {
"message": "Soubor záložek"
},
"DescriptionBookmarksfile": {
"message": "cesta k místu, kde bude soubor záložek na serveru umístěn, vzhledem k adrese WebDAV URL (všechny složky v cestě již musí existovat), např. personal_stuff/bookmarks.xbel."
},
"DescriptionBookmarksfilegoogle": {
"message": "název souboru záložek, který bude uložen na Disku Google. Nezadávejte celou cestu k souboru, pouze jeho název. Ujistěte se, že je tento název na vašem Disku jedinečný, např. mybookmarks.xbel."
},
"DescriptionBookmarksfilegit": {
"message": "cesta k souboru záložek relativní ke kořenu repozitáři Git (všechny složky cesty již musí existovat). Například personal_stuff/bookmarks.xbel"
},
"LabelServerfolder": {
"message": "Adresář na serveru"
},
"DescriptionServerfolder": {
"message": "Při synchronizaci budou vaše záložky v tomto prohlížeči uloženy jako odkazy pod touto cestou na serveru. Všimněte si, že tato cesta představuje složku v aplikaci Nextcloud Bookmarks, nikoli složku v Nextcloud Files. Nechte ji prázdnou, chcete-li všechny odkazy ukládat pouze do nejvyšší složky na serveru."
},
"DescriptionServerfolderlinkwarden": {
"message": "Při synchronizaci budou vaše záložky v tomto prohlížeči uloženy jako odkazy v této kolekci a s tímto prohlížečem budou synchronizovány pouze odkazy v této kolekci."
},
"DescriptionServerfolderkarakeep": {
"message": "Při synchronizaci budou vaše záložky v tomto prohlížeči uloženy jako odkazy v této kolekci a s tímto prohlížečem budou synchronizovány pouze odkazy v této kolekci."
},
"LabelLocaltarget": {
"message": "Místní cíl"
},
"DescriptionLocaltarget": {
"message": "Vyberte, zda chcete synchronizovat záložky nebo karty prohlížeče."
},
"LabelLocalfolder": {
"message": "Složka záložek"
},
"DescriptionLocalfolder": {
"message": "Bookmarks in this bookmarks folder will be stored as links on the server and links on the server will be stored as bookmarks in this bookmarks folder in this browser."
},
"LabelRootfolder": {
"message": "Kořenová složka"
},
"LabelNewfolder": {
"message": "Nově vytvořená složka"
},
"LabelSelectfolder": {
"message": "Výběr složky"
},
"LabelOptions": {
"message": "Nastavení"
},
"LabelSyncnow": {
"message": "Synchronizovat teď"
},
"LabelCancelsync": {
"message": "Zastavit synchronizaci"
},
"LabelSyncall": {
"message": "Synchronizovat všechny profily"
},
"LabelAutosync": {
"message": "Synchronizace na základě změn"
},
"StatusLastsynced": {
"message": "Naposledy synchronizováno před: {0}"
},
"StatusNeversynced": {
"message": "Zatím nesynchronizováno"
},
"StatusAllgood": {
"message": "Vše v pořádku"
},
"StatusDisabled": {
"message": "Vypnuto"
},
"StatusError": {
"message": "Chyba"
},
"StatusSyncing": {
"message": "Synchronizuje se"
},
"StatusScheduled": {
"message": "Naplánováno"
},
"LabelReset": {
"message": "Vrátit do výchozího stavu"
},
"DescriptionReset": {
"message": "Vrátit synchronizovanou složku do výchozího stavu a vytvořit novou"
},
"LabelChoosefolder": {
"message": "Vybrat složku"
},
"DescriptionChoosefolder": {
"message": "Použít pro synchronizaci existující složku"
},
"LabelRemoveaccount": {
"message": "Odebrat profil"
},
"DescriptionRemoveaccount": {
"message": "Odstranit tento profil (neodstraní vaše záložky)"
},
"LabelSyncfromscratch": {
"message": "Vyvolat synchronizaci od znovu"
},
"LabelResetCache": {
"message": "Smazat mezipaměť"
},
"DescriptionResetcache": {
"message": "Pro vymazání mezipaměti klikněte na toto tlačítko. Další synchronizace bude mít garantováno, že nesmaže žádná data pouze sloučí záložky serveru a lokální dohromady"
},
"LabelParallelsync": {
"message": "Urychlit synchronizaci"
},
"DescriptionParallelsync": {
"message": "Zaškrtnutím zapnete souběžné zpracovávání vícero složek, což urychlí synchronizaci. Tato funkce je experimentální a ztěžuje čtení záznamů s ladícími informacemi."
},
"LabelStrategy": {
"message": "Strategie synchronizace"
},
"DescriptionStrategy": {
"message": "Tato možnost určuje, jak synchronizovat záložky na jiná zařízení. Většinou budete chtít ponechat změny všech stran, pokud jsou kompatibilní. Ale někdy můžete chtít změny přepsat (zahrnuje přídavky a odstranění) z jiných prohlížečů, nebo přepsat změny udělané místně."
},
"LabelStrategydefault": {
"message": "Vždy sloučit místní změny se změnami z ostatních prohlížečů (doporučeno)"
},
"LabelStrategyslave": {
"message": "Vždy zrušit místní změny a stáhnout změny z ostatních prohlížečů."
},
"LabelStrategyoverwrite": {
"message": "Vždy nahrát místní změny a zrušit změny z ostatních prohlížečů."
},
"LabelSave": {
"message": "Uložit"
},
"LabelSelect": {
"message": "Vybrat"
},
"LabelCancel": {
"message": "Storno"
},
"LabelAdd": {
"message": "Přidat"
},
"LabelChange": {
"message": "Změnit"
},
"LabelRemove": {
"message": "Odebrat"
},
"LabelBack": {
"message": "Zpět"
},
"LabelAdapternextcloudfolders": {
"message": "Záložky Nextcloud "
},
"DescriptionAdapternextcloudfolders": {
"message": "Synchronizujte své záložky pomocí open-source aplikace Bookmarks pro Nextcloud (open-source platforma pro spolupráci, kterou můžete buď hostovat sami, nebo si u některého z různých hostitelů pořídit účet pro instanci v cloudu). Pomocí aplikace Nextcloud Bookmarks můžete synchronizovat pouze záložky http, ftp a javascript. Ujistěte se, že máte v Nextcloudu nainstalovanou aplikaci Bookmarks z obchodu s aplikacemi Nextcloud. Tato možnost nemůže využívat end-to-end šifrování."
},
"LabelAdapternextcloud": {
"message": "Nextcloud Záložky (původní)"
},
"DescriptionAdapternextcloud": {
"message": "Starší varianta je kompatibilní alespoň s verzí v0.11 aplikace Záložky. Bude emulovat složky pomocí značek obsahujících cestu ke složce. U nových profilů se nedoporučuje používat."
},
"LabelAdapterwebdav": {
"message": "WebDAV oddíl"
},
"DescriptionAdapterwebdav": {
"message": "Záložky můžete synchronizovat uložením do souboru v poskytnuté sdílené složce WebDAV. Pro tuto možnost neexistuje žádné doprovodné webové uživatelské rozhraní a můžete ji použít s libovolným serverem kompatibilním s WebDAV, ať už vlastním, nebo v cloudu. Lze synchronizovat záložky http, ftp, datové, souborové a javascriptové. Při použití této možnosti můžete zvolit použití šifrování end-to-end."
},
"LabelAddaccount": {
"message": "Přidat profil"
},
"LabelOpenintab": {
"message": "Otevřít v panelu"
},
"LabelDebuglogs": {
"message": "Záznamy ladících informací"
},
"LabelFunddevelopment": {
"message": "💸 Financovat vývoj"
},
"DescriptionFunddevelopment": {
"message": "Práce na floccus je poháněna dobrovolným předplatným. Pokud uznáte mou práci za užitečnou a můžete postrádat nějaké drobné bez nesnází, prosím, podpořte mou práci. Též prosím o hodnocení doplňku v obchodu vašeho výběru. Děkuji! 💙"
},
"LabelUntitledfolder": {
"message": "Nepojmenovaná složka"
},
"LabelSetkeybutton": {
"message": "Nastavit přístupové heslo"
},
"LabelKey": {
"message": "Zadejte vaši odemykací heslovou frázi"
},
"LabelKey2": {
"message": "Zadejte vaši odemykací heslovou frázi podruhé"
},
"LabelUnlock": {
"message": "Odemknout floccus"
},
"LabelRemovekey": {
"message": "Odebrat přístupové heslo"
},
"LabelRemovedkey": {
"message": "Přístupové heslo odebráno"
},
"LabelSyncinterval": {
"message": "Interval synchronizace"
},
"DescriptionSyncinterval": {
"message": "Časové rozpětí mezi dvěma synchronizacemi v minutách. Výchozí je 15 minut."
},
"LabelChooseadapter": {
"message": "Jak chcete synchronizovat?"
},
"LabelOptionsscreen": {
"message": "{0} možností",
"description": "Title of the options screen. The placeholder holds the profile type."
},
"LabelPaypal": {
"message": "Paypal"
},
"DescriptionPaypal": {
"message": "Přispějte na projekt jednorázově nebo pravidelně prostřednictvím služby PayPal."
},
"LabelOpencollective": {
"message": "OpenCollective"
},
"DescriptionOpencollective": {
"message": "Pokud chcete tento projekt podpořit, pravidelně darujte prostřednictvím služby OpenCollective"
},
"LabelLiberapay": {
"message": "Liberapay"
},
"DescriptionLiberapay": {
"message": "Pokud chcete tento projekt podpořit, pravidelně darujte prostřednictvím služby Liberapay"
},
"LabelGithubsponsors": {
"message": "GitHub sponzoři"
},
"DescriptionGithubsponsors": {
"message": "Pokud chcete tento projekt podpořit, pravidelně darujte prostřednictvím služby GitHub sponsors"
},
"LabelPatreon": {
"message": "Patreon"
},
"DescriptionPatreon": {
"message": "Přispívejte pravidelně pomocí Patreonu pro podporu projektu"
},
"LabelKofi": {
"message": "Kofi"
},
"DescriptionKofi": {
"message": "Přispívejte pravidelně nebo jednorázově pomocí Ko-fi pro podporu projektu"
},
"LegacyAdapterDeprecation": {
"message": "Tento starší typ profilu je zastaralý, a bude brzy odebrán. Přepněte prosím na nový způsob synchronizace nextcloud. Čeká na vás vyšší výkon a přesnost."
},
"LabelUpdated": {
"message": "⚡ Floccus byl aktualizován"
},
"DescriptionUpdated": {
"message": "Gratulujeme, na váš stroj dorazila nejnovější aktualizace doplňku floccus!"
},
"LabelReleaseNotes": {
"message": "Načíst poznámky k vydání"
},
"LabelOptionsServerDetails": {
"message": "Podrobnosti o serveru"
},
"LabelOptionsFolderMapping": {
"message": "Mapování složek"
},
"LabelOptionsSyncBehavior": {
"message": "Chování synchronizace"
},
"LabelOptionsDangerous": {
"message": "Nebezpečné akce"
},
"LabelAccountDeleted": {
"message": "Profil odstraněn"
},
"DescriptionAccountDeleted": {
"message": "Tento profil byl odstraněn"
},
"LabelNoAccount": {
"message": "Zatím bez profilů"
},
"DescriptionNoAccount": {
"message": "Přidejte nové nebo importujte profily ze souboru a můžete začít synchronizovat."
},
"LabelLoginFlowStart": {
"message": "Přihlásit se pomocí Nextcloud"
},
"LabelLoginFlowStop": {
"message": "O přihlášení pomocí Nextcloud"
},
"LabelLoginFlowError": {
"message": "Přihlášení pomocí Nextcloud selhalo"
},
"LabelNewAccount": {
"message": "Přidat profil"
},
"LabelNewImport": {
"message": "Importovat"
},
"LabelNestedSync": {
"message": "Vnořené profily"
},
"DescriptionNestedSync": {
"message": "Profily je možné vnořovat, takže nadřazená složka náleží účtu A a podřízená účtu B. Chcete povolit ostatním profilům synchronizaci i složky tohoto profilu?"
},
"LabelNestedSyncNo": {
"message": "Ne, vynechat složky tohoto profilu v jiných profilech."
},
"LabelNestedSyncYes": {
"message": "Ano, zahnout složky tohoto profilu v jiných profilech."
},
"LabelImportExport": {
"message": "Importovat/exportovat profily"
},
"LabelExport": {
"message": "Exportovat profily"
},
"LabelImport": {
"message": "Importovat profily"
},
"DescriptionExport": {
"message": "Vyberte profily, které byste chtěli exportovat do souboru, abyste je mohli jednoduše přidat v jiném zařízení nebo prohlížeči."
},
"DescriptionImport": {
"message": "Importovat soubor s exportovanými profily pro opětovné vytvoření profilů z jiného zařízení nebo prohlížeče. Prosíme, ujistěte se, že po importu znovu nastavíte správné složky synchronizace."
},
"LabelFolderNotFound": {
"message": "Složka nenalezena"
},
"LabelSyncTabs": {
"message": "Karty prohlížeče"
},
"DescriptionSyncTabs": {
"message": "Záložky uložené na serveru budou otevřeny jako karty prohližeče ve vašem prohlížeči a stávající karty budou odeslány na server. V závislosti na počtu otevřených odkazů ze serveru může být při jejich prohlížení váš prohlížeč značně zatížen."
},
"LabelTabs": {
"message": "Panely"
},
"LabelSyncDown": {
"message": "Stáhnout data"
},
"DescriptionSyncDown": {
"message": "Stáhnout změny z ostatních prohlížečů a přepsat lokální změny"
},
"LabelSyncUp": {
"message": "Nahrát data"
},
"DescriptionSyncUp": {
"message": "Nahrát lokální změny a přepsat změny z ostatních prohlížečů"
},
"LabelSyncDownOnce": {
"message": "Stáhnout data jednou"
},
"LabelSyncUpOnce": {
"message": "Nahrát data jednou"
},
"LabelSyncNormal": {
"message": "Sloučit"
},
"DescriptionSyncNormal": {
"message": "Sloučit lokální změny se změnami z ostatních prohlížečů"
},
"DescriptionFilesPermission": {
"message": "Zajistěte, abyste doplňku floccus udělili oprávnění nejen pro používání aplikace Záložky, ale také Nextcloud aplikaci Soubory."
},
"DescriptionExtension": {
"message": "Synchronizovat vaše záložky soukromě napříč prohlížeči a zařízeními"
},
"LabelFailsafe": {
"message": "Pojistka"
},
"DescriptionFailsafe": {
"message": "Někdy mohou chyby v konfiguraci nebo softwarové chyby způsobit nechtěné odstranění dat, která se pak ztratí, nebo nechtěnou duplikaci dat, kterou je pak obtížné vyřešit. Aby k tomu nedocházelo, floccus neodstraní více než 20 % vašich záložek najednou a také nepřidá více než 20 % k počtu odkazů najednou, pokud zde tuto pojistku nevypnete."
},
"LabelFailsafeon": {
"message": "Povoleno. Neodstraní nebo nepřidá více než 20 % z/do vašich místních záložek, aniž by se vás na to zeptal. (Doporučeno)"
},
"LabelFailsafeoff": {
"message": "Postižení. Povolí odebrání nebo přidání více než 20 % z/do místních záložek bez potvrzení."
},
"StatusFailsafeoff": {
"message": "Zabezpečení proti selhání je vypnuto. Hrozí nechtěná ztráta nebo duplikace dat. Doporučujeme zapnout funkci failsafe v nastavení profilu."
},
"LabelAdaptergoogledrive": {
"message": "Google Disk"
},
"DescriptionAdaptergoogledrive": {
"message": "Synchronizujte záložky přes (voltelně zašifrovaný) soubor, který bude uložen na vašem Google Drive. Mohou být synchronizovány záložky http, ftp, datové, souborové a javascriptové. Můžete si vybrat použití šifrování mezi koncovými body."
},
"LabelLogingoogle": {
"message": "Přihlášení pomocí Google"
},
"DescriptionLogingoogle": {
"message": "Připojte váš Google účet pro ukládání synchronizačního souboru záložek na váš Google Drive."
},
"DescriptionLoggedingoogle": {
"message": "Připojili jste váš Google účet pro ukládání synchronizačního souboru záložek na váš Google Drive."
},
"LabelPassphrase": {
"message": "Přístupové heslo"
},
"DescriptionPassphrase": {
"message": "Nastavte heslo pro šifrování vašeho souboru záložek. Pokud žádné nenastavíte, soubor nebude šifrován."
},
"LabelClientcert": {
"message": "Poslat klientské přístupové údaje"
},
"DescriptionClientcert": {
"message": "Povolte tuto možnost, pokud váš server vyžaduje certifikát klienta nebo cookie pro ověření. Může to způsobit nechtěné vedlejší účinky, jelikož floccus bude sdílet cookies s vaší běžnou relací prohlížení."
},
"LabelAllowredirects": {
"message": "Povolit přesměrování v URL serveru"
},
"DescriptionAllowredirects": {
"message": "Povolte tuto možnost, pokud dostáváte chyby přesměrování při synchronizaci, u kterých věříte, že jsou nezaručené."
},
"LabelSearch": {
"message": "Hledat v záložkách"
},
"LabelSearchfolder": {
"message": "Hledat {0}"
},
"LabelEdititem": {
"message": "Upravit"
},
"LabelDeleteitem": {
"message": "Odstranit"
},
"DescriptionReallydeleteitem": {
"message": "Opravdu chcete tuto položku smazat?"
},
"LabelNobookmarks": {
"message": "Nejsou tu žádné záložky"
},
"LabelAddbookmark": {
"message": "Přidat záložku"
},
"LabelEditbookmark": {
"message": "Upravit záložku"
},
"LabelAddfolder": {
"message": "Přidat složku"
},
"LabelEditfolder": {
"message": "Upravit složku"
},
"LabelSlugline": {
"message": "Soukromá synchronizace záložek"
},
"LabelDownloadlogs": {
"message": "Stáhnout záznam událostí"
},
"LabelDownloadfulllogs": {
"message": "Celý záznam událostí"
},
"LabelDownloadanonymizedlogs": {
"message": "Anonymizovaný záznam událostí"
},
"DescriptionDownloadlogs": {
"message": "Floccus zaznamenává všechny akce do souboru se záznamem událostí, který můžete sami zkontrolovat nebo jej zaslat vývojářům pro účely odhalení chyby. V anonymizovaném záznamu událostí jsou, názvy složek, záložek a stejně tak i URL adresy, nevratně zakódované pomocí kryptografických hašovacích funkcí. Když odesíláte anonymizovaný záznam událostí, ujistěte se, že stažený soubor neobsahuje žádná citlivá data, která nemusela být podchycena v anonymizačním procesu."
},
"ErrorFolderloopselected": {
"message": "Nelze přesunout složku do sebe samé"
},
"ErrorNofolderselected": {
"message": "Není vybrána složka"
},
"LabelAllownetwork": {
"message": "Umožnit využívání sítě"
},
"DescriptionAllownetwork": {
"message": "Folccus může použít síť mimo připojení k vašemu synchronizačnímu serveru i pro získání dalších informací o vašich záložkách (jako ikony). Zde můžete dovolit toto využití sítě."
},
"LabelMobilesettings": {
"message": "Nastavení pro mobilní platformu"
},
"LabelContinuefloccus":{
"message": "Pokračovat do floccus"
},
"LabelAbout":{
"message": "O floccus"
},
"LabelCurrentversion": {
"message": "Aktuální verze"
},
"DescriptionCurrentversion": {
"message": "Vámi nainstalovaná verze floccus je:"
},
"LabelContributors": {
"message": "Přispěvatelé"
},
"DescriptionContributors": {
"message": "Díky těmto lidem mohl floccus vzniknout"
},
"LabelSortcustom": {
"message": "Vlastní"
},
"LabelSorturl": {
"message": "Odkaz"
},
"LabelSorttitle": {
"message": "Název"
},
"LabelSyncmethod": {
"message": "Metoda synchronizace"
},
"LabelSyncserver": {
"message": "Synchronizační server"
},
"LabelSyncfolders": {
"message": "Synchronizovat složky"
},
"LabelSyncbehavior": {
"message": "Chování synchronizace"
},
"LabelContinue": {
"message": "Pokračovat"
},
"LabelDone": {
"message": "Hotovo"
},
"LabelConnect": {
"message": "Připojit"
},
"LabelServersetup": {
"message": "Se kterým serverem chcete synchronizovat?"
},
"LabelGoogledrivesetup": {
"message": "Přihlášení do Google Disk"
},
"LabelSyncfoldersetup": {
"message": "Které složky chcete synchronizovat?"
},
"LabelSyncbehaviorsetup": {
"message": "Jak chcete, aby synchronizace fungovala?"
},
"LabelAccountcreated": {
"message": "Profil vytvořen"
},
"DescriptionAccountcreated": {
"message": "A ještě jedna věc: Synchronizace není zálohování. Zajistěte si pravidelné zálohování záložek.\n\nTaké si uvědomte, že kombinace floccus se synchronizací záložek zabudovaných v prohlížeči není podporována a můžete skončit s duplicitami."
},
"DescriptionNonhttps": {
"message": "Byl zadán server, který používá nezabezpečený protokol. Je doporučeno používat pouze servery podporujícíc HTTPS."
},
"LabelFiletype": {
"message": "Formát souboru"
},
"DescriptionFiletype": {
"message": "Můžete si vybrat formát ukládání záložek v online úložišti."
},
"LabelFiletypehtml": {
"message": "HTML, široce podporovaný a otevřený formát (experimentální)"
},
"LabelFiletypexbel": {
"message": "XBEL, jednoduchý otevřený formát"
},
"LabelImportbookmarks": {
"message": "Naimportovat záložky"
},
"DescriptionImportbookmarks": {
"message": "Naimportovat HTML soubor se záložkami do stávající složky"
},
"LabelExportBookmarks": {
"message": "Exportovat záložky"
},
"DescriptionExportBookmarks" : {
"message": "Můžete exportovat všechny záložky tohoto profilu ve formátu HTML, který je kompatibilní se všemi hlavními prohlížeči."
},
"LabelShareitem": {
"message": "Sdílet"
},
"LabelImportsuccessful": {
"message": "Profil(y) úspěšně importován(y)"
},
"DescriptionSyncinprogress": {
"message": "Synchronizace probíhá."
},
"DescriptionSyncscheduled": {
"message": "Tento profil bude brzy synchronizován. Čekáme na dokončení synchronizace vašich ostatních zařízení nebo jiných profilů na tomto zařízení."
},
"LabelAdaptergit": {
"message": "Git přes HTTPS"
},
"DescriptionAdaptergit": {
"message": "Možnost Git synchronizuje záložky tak, že je uloží do souboru v poskytnutém úložišti Git. Pro tuto možnost není k dispozici žádné doprovodné webové rozhraní, ale můžete ji použít s jakýmkoli hostingovým serverem Git, jako je Github, Gitlab, Gitea atd. Dokáže synchronizovat záložky http, ftp, datové, souborové a javascriptové. Při použití této možnosti nelze využít end-to-end šifrování. Tato možnost není v mobilní aplikaci v současné době k dispozici."
},
"LabelGiturl": {
"message": "URL repozitáře pomocí HTTP"
},
"LabelGitbranch": {
"message": "Větev Gitu"
},
"LabelTelemetry": {
"message": "Automatizované hlášení chyb"
},
"DescriptionTelemetry": {
"message": "Floccus může automaticky posílat data o chybách mně - vývojáři. Toto je obrovská pomoc při zjišťování a rychlejší řešení chyb ve floccus a zlepší se vaše zkušenost s floccus v dlouhodobém horizontu. I když je hlášení chyb povolené, vývojáři floccus nikdy nebudou mít přístup k vašim záložkám."
},
"DescriptionTelemetrysyncmethod": {
"message": "Novinka: Kromě informací o chybách nyní floccus odesílá také informace o tom, jakou metodu synchronizace používáte, pokud je tato možnost povolena. To nám pomáhá vylepšovat aplikaci floccus a ujišťovat se, že synchronizační metody fungují podle očekávání."
},
"LabelTelemetryenable": {
"message": "Automatické odesílání chybových údajů a informací o tom, jakou metodu synchronizace používáte, vývojářům aplikace floccus."
},
"LabelTelemetrydisable": {
"message": "Neposílejte vývojářům floccus žádná data"
},
"LabelAccountlabel": {
"message": "Označení profilu"
},
"DescriptionAccountlabel": {
"message": "Dejte tomuto profilu název pro snazší rozpoznání"
},
"LabelClickcount": {
"message": "Počet kliknutí"
},
"DescriptionClickcount": {
"message": "Posílat statistiky o otevírání záložek na Nextcloud server, abyste je mohli řadit dle počtu otevření"
},
"DescriptionGoogleplayreview": {
"message": "Napište recenzi na Google Play"
},
"DescriptionAppstorereview": {
"message": "Napište recenzi na App Store"
},
"DescriptionChromereview": {
"message": "Napište recenzi na Chrome WebStore"
},
"DescriptionAlternativereview": {
"message": "Napište recenzi na AlternativeTo.net"
},
"DescriptionMozillareview": {
"message": "Napište recenzi na Rozšířeních Mozilla"
},
"DescriptionEdgereview": {
"message": "Napište recenzi na Rozšířeních Edge"
},
"LabelWritereview": {
"message": "💙 Sdílejte lásku!"
},
"DescriptionWritereview": {
"message": "Pokud vás floccus zajímá, dejte o tom světu vědět na jedné z platforem níže."
},
"DescriptionDonateintervention": {
"message": "Máte rádi synchronizaci záložek? Podpořte mě."
},
"LabelDonate": {
"message": "Přispět"
},
"DescriptionDisabledaftererror": {
"message": "Vyzkoušeno 10x před zakázáním tohoto profilu"
},
"DescriptionBookmarkexists": {
"message": "Tato záložka ve vybraném profilu již existuje"
},
"LabelReportproblem": {
"message": "Ohlásit problém"
},
"DescriptionReportproblem": {
"message": "Pokud se chcete obrátit s konkrétním problémem přímo na vývojáře, můžete tak učinit zde:"
},
"LabelAdapterKarakeep": {
"message": "Karakeep"
},
"DescriptionAdapterKarakeep": {
"message": "Synchronizujte své záložky s aplikací Karakeep s otevřeným zdrojovým kódem. Tato možnost nemůže využívat end-to-end šifrování a nepodporuje zachování pořadí záložek při synchronizaci."
},
"LabelApiKey": {
"message": "Klíč API"
},
"LabelKarakeepurl": {
"message": "Adresa URL vašeho serveru Karakeep"
},
"LabelKarakeepconnectionerror": {
"message": "Nepodařilo se připojit k serveru Karakeep"
},
"LabelAdapterlinkwarden": {
"message": "Linkwarden"
},
"DescriptionAdapterlinkwarden": {
"message": "Synchronizujte své záložky s aplikací Linkwarden s otevřeným zdrojovým kódem, která je umístěna na vašem vlastním serveru nebo v cloudu na adrese cloud.linkwarden.app. Lze synchronizovat pouze záložky http, ftp a javascriptové záložky. Tato možnost nemůže využívat end-to-end šifrování a nepodporuje zachování pořadí záložek napříč synchronizacemi."
},
"LabelLinkwardenurl": {
"message": "Adresa URL vašeho serveru Linkwarden"
},
"LabelAccesstoken": {
"message": "Přístupový token"
},
"LabelLinkwardenconnectionerror": {
"message": "Nepodařilo se připojit k serveru Linkwarden"
},
"LabelSearchresultsotherfolders": {
"message": "Výsledky z jiných složek"
},
"LabelScheduledforcesync": {
"message": "Vynutit synchronizaci"
},
"DescriptionScheduledforcesync": {
"message": "Opravdu chcete vynutit synchronizaci? Synchronizace se dvěma zařízeními současně může mít nepředvídatelné následky včetně poškození dat. Před potvrzením se ujistěte, že v danou chvíli neprobíhá synchronizace s žádným jiným zařízením."
},
"DescriptionAutosync": {
"message": "Zapnutím synchronizace na základě změn zajistíte, že se synchronizace spustí pokaždé, když provedete místní změny."
},
"LabelOpeninnewtab": {
"message": "Otevření tohoto zobrazení na nové kartě"
},
"LabelGivefeedback": {
"message": "Poskytněte zpětnou vazbu"
},
"LabelYourname": {
"message": "Vaše jméno"
},
"LabelYouremail": {
"message": "Váš e-mail (nepovinné)"
},
"LabelYourmessage": {
"message": "Vaše zpětná vazba"
},
"LabelSubmitfeedback": {
"message": "Odeslat zpětnou vazbu"
},
"DescriptionFeedbacklegal": {
"message": "Tento formulář pro zpětnou vazbu využívá službu Sentry. Stisknutím tlačítka odeslat souhlasíte s uložením zadaných údajů na serverech společnosti Sentry. Žádné z vašich údajů o záložkách nebudou odeslány společnosti Sentry."
},
"DescriptionFeedbackhowto": {
"message": "Děkujeme, že jste věnovali čas a poskytli vývojářům floccusu zpětnou vazbu! Pokud se vaše zpětná vazba týká problému, nezapomeňte uvést, jaké kroky jste podnikli, co jste očekávali a co se místo toho stalo. Pokud se vaše zpětná vazba týká požadavku na funkci, nezapomeňte uvést případ použití nebo problém, který by pro vás tato funkce vyřešila. Pokud uvedete svůj e-mail, můžeme se vám ozvat. Děkujeme vám!"
},
"LabelFeedbacksent": {
"message": "Děkujeme za vaši zpětnou vazbu!"
},
"LabelFaq":{
"message": "Podívejte se na často kladené dotazy"
},
"StatusSyncingfailed": {
"message": "Synchronizace se nezdařila"
},
"StatusSyncingcomplete": {
"message": "Synchronizace dokončena"
},
"NotificationSyncingprofile": {
"message": "Synchronizační profil {0}"
},
"NotificationSyncingsucceeded": {
"message": "Synchronizace profilu {0} byla úspěšná"
},
"NotificationSyncingfailed": {
"message": "Nepodařilo se synchronizovat profil {0}"
},
"LabelSyncintervalenabled": {
"message": "Časová synchronizace"
},
"DescriptionSyncintervalenabled": {
"message": "Zapnutím synchronizace podle času se automaticky naplánuje synchronizace tohoto profilu každých několik minut."
}
}
================================================
FILE: _locales/de/messages.json
================================================
{
"Error001": {
"message": "E001: Der Ordner, in dem neu erzeugt werden soll, existiert nicht."
},
"Error002": {
"message": "E002: Zu aktualisierendes Lesezeichen existiert nicht mehr."
},
"Error003": {
"message": "E003: Der Ordner, aus dem verschoben werden soll, existiert nicht. Dies ist eine Anomalie. Herzlichen Glückwunsch."
},
"Error004": {
"message": ".E004: Der Ordner, in den verschoben werden soll, existiert nicht"
},
"Error005": {
"message": "E005: Der Ordner, in dem erzeugt werden soll, existiert nicht."
},
"Error006": {
"message": "E006: Zu aktualisierender Ordner existiert nicht."
},
"Error007": {
"message": "E007: Zu verschiebender Ordner existiert nicht."
},
"Error008": {
"message": "E008: Der Ordner, aus dem verschoben werden soll, existiert nicht."
},
"Error009": {
"message": "E009: Der Ordner, in den verschoben werden soll, existiert nicht."
},
"Error010": {
"message": "E010: Zu ordnender Ordner konnte nicht gefunden werden."
},
"Error011": {
"message": "E011: Der Eintrag in der Ordner-Ordnung ist kein Kind des Ordners: {0}"
},
"Error012": {
"message": "E012: Der Ordner-Ordnung fehlen einige Kinder des Ordners."
},
"Error013": {
"message": "E013: Zu löschender Ordner existiert nicht."
},
"Error014": {
"message": "E014: Der Elternordner, aus dem gelöscht werden soll, existiert nicht."
},
"Error015": {
"message": "E015: Unerwartete Antwortdaten vom Server erhalten."
},
"Error016": {
"message": "E016: Zeitüberschreitung einer Anfrage. Überprüfen Sie die Server-Konfiguration."
},
"Error017": {
"message": "E017: Netzwerkfehler: Überprüfen Sie Ihre Netzwerkverbindung, Ihre Kontodaten und Ihre TLS/SSL-Einstellungen."
},
"Error018": {
"message": "E018: Konnte nicht am Server authentifiziert werden."
},
"Error019": {
"message": "E019: HTTP-Status {0}. Fehlerhafte Anfrage {1}: {2}. Überprüfe die Serverkonfiguration und das Protokoll."
},
"Error020": {
"message": "E020: Die Serverantwort konnte nicht geparst werden."
},
"Error021": {
"message": "E021: Inkonsistenter Server-Zustand. Ein Ordner ist in der Kind-Ordnung enthalten, aber nicht im Ordner-Baum."
},
"Error022": {
"message": "E022: Ordner {0} enthält angeblich ein nicht existierendes Lesezeichen: {1}"
},
"Error023": {
"message": "E023: Freigabe der Lock-Datei war nicht erfolgreich. Erwägen Sie {0} von Hand zu löschen."
},
"Error024": {
"message": "E024: HTTP-Status {0} während des Ermittelns des Status der Lock-Datei {1}."
},
"Error025": {
"message": "E025: Die Einstellung der Bookmarks-Datei darf nicht mit einem Schrägstrich beginnen: '/'"
},
"Error026": {
"message": "E026: Der Synchronisierungsprozess wurde abgebrochen"
},
"Error027": {
"message": "E027: Der Synchronisierungsprozess wurde unterbrochen."
},
"Error028": {
"message": "E028: Konnte nicht am Server authentifiziert werden. Falls Sie 2FA nutzen, stellen Sie sicher auch Zugriff auf alle Dateien zu gewähren."
},
"Error029": {
"message": "E029: Failsafe: Der aktuelle Synchronisierungslauf würde {0} % der Links auf dem Server löschen. Die Ausführung wird verweigert. Deaktiviere diese Sicherheitsvorkehrung in den Profileinstellungen, wenn Du trotzdem fortfahren möchtest. Wenn Du dies nicht verursacht hast, kann die Schaltfläche für die manuelle Synchronisierung verwendet werden, um den lokalen Status auf diesem Gerät mit dem Status auf dem Server zu überschreiben. Wenn Du glaubst, dass es sich um einen Fehler handelt, wenden Sie sich bitte mit dem Debug-Protokoll dieses Laufs an die Entwickler."
},
"Error030": {
"message": "E030: Entschlüsseln der Lesezeichendatei fehlgeschlagen. Die Passphrase könnte falsch oder die Datei beschädigt sein."
},
"Error031": {
"message": "E031: Authentifizierung mit Google Drive fehlgeschlagen. Bitte verbinden Sie Floccus noch einmal mit Ihrem Google-Konto."
},
"Error032": {
"message": "E032: OAuth-Fehler. Tokenvalidierungsfehler. Bitte verbinden Sie sich erneut mit ihrem Google-Konto."
},
"Error033": {
"message": "E033: Weiterleitung festgestellt. Vergewissern Sie sich, dass der angegebene Server die ausgewählte Synchronisierungsmethode unterstützt und die URL stimmt, die Sie eingegeben haben und nicht auf eine andere URL weiterleitet. Falls die Weiterleitung teil Ihres Server-Setups ist, können Sie diese Kontrolle in den Einstellungen deaktivieren."
},
"Error034": {
"message": "E034: Die entfernte Lesezeichendatei ist nicht lesbar. Vielleicht hast du vergessen eine Verschlüsselungspassphrase anzugeben oder das falsche Dateiformat genutzt."
},
"Error035": {
"message": "E035: Das folgende Lesezeichen konnte nicht auf dem Server erstellt werden: {0} -- Ist die Lesezeichen-App auf dem neuesten Stand?"
},
"Error036": {
"message": "E036: Fehlende Berechtigungen für den Zugriff auf den Sync-Server"
},
"Error037": {
"message": "E037: Ressource ist gesperrt"
},
"Error038": {
"message": "E038: Konnte lokalen Ordner nicht finden"
},
"Error039": {
"message": "E039: Das folgende Lesezeichen konnte nicht auf dem Server aktualisiert werden: {0}"
},
"Error040": {
"message": "E040: Es konnte nicht nach Ihrem gewählten Dateinamen in Google Drive gesucht werden"
},
"Error041": {
"message": "E041: Die Größe der Lesezeichen-Datei auf dem Server unterscheidet sich von der heruntergeladenen Datei. Dies könnte ein temporäres Netzwerk-Problem sein. Falls dieser Fehler jedoch bestehen bleibt, kontaktieren sie den Server-Administrator."
},
"Error042": {
"message": "E042: Die Größe der Lesezeichen-Datei auf dem Server kontte nicht ermittelt werden. Es ist somit nicht möglich zu überprüfen, ob die Datei vollständig heruntergeladen wurde. Falls dieser Fehler bestehen bleibt kontaktieren Sie den Server-Administrator."
},
"Error043": {
"message": "E043: Failsafe: Der aktuelle Synchronisierungsvorgang würde die Anzahl der Links auf dem Server um {0} % erhöhen. Die Ausführung wird verweigert. Deaktiviere diesen Sicherheitsmechanismus in den Profileinstellungen, wenn du trotzdem fortfahren möchtest. Wenn du dies nicht verursacht hast, kannst du die Schaltflächen für die manuelle Synchronisierung verwenden, um den lokalen Status auf diesem Gerät mit dem Status auf dem Server zu überschreiben. Wenn Du glaubst, dass es sich um einen Fehler handelt, wende dich bitte mit dem Debug-Protokoll dieses Durchlaufs an die Entwickler."
},
"Error044": {
"message": "E044: Git push Operation fehlgeschlagen: {0}"
},
"Error045": {
"message": "E045: Unerwarteter Ordnerpfad. Der lokale Sync-Ordner für dieses Profil befand sich früher unter \"{0}\", ist aber jetzt unter \"{1}\". Bitte vergewissern Sie sich, dass dies beabsichtigt ist, und stellen Sie den lokalen Synchronisierungsordner in den Profileinstellungen erneut ein."
},
"Error046": {
"message": "E046: Ungültige URL. {0} \" ist keine gültige URL."
},
"Error047": {
"message": "E047: XBEL-Datei konnte nicht geparst werden. Die XBEL-Daten scheinen beschädigt oder unvollständig zu sein. Sie können versuchen, die Datei auf dem Server zu löschen, damit Floccus sie neu erstellen kann. Stellen Sie sicher, dass Sie vorher ein Backup erstellen."
},
"Error049": {
"message": "E049: Failsafe: Der aktuelle Synchronisierungslauf würde die Anzahl der lokalen Verknüpfungen in diesem Profil um {0} % erhöhen. Die Ausführung wird verweigert. Deaktiviere diese Sicherheitsvorkehrung in den Profileinstellungen, wenn du trotzdem fortfahren möchten. Wenn du dies nicht verursacht hast, kannst du die Schaltflächen für die manuelle Synchronisierung verwenden, um den lokalen Status auf diesem Gerät mit dem Status auf dem Server zu überschreiben. Wenn du glaubst, dass es sich um einen Fehler handelt, wende dich bitte mit dem Debug-Protokoll dieses Durchlaufs an die Entwickler."
},
"Error050": {
"message": "E050: Failsafe: Der aktuelle Synchronisierungslauf würde {0} % Ihrer lokalen Links in diesem Profil löschen. Ausführung wird verweigert. Deaktiviere diese Sicherheitsvorkehrung in den Profileinstellungen, wenn du trotzdem fortfahren möchten. Wenn du dies nicht verursacht hast, kannst du die Schaltflächen für die manuelle Synchronisierung verwenden, um den lokalen Status auf diesem Gerät mit dem Status auf dem Server zu überschreiben. Wenn du glaubst, dass es sich um einen Fehler handelt, wende dich bitte mit dem Debug-Protokoll dieses Durchlaufs an die Entwickler."
},
"Error051": {
"message": "E051: Die Authentifizierung bei Dropbox ist fehlgeschlagen. Bitte verbinde Floccus erneut mit dem Dropbox-Konto."
},
"Error052": {
"message": "E052: OAuth-Fehler. Fehler bei der Token-Überprüfung. Bitte verbinde dein Dropbox-Konto erneut."
},
"Error053": {
"message": "E053: Der Dateiname konnte in Deiner Dropbox nicht gefunden werden"
},
"Error054": {
"message": "E054: Vorlage für Dropbox konnte nicht abgerufen werden"
},
"LabelWebdavurl": {
"message": "WebDAV-URL"
},
"DescriptionWebdavurl": {
"message": "z. B. mit Nextcloud: https://ihre-domain.com/remote.php/webdav/"
},
"LabelNextcloudurl": {
"message": "Nextcloud-URL"
},
"LabelUsername": {
"message": "Benutzername"
},
"LabelPassword": {
"message": "Passwort"
},
"LabelBookmarksfile": {
"message": "Lesezeichen-Datei"
},
"DescriptionBookmarksfile": {
"message": "Ein Pfad zur Lesezeichendatei auf dem Server, relativ zur WebDAV-URL (alle Ordner darin müssen bereits existieren). z.B. persönlich/lesezeichen.xbel (Kein Schrägstrich am Anfang!)"
},
"DescriptionBookmarksfilegoogle": {
"message": "Der Dateiname der Lesezeichendatei, die in Ihrem Google Drive gespeichert wird. Stellen Sie sicher, dass der Dateiname in Google Drive einzigartig ist. z.B. MeineLesezeichen.xbel"
},
"DescriptionBookmarksfiledropbox": {
"message": "Der Dateiname der Lesezeichen-Datei, die in deiner Dropbox gespeichert wird. Gib nicht den vollständigen Dateipfad ein, sondern nur den Dateinamen. Achte darauf, dass dieser Name in der Dropbox eindeutig ist. Z. B. mybookmarks.xbel"
},
"DescriptionBookmarksfilegit": {
"message": "Pfad zur Lesezeichen-Datei, relativ zu deinem Git-Repository Wurzelverzeichnis (alle Verzeichnisse auf diesem Pfad müssen bereits existieren), z.B. personal_stuff/bookmarks.xbel"
},
"LabelServerfolder": {
"message": "Ziel auf dem Server"
},
"DescriptionServerfolder": {
"message": "Beim Synchronisieren werden Ihre Lesezeichen in diesem Browser als Links unter diesem Pfad auf dem Server gespeichert. Beachten Sie, dass dieser Pfad einen Ordner in der Nextcloud Bookmarks-App darstellt, nicht einen Ordner in Nextcloud Files. Lassen Sie dieses Feld leer, um alle Links direkt im obersten Ordner auf dem Server zu platzieren."
},
"DescriptionServerfolderlinkwarden": {
"message": "Beim Synchronisieren werden deine Lesezeichen in diesem Browser als Links in dieser Kollektion in Linkwarden gespeichert und nur Links in dieser Kollektion werden mit diesem Browser synchronisiert."
},
"DescriptionServerfolderkarakeep": {
"message": "Beim Synchronisieren werden deine Lesezeichen in diesem Browser als Links in dieser Kollektion in KaraKeep gespeichert und nur Links in dieser Kollektion werden mit diesem Browser synchronisiert."
},
"LabelLocaltarget": {
"message": "Lokales Ziel"
},
"DescriptionLocaltarget": {
"message": "Wählen Sie hier aus, ob Sie Browser-Lesezeichen oder Browser-Tabs synchronisieren möchten."
},
"LabelLocalfolder": {
"message": "Lesezeichenordner"
},
"DescriptionLocalfolder": {
"message": "Lesezeichen in diesem Lesezeichenordner werden als Links auf dem Server gespeichert und Links auf dem Server werden als Lesezeichen in diesem Lesezeichenordner in diesem Browser gespeichert."
},
"LabelRootfolder": {
"message": "Wurzelordner"
},
"LabelNewfolder": {
"message": "Neu erstellter Ordner"
},
"LabelSelectfolder": {
"message": "Ordner wählen"
},
"LabelOptions": {
"message": "Optionen"
},
"LabelSyncnow": {
"message": "Jetzt synchronisieren"
},
"LabelCancelsync": {
"message": "Abbrechen"
},
"LabelSyncall": {
"message": "Alle Profile synchronisieren"
},
"LabelAutosync": {
"message": "Änderungsbasierte Synchronisierung"
},
"StatusLastsynced": {
"message": "Zuletzt synchronisiert: vor {0}"
},
"StatusNeversynced": {
"message": "Noch nie synchronisiert."
},
"StatusAllgood": {
"message": "Alles gut"
},
"StatusDisabled": {
"message": "Deaktiviert"
},
"StatusError": {
"message": "Fehler"
},
"StatusSyncing": {
"message": "Synchronisiere"
},
"StatusScheduled": {
"message": "Geplant"
},
"LabelReset": {
"message": "Zurücksetzen"
},
"DescriptionReset": {
"message": "Setzen Sie den synchronisierten Ordner zurück um einen neuen generieren zu lassen."
},
"LabelChoosefolder": {
"message": "Ordner wählen"
},
"DescriptionChoosefolder": {
"message": "Setzen Sie einen existierenden Ordner, der synchronisiert werden soll."
},
"LabelRemoveaccount": {
"message": "Profil löschen"
},
"DescriptionRemoveaccount": {
"message": "Löschen Sie dieses Profil (dies entfernt nicht Ihre Lesezeichen)"
},
"LabelSyncfromscratch": {
"message": "Neue Synchronisierung von Grund auf auslösen"
},
"LabelResetCache": {
"message": "Cache zurücksetzen"
},
"DescriptionResetcache": {
"message": "Klicken Sie diesen Button, um den Cache zurückzusetzen, sodass die nächste Synchronisierung garantiert keine Lesezeichen löscht, sondern lediglich Server und Lokale Lesezeichen vereinigt."
},
"LabelParallelsync": {
"message": "Synchronisierung beschleunigen"
},
"DescriptionParallelsync": {
"message": "Setzen Sie diesen Haken um mehrere Ordner parallel abzuarbeiten und so die Synchronisierung zu beschleunigen. Dieses Feature ist experimentell und macht es schwieriger die Debug Logs zu lesen."
},
"LabelStrategy": {
"message": "Synchronisationsstrategie"
},
"DescriptionStrategy": {
"message": "Diese Option bestimmt wie der Lesezeichenbaum auf dem Server mit dem im Browser synchronisiert wird. Normalerweise will man Änderungen von beiden Seiten behalten, sofern sie kompatibel sind, aber manchmal ist es nötig die lokale Version genau so auf den Server zu übertragen, oder anders herum."
},
"LabelStrategydefault": {
"message": "Führe lokale Änderungen immer mit denen von anderen Browsern zusammen (empfohlen)."
},
"LabelStrategyslave": {
"message": "Verwirf lokale Änderungen und lade immer Änderungen von anderen Browsern herunter."
},
"LabelStrategyoverwrite": {
"message": "Lade lokale Änderungen immer hoch und verwirf Änderungen von anderen Browsern."
},
"LabelSave": {
"message": "Speichern"
},
"LabelSelect": {
"message": "Auswählen"
},
"LabelCancel": {
"message": "Abbrechen"
},
"LabelAdd": {
"message": "Hinzufügen"
},
"LabelChange": {
"message": "Ändern"
},
"LabelRemove": {
"message": "Entfernen"
},
"LabelBack": {
"message": "Zurück"
},
"LabelAdapternextcloudfolders": {
"message": "Nextcloud Bookmarks"
},
"DescriptionAdapternextcloudfolders": {
"message": "Synchronisieren Sie Ihre Lesezeichen mit der Open-Source Lesezeichen Applikation für Nextcloud (eine Open-Source Kollaborationsplatform, die Sie selbst hosten können oder für die Sie ein Konto auf einer Instanz in der Cloud bei verschiedenen Hostern bekommen können). Mit Nextcloud Bookmarks können Sie nur HTTP, FTP und JavaScript Lesezeichen synchronisieren. Vergewissern Sie sich, dass sie die Bookmarks Applikation aus dem Nextcloud App Store in Ihrer Nextcloud installiert haben, wenn Sie diese Option nutzen wollen. Diese Option kann keine Ende-zu-Ende-Verschlüsselung nutzen."
},
"LabelAdapternextcloud": {
"message": "Nextcloud Bookmarks (alte Version)"
},
"DescriptionAdapternextcloud": {
"message": "Die Legacy-Option ist kompatibel mit mindestens Version v0.11 der Bookmarks-App. Sie wird Ordner mit Hilfe von Tags emulieren, die den Ordnerpfad enthalten. Es wird nicht empfohlen, dies für neue Profile zu verwenden."
},
"LabelAdapterwebdav": {
"message": "WebDAV-Freigabe"
},
"DescriptionAdapterwedavexamples": {
"message": "z.B.: Koofr, pCloud, IceDrive, kDrive, MagentaCLOUD, Disroot, Mailbox.org, Synology NAS, GMX, WEB.DE"
},
"DescriptionAdapterwebdav": {
"message": "Synchronisieren Sie Ihre Lesezeichen indem Sie sie in einer Datei in einem konfigurierbaren WebDAV-Verzeichnis speichern. Es gibt keine dazugehörige Benutzeroberfläche im Web für diese Option, aber Sie können jeden beliebigen WebDAV-kompatiblen Server benutzen, ob selbst gehostet oder in der Cloud. Diese Option unterstützt HTTP, FTP, DATA, FILE und JavaScript Lesezeichen. Sie haben die Möglichkeit Ende-zu-Ende-Verschlüsselung zu nutzen, wenn sie diese Option wählen."
},
"LabelAddaccount": {
"message": "Profil hinzufügen"
},
"LabelOpenintab": {
"message": "In Tab öffnen"
},
"LabelDebuglogs": {
"message": "Debug-Logs"
},
"LabelFunddevelopment": {
"message": "💸 Unterstütze die Entwicklung finanziell"
},
"DescriptionFunddevelopment": {
"message": "Die Arbeit an floccus wird gefördert durch ein freiwilliges Abo-Modell. Wenn Sie glauben, dass das was ich tue nutzbringend ist, und Sie ohne Not einen kleinen Betrag erübrigen können, freue ich mich wenn Sie meine Arbeit unterstützen. Über eine Bewertung im Addon-Store Ihrer Wall freue ich mich ebenfalls. Vielen Dank. 💙"
},
"LabelUntitledfolder": {
"message": "Unbenannter Ordner"
},
"LabelSetkeybutton": {
"message": "Passphrase einstellen"
},
"LabelKey": {
"message": "Passwort zum entsperren eingeben"
},
"LabelKey2": {
"message": "Passwort ein zweites Mal eingeben"
},
"LabelUnlock": {
"message": "Floccus entsperren"
},
"LabelRemovekey": {
"message": "Passphrase entfernen"
},
"LabelRemovedkey": {
"message": "Passphrase wurde entfernt"
},
"LabelSyncinterval": {
"message": "Synchronisierungsintervall"
},
"DescriptionSyncinterval": {
"message": "Die Zeitspanne zwischen zwei Synchronisierungsläufen. Der Standard-Wert sind 15 Minuten."
},
"LabelChooseadapter": {
"message": "Wie willst du synchronisieren?"
},
"LabelOptionsscreen": {
"message": "{0} Optionen",
"description": "Title of the options screen. The placeholder holds the profile type."
},
"LabelPaypal": {
"message": "Paypal"
},
"DescriptionPaypal": {
"message": "Spende einmalig oder regelmäßig via Paypal, um das Projekt zu unterstützen"
},
"LabelOpencollective": {
"message": "OpenCollective"
},
"DescriptionOpencollective": {
"message": "Tätige regelmäßige Spenden über OpenCollective um das Projekt zu unterstützen."
},
"LabelLiberapay": {
"message": "Liberapay"
},
"DescriptionLiberapay": {
"message": "Tätige regelmäßige Spenden über Liberapay um das Projekt zu unterstützen."
},
"LabelGithubsponsors": {
"message": "GitHub sponsors"
},
"DescriptionGithubsponsors": {
"message": "Tätige regelmäßige Spenden über GitHub sponsors um das Projekt zu unterstützen"
},
"LabelPatreon": {
"message": "Patreon"
},
"DescriptionPatreon": {
"message": "Tätige regelmäßige Spenden über Patreon um das Projekt zu unterstützen."
},
"LabelKofi": {
"message": "Kofi"
},
"DescriptionKofi": {
"message": "Tätige regelmäßige oder einmalige Spenden über Kofi um das Projekt zu unterstützen."
},
"LegacyAdapterDeprecation": {
"message": "Dieser veraltete Profiltyp wird nicht mehr unterstützt und wird bald entfernt. Bitte wechseln Sie zur neuen Nextcloud-Synchronisierungsmethode. Verbesserte Leistung und Genauigkeit erwarten Sie."
},
"LabelUpdated": {
"message": "⚡ Floccus wurde aktualisiert"
},
"DescriptionUpdated": {
"message": "Glückwunsch, das aktuellste Floccus-Update befindet sich auf Ihrem Rechner! 🎉"
},
"LabelReleaseNotes": {
"message": "Release-Notes lesen"
},
"LabelOptionsServerDetails": {
"message": "Serverdetails"
},
"LabelOptionsFolderMapping": {
"message": "Ordnerzuordnung"
},
"LabelOptionsSyncBehavior": {
"message": "Synchronisationsverhalten"
},
"LabelOptionsDangerous": {
"message": "Gefährliche Funktionen"
},
"LabelAccountDeleted": {
"message": "Profil gelöscht"
},
"DescriptionAccountDeleted": {
"message": "Dieses Profil wurde gelöscht."
},
"LabelNoAccount": {
"message": "Es gibt noch keine Profile"
},
"DescriptionNoAccount": {
"message": "Lege neue Profile an oder importiere Profile aus einer Datei. Danach kannst du mit der Synchronisierung beginnen."
},
"LabelLoginFlowStart": {
"message": "Mit Nextcloud anmelden"
},
"LabelLoginFlowStop": {
"message": "Anmeldung bei Nextcloud abbrechen"
},
"LabelLoginFlowError": {
"message": "Anmeldung bei Nextcloud fehlgeschlagen."
},
"LabelNewAccount": {
"message": "Profil hinzufügen"
},
"LabelNewImport": {
"message": "Import"
},
"LabelNestedSync": {
"message": "Verschachtelte Profile"
},
"DescriptionNestedSync": {
"message": "Sie können Profile verschachteln, sodass ein übergeordneter Ordner zu Profil A gehört und ein Unterordner zu Profil A und B. Möchten Sie anderen Profilen erlauben, diesen Ordner des Profils zu synchronisieren?"
},
"LabelNestedSyncNo": {
"message": "Nein, ignoriere den Ordner dieses Profils in anderen Profilen."
},
"LabelNestedSyncYes": {
"message": "Ja, nimm den Ordner dieses Profils bei anderen Profilen hinzu."
},
"LabelImportExport": {
"message": "Profile importieren/exportieren"
},
"LabelExport": {
"message": "Profile exportieren"
},
"LabelImport": {
"message": "Profile importieren"
},
"DescriptionExport": {
"message": "Wählen Sie unten die Profile aus, die Sie in eine Datei exportieren möchten, damit Sie die gleichen Profile problemlos auf einem anderen Gerät oder Browser wiederherstellen können."
},
"DescriptionImport": {
"message
gitextract_bb9v7fk9/ ├── .all-contributorsrc ├── .eslintrc.json ├── .github/ │ ├── FUNDING.yml │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.yml │ │ ├── config.yml │ │ └── feature_request.yml │ ├── dependabot.yml │ └── workflows/ │ ├── build.yml │ ├── codeql-analysis.yml │ ├── dependabot-approve.yml │ ├── issues.yml │ ├── lock-threads.yml │ ├── stale.yml │ └── tests.yml ├── .gitignore ├── .prettierrc ├── CHANGELOG.md ├── CONSIDERATIONS.md ├── LICENSE.txt ├── PRIVACY_POLICY.md ├── README.md ├── _locales/ │ ├── cs/ │ │ └── messages.json │ ├── de/ │ │ └── messages.json │ ├── el/ │ │ └── messages.json │ ├── en/ │ │ └── messages.json │ ├── es/ │ │ └── messages.json │ ├── es_ES/ │ │ └── messages.json │ ├── et/ │ │ └── messages.json │ ├── fi/ │ │ └── messages.json │ ├── fr/ │ │ └── messages.json │ ├── gl/ │ │ └── messages.json │ ├── it/ │ │ └── messages.json │ ├── ja/ │ │ └── messages.json │ ├── ko_KR/ │ │ └── messages.json │ ├── nb/ │ │ └── messages.json │ ├── nl_NL/ │ │ └── messages.json │ ├── pl/ │ │ └── messages.json │ ├── pt/ │ │ └── messages.json │ ├── pt_BR/ │ │ └── messages.json │ ├── pt_PT/ │ │ └── messages.json │ ├── ro_RO/ │ │ └── messages.json │ ├── ru/ │ │ └── messages.json │ ├── sk/ │ │ └── messages.json │ ├── sv/ │ │ └── messages.json │ ├── tr/ │ │ └── messages.json │ ├── tr_TR/ │ │ └── messages.json │ ├── zh/ │ │ └── messages.json │ ├── zh-Hans/ │ │ └── messages.json │ ├── zh_CN/ │ │ └── messages.json │ └── zh_TW/ │ └── messages.json ├── android/ │ ├── .gitignore │ ├── app/ │ │ ├── .gitignore │ │ ├── build.gradle │ │ ├── capacitor.build.gradle │ │ ├── proguard-rules.pro │ │ └── src/ │ │ └── main/ │ │ ├── AndroidManifest.xml │ │ ├── assets/ │ │ │ ├── capacitor.config.json │ │ │ └── capacitor.plugins.json │ │ ├── java/ │ │ │ └── org/ │ │ │ └── handmadeideas/ │ │ │ └── floccus/ │ │ │ └── MainActivity.java │ │ └── res/ │ │ ├── drawable-v26/ │ │ │ ├── ic_launcher_foreground.xml │ │ │ └── notification_icon.xml │ │ ├── layout/ │ │ │ └── activity_main.xml │ │ ├── mipmap-anydpi-v26/ │ │ │ ├── ic_launcher.xml │ │ │ └── ic_launcher_round.xml │ │ ├── values/ │ │ │ ├── ic_launcher_background.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ └── xml/ │ │ ├── config.xml │ │ ├── file_paths.xml │ │ └── network_security_config.xml │ ├── build.gradle │ ├── capacitor.settings.gradle │ ├── gradle/ │ │ └── wrapper/ │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties │ ├── gradle.properties │ ├── gradlew │ ├── gradlew.bat │ ├── settings.gradle │ └── variables.gradle ├── capacitor.config.json ├── doc/ │ └── Adapters.md ├── doiuse-report.baseline.txt ├── dropbox-api.credentials.json ├── fastlane/ │ └── metadata/ │ └── android/ │ └── en-US/ │ ├── full_description.txt │ └── short_description.txt ├── google-api.credentials.json ├── gulpfile.js ├── html/ │ ├── background.html │ ├── index.html │ ├── options.html │ └── test.html ├── img/ │ ├── promotional-tile-medium.xcf │ ├── promotional-tile-medium2.xcf │ └── promotional-tile-small.xcf ├── ios/ │ ├── .gitignore │ └── App/ │ ├── App/ │ │ ├── App.entitlements │ │ ├── AppDelegate.swift │ │ ├── Assets.xcassets/ │ │ │ ├── AppIcon.appiconset/ │ │ │ │ └── Contents.json │ │ │ ├── Contents.json │ │ │ └── Splash.imageset/ │ │ │ └── Contents.json │ │ ├── Base.lproj/ │ │ │ ├── LaunchScreen.storyboard │ │ │ └── Main.storyboard │ │ ├── Info.plist │ │ ├── capacitor.config.json │ │ └── config.xml │ ├── App.xcodeproj/ │ │ ├── project.pbxproj │ │ ├── project.xcworkspace/ │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata/ │ │ │ └── IDEWorkspaceChecks.plist │ │ └── xcshareddata/ │ │ └── xcschemes/ │ │ ├── Floccus New Bookmark.xcscheme │ │ └── Floccus.xcscheme │ ├── App.xcworkspace/ │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata/ │ │ ├── IDEWorkspaceChecks.plist │ │ └── WorkspaceSettings.xcsettings │ ├── Floccus New Bookmark/ │ │ ├── Base.lproj/ │ │ │ └── MainInterface.storyboard │ │ ├── Floccus New Bookmark.entitlements │ │ ├── Info.plist │ │ └── ShareViewController.swift │ ├── Floccus.entitlements │ ├── Podfile │ └── PrivacyInfo.xcprivacy ├── lib/ │ └── gulp-crx.js ├── manifest-firefox-override.sh ├── manifest.chrome.json ├── manifest.firefox.json ├── manifest.json ├── package.json ├── src/ │ ├── build-fixtures/ │ │ └── lazyLoadIntegration.js │ ├── entries/ │ │ ├── background-script.js │ │ ├── native.js │ │ ├── options.js │ │ └── test.js │ ├── errors/ │ │ └── Error.ts │ ├── lib/ │ │ ├── Account.ts │ │ ├── AdapterFactory.ts │ │ ├── CacheTree.ts │ │ ├── CachingTreeWrapper.ts │ │ ├── Controller.ts │ │ ├── Crypto.ts │ │ ├── DefunctCrypto.js │ │ ├── Diff.ts │ │ ├── LocalTabs.ts │ │ ├── Logger.js │ │ ├── Mappings.ts │ │ ├── PathHelper.js │ │ ├── Scanner.ts │ │ ├── Tree.ts │ │ ├── adapters/ │ │ │ ├── Caching.ts │ │ │ ├── Dropbox.ts │ │ │ ├── Fake.js │ │ │ ├── Git.ts │ │ │ ├── GoogleDrive.ts │ │ │ ├── Karakeep.ts │ │ │ ├── Linkwarden.ts │ │ │ ├── NextcloudBookmarks.ts │ │ │ └── WebDav.ts │ │ ├── browser/ │ │ │ ├── BrowserAccount.ts │ │ │ ├── BrowserAccountStorage.js │ │ │ ├── BrowserController.js │ │ │ ├── BrowserDetection.ts │ │ │ └── BrowserTree.ts │ │ ├── browser-api.js │ │ ├── getFavicon.js │ │ ├── interfaces/ │ │ │ ├── Account.ts │ │ │ ├── AccountStorage.ts │ │ │ ├── Adapter.ts │ │ │ ├── Controller.ts │ │ │ ├── Ordering.ts │ │ │ ├── Resource.ts │ │ │ └── Serializer.ts │ │ ├── isTest.ts │ │ ├── murmurhash3.js │ │ ├── native/ │ │ │ ├── I18n.ts │ │ │ ├── NativeAccount.ts │ │ │ ├── NativeAccountStorage.js │ │ │ ├── NativeController.js │ │ │ └── NativeTree.ts │ │ ├── on-wake-up.ts │ │ ├── sentry.ts │ │ ├── serializers/ │ │ │ ├── Html.ts │ │ │ └── Xbel.ts │ │ ├── statusCodes.ts │ │ ├── strategies/ │ │ │ ├── Default.ts │ │ │ ├── Merge.ts │ │ │ └── Unidirectional.ts │ │ └── yieldToEventLoop.ts │ ├── test/ │ │ ├── index.js │ │ ├── reporter.js │ │ └── test.js │ └── ui/ │ ├── App.vue │ ├── NativeApp.vue │ ├── NativeRouter.js │ ├── components/ │ │ ├── AccountCard.vue │ │ ├── NextcloudLogin.vue │ │ ├── OptionAllowRedirects.vue │ │ ├── OptionAutoSync.vue │ │ ├── OptionClientCert.vue │ │ ├── OptionDeleteAccount.vue │ │ ├── OptionDownloadLogs.vue │ │ ├── OptionExportBookmarks.vue │ │ ├── OptionFailsafe.vue │ │ ├── OptionFileType.vue │ │ ├── OptionNestedSync.vue │ │ ├── OptionPassphrase.vue │ │ ├── OptionResetCache.vue │ │ ├── OptionSyncFolder.vue │ │ ├── OptionSyncInterval.vue │ │ ├── OptionSyncIntervalEnabled.vue │ │ ├── OptionSyncStrategy.vue │ │ ├── OptionsDropbox.vue │ │ ├── OptionsFake.vue │ │ ├── OptionsGit.vue │ │ ├── OptionsGoogleDrive.vue │ │ ├── OptionsKarakeep.vue │ │ ├── OptionsLinkwarden.vue │ │ ├── OptionsNextcloudBookmarks.vue │ │ ├── OptionsNextcloudLegacy.vue │ │ ├── OptionsWebdav.vue │ │ └── native/ │ │ ├── Breadcrumbs.vue │ │ ├── DialogChooseFolder.vue │ │ ├── DialogEditBookmark.vue │ │ ├── DialogEditFolder.vue │ │ ├── DialogImportBookmarks.vue │ │ ├── Drawer.vue │ │ ├── FaviconImage.vue │ │ ├── Item.vue │ │ └── OptionAllowNetwork.vue │ ├── index.js │ ├── native-public-path.js │ ├── native.js │ ├── plugins/ │ │ ├── capacitor.js │ │ ├── i18n.js │ │ └── vuetify.js │ ├── router.js │ ├── store/ │ │ ├── actions.js │ │ ├── definitions.js │ │ ├── index.js │ │ ├── mutations.js │ │ └── native/ │ │ ├── actions.js │ │ ├── index.js │ │ └── mutations.js │ └── views/ │ ├── AccountOptions.vue │ ├── Donate.vue │ ├── Feedback.vue │ ├── ImportExport.vue │ ├── NewAccount.vue │ ├── Overview.vue │ ├── Telemetry.vue │ ├── Update.vue │ └── native/ │ ├── About.vue │ ├── AddBookmarkIntent.vue │ ├── Feedback.vue │ ├── Home.vue │ ├── ImportExport.vue │ ├── NewAccount.vue │ ├── Options.vue │ ├── Telemetry.vue │ ├── Tree.vue │ └── Update.vue ├── supportedBrowsers.js ├── test/ │ ├── apache-vhost.conf │ ├── apcu.ini │ ├── save-stats.js │ └── selenium-runner.js ├── transifex.yml ├── tsconfig.json ├── webpack.common.js ├── webpack.dev.js └── webpack.prod.js
SYMBOL INDEX (942 symbols across 65 files)
FILE: android/app/src/main/java/org/handmadeideas/floccus/MainActivity.java
class MainActivity (line 8) | public class MainActivity extends BridgeActivity {
method onNewIntent (line 10) | @Override
method handleIntent (line 16) | private void handleIntent(Intent intent) {
FILE: gulpfile.js
constant VERSION (line 26) | const VERSION = require('./package.json').version
constant WEBSTORE_ID (line 51) | const WEBSTORE_ID = 'fnaicdffflnofjppbagibeoednhnbjhg'
constant WEBSTORE_CREDENTIALS (line 53) | let WEBSTORE_CREDENTIALS
function onWatchEvent (line 295) | function onWatchEvent(path) {
FILE: lib/gulp-crx.js
function transform (line 11) | function transform(file, encoding, done) {
FILE: src/build-fixtures/lazyLoadIntegration.js
function lazyLoadIntegration (line 1) | function lazyLoadIntegration() {
FILE: src/errors/Error.ts
class FloccusError (line 4) | class FloccusError extends Error {
method constructor (line 7) | constructor(message) {
class TransientError (line 14) | class TransientError extends FloccusError {
method constructor (line 15) | constructor(message) {
class UnknownCreateTargetError (line 21) | class UnknownCreateTargetError extends FloccusError {
method constructor (line 23) | constructor() {
class UnknownBookmarkUpdateError (line 29) | class UnknownBookmarkUpdateError extends TransientError {
method constructor (line 31) | constructor() {
class UnknownMoveOriginError (line 37) | class UnknownMoveOriginError extends TransientError {
method constructor (line 39) | constructor() {
class UnknownMoveTargetError (line 45) | class UnknownMoveTargetError extends FloccusError {
method constructor (line 47) | constructor() {
class UnknownFolderParentUpdateError (line 53) | class UnknownFolderParentUpdateError extends TransientError {
method constructor (line 55) | constructor() {
class UnknownFolderUpdateError (line 61) | class UnknownFolderUpdateError extends TransientError {
method constructor (line 63) | constructor() {
class UnknownFolderMoveError (line 69) | class UnknownFolderMoveError extends TransientError {
method constructor (line 71) | constructor() {
class UnknownFolderOrderError (line 80) | class UnknownFolderOrderError extends TransientError {
method constructor (line 82) | constructor() {
class UnknownFolderItemOrderError (line 88) | class UnknownFolderItemOrderError extends FloccusError {
method constructor (line 91) | constructor(item: string) {
class MissingItemOrderError (line 98) | class MissingItemOrderError extends FloccusError {
method constructor (line 101) | constructor(item: string) {
class UnknownFolderRemoveError (line 108) | class UnknownFolderRemoveError extends TransientError {
method constructor (line 110) | constructor() {
class UnknownFolderParentRemoveError (line 116) | class UnknownFolderParentRemoveError extends FloccusError {
method constructor (line 118) | constructor() {
class UnexpectedServerResponseError (line 124) | class UnexpectedServerResponseError extends TransientError {
method constructor (line 126) | constructor() {
class RequestTimeoutError (line 132) | class RequestTimeoutError extends TransientError {
method constructor (line 134) | constructor() {
class NetworkError (line 140) | class NetworkError extends TransientError {
method constructor (line 142) | constructor() {
class AuthenticationError (line 150) | class AuthenticationError extends FloccusError {
method constructor (line 152) | constructor() {
class HttpError (line 158) | class HttpError extends TransientError {
method constructor (line 164) | constructor(status: number, method: string) {
class ParseResponseError (line 175) | class ParseResponseError extends TransientError {
method constructor (line 178) | constructor(response: string) {
class InconsistentServerStateError (line 185) | class InconsistentServerStateError extends TransientError {
method constructor (line 187) | constructor() {
class InconsistentBookmarksExistenceError (line 195) | class InconsistentBookmarksExistenceError extends TransientError {
method constructor (line 199) | constructor(folder: string, bookmark: string) {
class UnclearedLockFileError (line 209) | class UnclearedLockFileError extends FloccusError {
method constructor (line 213) | constructor(lockFile:string) {
class LockFileError (line 220) | class LockFileError extends FloccusError {
method constructor (line 225) | constructor(status:number, lockFile:string) {
class SlashError (line 233) | class SlashError extends FloccusError {
method constructor (line 238) | constructor() {
class CancelledSyncError (line 244) | class CancelledSyncError extends FloccusError {
method constructor (line 246) | constructor() {
class InterruptedSyncError (line 252) | class InterruptedSyncError extends TransientError {
method constructor (line 254) | constructor() {
class ServersideDeletionFailsafeError (line 262) | class ServersideDeletionFailsafeError extends FloccusError {
method constructor (line 266) | constructor(percent:number) {
class DecryptionError (line 273) | class DecryptionError extends FloccusError {
method constructor (line 276) | constructor() {
class GoogleDriveAuthenticationError (line 282) | class GoogleDriveAuthenticationError extends FloccusError {
method constructor (line 284) | constructor() {
class GoogleOAuthTokenError (line 290) | class GoogleOAuthTokenError extends FloccusError {
method constructor (line 292) | constructor() {
class RedirectError (line 298) | class RedirectError extends FloccusError {
method constructor (line 300) | constructor() {
class FileUnreadableError (line 306) | class FileUnreadableError extends FloccusError {
method constructor (line 308) | constructor() {
class CreateBookmarkError (line 314) | class CreateBookmarkError extends FloccusError {
method constructor (line 317) | constructor(bookmark: Bookmark<TItemLocation>) {
class MissingPermissionsError (line 324) | class MissingPermissionsError extends FloccusError {
method constructor (line 326) | constructor() {
class ResourceLockedError (line 332) | class ResourceLockedError extends FloccusError {
method constructor (line 334) | constructor() {
class LocalFolderNotFoundError (line 340) | class LocalFolderNotFoundError extends FloccusError {
method constructor (line 342) | constructor() {
class UpdateBookmarkError (line 348) | class UpdateBookmarkError extends FloccusError {
method constructor (line 351) | constructor(bookmark: Bookmark<TItemLocation>) {
class GoogleDriveSearchError (line 358) | class GoogleDriveSearchError extends FloccusError {
method constructor (line 360) | constructor() {
class FileSizeMismatch (line 366) | class FileSizeMismatch extends TransientError {
method constructor (line 368) | constructor() {
class FileSizeUnknown (line 376) | class FileSizeUnknown extends FloccusError {
method constructor (line 378) | constructor() {
class ServersideAdditionFailsafeError (line 384) | class ServersideAdditionFailsafeError extends FloccusError {
method constructor (line 388) | constructor(percent:number) {
class GitPushError (line 395) | class GitPushError extends FloccusError {
method constructor (line 399) | constructor(errorMessage:string) {
class UnexpectedFolderPathError (line 406) | class UnexpectedFolderPathError extends FloccusError {
method constructor (line 411) | constructor(originalPath: string, newPath: string) {
class InvalidUrlError (line 419) | class InvalidUrlError extends FloccusError {
method constructor (line 423) | constructor(url: string) {
class XbelParseError (line 430) | class XbelParseError extends FloccusError {
method constructor (line 432) | constructor() {
class MappingFailureError (line 438) | class MappingFailureError extends FloccusError {
method constructor (line 442) | constructor(id: string) {
class ClientsideAdditionFailsafeError (line 449) | class ClientsideAdditionFailsafeError extends FloccusError {
method constructor (line 453) | constructor(percent:number) {
class ClientsideDeletionFailsafeError (line 460) | class ClientsideDeletionFailsafeError extends FloccusError {
method constructor (line 464) | constructor(percent:number) {
class DropboxAuthenticationError (line 471) | class DropboxAuthenticationError extends FloccusError {
method constructor (line 473) | constructor() {
class DropboxOAuthTokenError (line 479) | class DropboxOAuthTokenError extends FloccusError {
method constructor (line 481) | constructor() {
class DropboxSearchError (line 487) | class DropboxSearchError extends FloccusError {
method constructor (line 489) | constructor() {
class DropboxTemplateError (line 495) | class DropboxTemplateError extends FloccusError {
method constructor (line 497) | constructor() {
FILE: src/lib/Account.ts
constant LOCK_TIMEOUT (line 38) | const LOCK_TIMEOUT = 1000 * 60 * 60 * 2
class Account (line 42) | class Account {
method getAccountClass (line 46) | static async getAccountClass(): Promise<IAccount> {
method get (line 58) | static async get(id:string):Promise<Account> {
method create (line 68) | static async create(data: IAccountData):Promise<Account> {
method import (line 72) | static async import(accounts:IAccountData[]):Promise<void> {
method export (line 78) | static async export(accountIds:string[]):Promise<IAccountData[]> {
method constructor (line 95) | constructor(id:string, storageAdapter:IAccountStorage, serverAdapter: ...
method delete (line 104) | async delete():Promise<void> {
method getLabel (line 108) | getLabel():string {
method getData (line 112) | getData():IAccountData {
method getResource (line 135) | async getResource():Promise<OrderFolderResource<typeof ItemLocation.LO...
method getServer (line 139) | async getServer():Promise<TAdapter> {
method setData (line 143) | async setData(data:Partial<IAccountData>):Promise<void> {
method updateFromStorage (line 151) | async updateFromStorage():Promise<void> {
method tracksBookmark (line 155) | async tracksBookmark(localId:string):Promise<boolean> {
method init (line 168) | async init():Promise<void> {
method isInitialized (line 172) | async isInitialized():Promise<boolean> {
method sync (line 176) | async sync(strategy?:TAccountStrategy, forceSync = false):Promise<void> {
method stringifyError (line 441) | static async stringifyError(er:any):Promise<string> {
method cancelSync (line 445) | async cancelSync():Promise<void> {
method progressCallback (line 461) | private async progressCallback(progress: number, actionsDone: number) {
method getAllAccounts (line 500) | static async getAllAccounts():Promise<Account[]> {
method getAccountsContainingLocalId (line 504) | static async getAccountsContainingLocalId(localId:string, ancestors:st...
function matchAllErrors (line 509) | function matchAllErrors(e, fn:(e)=>boolean) {
FILE: src/lib/AdapterFactory.ts
method register (line 6) | register(type:string, adapter: any):void {
method factory (line 9) | async factory(data: any): Promise<TAdapter> {
method getDefaultValues (line 15) | async getDefaultValues(type:string):Promise<IAccountData> {
FILE: src/lib/CacheTree.ts
class CacheTree (line 5) | class CacheTree extends CachingAdapter implements IResource<typeof ItemL...
method constructor (line 8) | constructor() {
method setTree (line 12) | public setTree(tree: Folder<typeof ItemLocation.LOCAL>) {
method getBookmarksTree (line 17) | async getBookmarksTree(): Promise<Folder<typeof ItemLocation.LOCAL>> {
method isAvailable (line 23) | isAvailable(): Promise<boolean> {
FILE: src/lib/CachingTreeWrapper.ts
class CachingTreeWrapper (line 6) | class CachingTreeWrapper implements OrderFolderResource<typeof ItemLocat...
method constructor (line 10) | constructor(innerTree: OrderFolderResource<typeof ItemLocation.LOCAL>) {
method getBookmarksTree (line 15) | async getBookmarksTree(): Promise<Folder<typeof ItemLocation.LOCAL>> {
method setCacheTree (line 21) | async setCacheTree(tree: Folder<typeof ItemLocation.LOCAL>) {
method createBookmark (line 25) | async createBookmark(bookmark:Bookmark<typeof ItemLocation.LOCAL>): Pr...
method updateBookmark (line 37) | async updateBookmark(bookmark:Bookmark<typeof ItemLocation.LOCAL>):Pro...
method removeBookmark (line 42) | async removeBookmark(bookmark:Bookmark<typeof ItemLocation.LOCAL>): Pr...
method createFolder (line 47) | async createFolder(folder:Folder<typeof ItemLocation.LOCAL>): Promise<...
method orderFolder (line 59) | async orderFolder(id:string|number, order:Ordering<typeof ItemLocation...
method updateFolder (line 64) | async updateFolder(folder:Folder<typeof ItemLocation.LOCAL>): Promise<...
method removeFolder (line 69) | async removeFolder(folder:Folder<typeof ItemLocation.LOCAL>): Promise<...
method isAvailable (line 74) | isAvailable(): Promise<boolean> {
method isUsingBrowserTabs (line 78) | async isUsingBrowserTabs() {
method getCacheTree (line 82) | getCacheTree(): Promise<Folder<typeof ItemLocation.LOCAL>> {
method getCapabilities (line 86) | getCapabilities(): Promise<ICapabilities> {
method setHashSettings (line 90) | setHashSettings(hashSettings: IHashSettings): void {
method cancel (line 94) | cancel(): void {
method isAtomic (line 98) | isAtomic(): boolean {
FILE: src/lib/Controller.ts
type FloccusWorker (line 5) | interface FloccusWorker {
class Controller (line 10) | class Controller implements IController {
method getSingleton (line 15) | static async getSingleton():Promise<IController> {
method constructor (line 28) | constructor(worker?: FloccusWorker) {
method getWorker (line 32) | async getWorker(): Promise<FloccusWorker> {
method cancelSync (line 74) | async cancelSync(accountId, keepEnabled): Promise<void> {
method onStatusChange (line 82) | onStatusChange(listener): () => void {
method scheduleSync (line 99) | async scheduleSync(accountId, wait): Promise<void> {
method scheduleAll (line 107) | async scheduleAll(): Promise<void> {
method setEnabled (line 115) | async setEnabled(enabled: boolean): Promise<void> {
method syncAccount (line 122) | async syncAccount(accountId, strategy, forceSync = false): Promise<voi...
method unlock (line 141) | async unlock(key): Promise<void> {
method getUnlocked (line 149) | async getUnlocked(): Promise<boolean> {
method onLoad (line 168) | async onLoad() {
FILE: src/lib/Crypto.ts
class Crypto (line 5) | class Crypto {
method xxhash32 (line 9) | static async xxhash32(message: string): Promise<string> {
method murmurHash3 (line 13) | static async murmurHash3(message: string): Promise<string> {
method sha256 (line 20) | static async sha256(message: string): Promise<string> {
method bufferToHexstr (line 27) | static bufferToHexstr(buffer: Uint8Array): string {
method hexstrToBuffer (line 33) | static hexstrToBuffer(hex: string): Uint8Array {
method prepareKey (line 44) | static async prepareKey(passphrase: string, salt: string): Promise<Cry...
method decryptAES (line 66) | static async decryptAES(key: string, payload: string, salt: string) : ...
method encryptAES (line 76) | static async encryptAES(key: string, message: string, salt: string): P...
method concatBytes (line 92) | static concatBytes(array1: Uint8Array, array2: Uint8Array): Uint8Array {
method getRandomBytes (line 99) | static getRandomBytes(bytelength: number) : Uint8Array<ArrayBuffer> {
FILE: src/lib/DefunctCrypto.js
class Crypto (line 1) | class Crypto {
method sha256 (line 2) | static async sha256(message) {
method bufferToHexstr (line 9) | static bufferToHexstr(buffer) {
method hexstrToBuffer (line 15) | static hexstrToBuffer(hex) {
method prepareKey (line 26) | static async prepareKey(key) {
method decryptAES (line 41) | static async decryptAES(key, iv, ciphertext) {
method encryptAES (line 51) | static async encryptAES(key, iv, message) {
method getRandomBytes (line 61) | static getRandomBytes(bytelength) {
FILE: src/lib/Diff.ts
type TActionType (line 18) | type TActionType = (typeof ActionType)[keyof typeof ActionType];
type CreateAction (line 20) | interface CreateAction<L1 extends TItemLocation, L2 extends TItemLocatio...
type UpdateAction (line 28) | interface UpdateAction<L1 extends TItemLocation, L2 extends TItemLocatio...
type RemoveAction (line 34) | interface RemoveAction<L1 extends TItemLocation, L2 extends TItemLocatio...
type ReorderAction (line 42) | interface ReorderAction<L1 extends TItemLocation, L2 extends TItemLocati...
type MoveAction (line 50) | interface MoveAction<L1 extends TItemLocation, L2 extends TItemLocation> {
type Action (line 58) | type Action<L1 extends TItemLocation, L2 extends TItemLocation> = Create...
type LocationOfAction (line 60) | type LocationOfAction<A> = A extends Action<infer L, TItemLocation> ? L ...
type OldLocationOfAction (line 61) | type OldLocationOfAction<A> = A extends Action<TItemLocation, infer L> ?...
type MapLocation (line 63) | type MapLocation<A extends Action<TItemLocation, TItemLocation>, NewLoca...
class Diff (line 81) | class Diff<
method constructor (line 88) | constructor() {
method clone (line 92) | clone(filter: (action: A) => boolean = () => true): Diff<L1, L2, A> {
method commit (line 103) | commit(action: A): void {
method retract (line 107) | retract(action: A): void {
method getActions (line 111) | getActions(): A[] {
method containsParent (line 115) | static containsParent(
method findChain (line 160) | static findChain(
method sortMoves (line 237) | static sortMoves<L1 extends TItemLocation, L2 extends TItemLocation>(
method map (line 290) | map<L3 extends TItemLocation>(
method toJSON (line 405) | toJSON() {
method toJSONAsync (line 415) | async toJSONAsync() {
method inspect (line 431) | inspect(depth = 0): string {
method fromJSON (line 452) | static fromJSON<
method fromJSONAsync (line 466) | static async fromJSONAsync<
type PlanStage1 (line 482) | interface PlanStage1<L1 extends TItemLocation, L2 extends TItemLocation> {
type PlanStage2 (line 490) | interface PlanStage2<L1 extends TItemLocation, L2 extends TItemLocation,...
type PlanStage3 (line 498) | interface PlanStage3<L1 extends TItemLocation, L2 extends TItemLocation,...
type PlanRevert (line 506) | interface PlanRevert<L1 extends TItemLocation, L2 extends TItemLocation> {
FILE: src/lib/LocalTabs.ts
class LocalTabs (line 9) | class LocalTabs implements OrderFolderResource<typeof ItemLocation.LOCAL> {
method constructor (line 13) | constructor(storage:unknown) {
method getWindowIdFromFolderId (line 18) | private getWindowIdFromFolderId(folderId:string|number):number {
method getTabGroupIdFromFolderId (line 22) | private getTabGroupIdFromFolderId(folderId:string|number):number {
method getFolderIdFromWindowId (line 26) | private getFolderIdFromWindowId(windowId:number):string {
method getFolderIdFromTabGroupId (line 30) | private getFolderIdFromTabGroupId(tabGroupId:number):string {
method getBookmarksTree (line 34) | async getBookmarksTree():Promise<Folder<typeof ItemLocation.LOCAL>> {
method createBookmark (line 138) | async createBookmark(bookmark:Bookmark<typeof ItemLocation.LOCAL>): Pr...
method updateBookmark (line 207) | async updateBookmark(bookmark:Bookmark<typeof ItemLocation.LOCAL>):Pro...
method removeBookmark (line 276) | async removeBookmark(bookmark:Bookmark<typeof ItemLocation.LOCAL>): Pr...
method createFolder (line 287) | async createFolder(folder:Folder<typeof ItemLocation.LOCAL>): Promise<...
method orderFolder (line 345) | async orderFolder(id:string|number, order:Ordering<typeof ItemLocation...
method updateFolder (line 442) | async updateFolder(folder:Folder<typeof ItemLocation.LOCAL>):Promise<v...
method removeFolder (line 465) | async removeFolder(folder:Folder<typeof ItemLocation.LOCAL>):Promise<v...
method isAvailable (line 506) | async isAvailable(): Promise<boolean> {
method isUsingBrowserTabs (line 513) | async isUsingBrowserTabs() {
method getCapabilities (line 517) | async getCapabilities(): Promise<ICapabilities> {
method setHashSettings (line 525) | setHashSettings(hashSettings: IHashSettings): void {
method cancel (line 529) | cancel(): void {
method isAtomic (line 533) | isAtomic(): boolean {
function awaitTabsUpdated (line 538) | function awaitTabsUpdated() {
FILE: src/lib/Logger.js
class Logger (line 11) | class Logger {
method log (line 12) | static log() {
method trimLogs (line 22) | static trimLogs() {
method persist (line 26) | static async persist() {
method intermittentPersist (line 41) | static async intermittentPersist() {
method getLogs (line 54) | static async getLogs() {
method anonymizeLogs (line 61) | static async anonymizeLogs(logs) {
method replaceAsync (line 86) | static async replaceAsync(str, regex, asyncFn) {
method downloadLogs (line 102) | static async downloadLogs(anonymous = false) {
method download (line 123) | static async download(filename, blob) {
FILE: src/lib/Mappings.ts
type InternalItemTypeMapping (line 3) | type InternalItemTypeMapping = { LocalToServer: Record<string, string>, ...
type Mapping (line 5) | type Mapping = Record<TItemType,Record<string,number|string>>
type MappingSnapshot (line 7) | type MappingSnapshot = {
class Mappings (line 12) | class Mappings {
method constructor (line 17) | constructor(storageAdapter:any, mappingsData:any) {
method getSnapshot (line 23) | getSnapshot():MappingSnapshot {
method gc (line 36) | async gc(tree: Folder<typeof ItemLocation.LOCAL>) {
method addFolder (line 50) | async addFolder({ localId, remoteId }: { localId?:string|number, remot...
method removeFolder (line 54) | async removeFolder({ localId, remoteId }: { localId?:string|number, re...
method addBookmark (line 58) | async addBookmark({ localId, remoteId }: { localId?:string|number, rem...
method removeBookmark (line 62) | async removeBookmark({ localId, remoteId }: { localId?:string|number, ...
method persist (line 66) | async persist():Promise<void> {
method add (line 73) | private static add(mappings, { localId, remoteId }: { localId?:string|...
method remove (line 81) | private static remove(mappings, { localId, remoteId }: { localId?:stri...
method mapRawId (line 98) | static mapRawId(mappingsSnapshot:MappingSnapshot, id: string|number, t...
method mapId (line 105) | static mapId(mappingsSnapshot:MappingSnapshot, item: TItem<TItemLocati...
method mapParentId (line 112) | static mapParentId(mappingsSnapshot:MappingSnapshot, item: TItem<TItem...
method mappable (line 119) | static mappable(mappingsSnapshot: MappingSnapshot, item1: TItem<TItemL...
FILE: src/lib/PathHelper.js
class PathHelper (line 1) | class PathHelper {
method reverseStr (line 2) | static reverseStr(str) {
method pathToArray (line 9) | static pathToArray(path) {
method arrayToPath (line 18) | static arrayToPath(array) {
FILE: src/lib/Scanner.ts
type ScanResult (line 8) | interface ScanResult<L1 extends TItemLocation, L2 extends TItemLocation> {
class Scanner (line 16) | class Scanner<L1 extends TItemLocation, L2 extends TItemLocation> {
method constructor (line 26) | constructor(oldTree:TItem<L1>, newTree:TItem<L2>, mergeable:(i1:TItem<...
method getDiffs (line 42) | getDiffs(): ScanResult<L2, L1> {
method run (line 46) | async run():Promise<ScanResult<L2, L1>> {
method diffItem (line 53) | async diffItem(oldItem:TItem<L1>, newItem:TItem<L2>):Promise<void> {
method diffFolder (line 63) | async diffFolder(oldFolder:Folder<L1>, newFolder:Folder<L2>):Promise<v...
method diffBookmark (line 127) | async diffBookmark(oldBookmark:Bookmark<L1>, newBookmark:Bookmark<L2>)...
method bookmarkHasChanged (line 139) | async bookmarkHasChanged(oldBookmark:Bookmark<L1>, newBookmark:Bookmar...
method folderHasChanged (line 145) | async folderHasChanged(oldFolder:Folder<L1>, newFolder:Folder<L2>):Pro...
method findMoves (line 151) | async findMoves():Promise<void> {
method addReorders (line 292) | async addReorders(): Promise<void> {
FILE: src/lib/Tree.ts
constant STRANGE_PROTOCOLS (line 7) | const STRANGE_PROTOCOLS = ['data:', 'javascript:', 'about:', 'chrome:', ...
type TItemLocation (line 14) | type TItemLocation = (typeof ItemLocation)[keyof typeof ItemLocation];
type TOppositeLocation (line 16) | type TOppositeLocation<L extends TItemLocation> = L extends typeof ItemL...
type TItemType (line 23) | type TItemType = (typeof ItemType)[keyof typeof ItemType];
type IItemIndex (line 25) | interface IItemIndex<L extends TItemLocation> {
class Bookmark (line 32) | class Bookmark<L extends TItemLocation> {
method constructor (line 44) | constructor({
method canMergeWith (line 89) | canMergeWith<L2 extends TItemLocation>(otherItem: TItem<L2>): boolean {
method childrenSimilarity (line 96) | childrenSimilarity<L2 extends TItemLocation>(otherItem: TItem<L2>): nu...
method setHashCacheValue (line 100) | setHashCacheValue(hashSettings: IHashSettings, value: string): void {
method hash (line 106) | async hash(
method clone (line 130) | clone(withHash?: boolean): Bookmark<L> {
method cloneWithLocation (line 138) | cloneWithLocation<L2 extends TItemLocation>(
method copy (line 147) | copy(withHash?: boolean): Bookmark<L> {
method copyWithLocation (line 153) | copyWithLocation<L2 extends TItemLocation>(
method toJSON (line 165) | toJSON() {
method toJSONAsync (line 182) | async toJSONAsync(): Promise<any> {
method createIndex (line 200) | createIndex(): IItemIndex<L> {
method findItem (line 206) | findItem(type: TItemType, id: string | number): TItem<L> | null {
method findItemFilter (line 214) | findItemFilter(
method count (line 225) | count(): number {
method countFolders (line 229) | countFolders(): number {
method inspect (line 233) | inspect(depth = 0): string {
method visitCreate (line 242) | visitCreate(resource: TResource<L>): Promise<number | string> {
method visitUpdate (line 246) | visitUpdate(resource: TResource<L>): Promise<void> {
method visitRemove (line 250) | visitRemove(resource: TResource<L>): Promise<void> {
method hydrate (line 254) | static hydrate<L2 extends TItemLocation>(obj: any): Bookmark<L2> {
class Folder (line 259) | class Folder<L extends TItemLocation> {
method constructor (line 271) | constructor({
method findItemFilter (line 311) | findItemFilter(
method findFolder (line 324) | findFolder(id: string | number): Folder<L> {
method findBookmark (line 341) | findBookmark(id: string | number): Bookmark<L> {
method findItem (line 361) | findItem(type: TItemType, id: string | number): TItem<L> | null {
method traverse (line 369) | async traverse(
method canMergeWith (line 387) | canMergeWith<L2 extends TItemLocation>(otherItem: TItem<L2>): boolean {
method childrenSimilarity (line 394) | childrenSimilarity<L2 extends TItemLocation>(otherItem: TItem<L2>): nu...
method setHashCacheValue (line 404) | setHashCacheValue(hashSettings: IHashSettings, value: string): void {
method hash (line 410) | async hash(
method copy (line 461) | copy(withHash?: boolean): Folder<L> {
method copyWithLocation (line 471) | copyWithLocation<L2 extends TItemLocation>(
method clone (line 487) | clone(withHash?: boolean): Folder<L> {
method cloneWithLocation (line 497) | cloneWithLocation<L2 extends TItemLocation>(
method toJSON (line 513) | toJSON(): Folder<L> {
method toJSONAsync (line 533) | async toJSONAsync(): Promise<Folder<L>> {
method count (line 554) | count(): number {
method countFolders (line 561) | countFolders(): number {
method createIndex (line 568) | createIndex(): IItemIndex<L> {
method updateIndex (line 590) | updateIndex(item: TItem<L>) {
method removeFromIndex (line 600) | removeFromIndex(item: TItem<L>) {
method inspect (line 605) | inspect(depth = 0): string {
method visitCreate (line 621) | visitCreate(resource: TResource<L>): Promise<number | string> {
method visitUpdate (line 625) | visitUpdate(resource: TResource<L>): Promise<void> {
method visitRemove (line 629) | visitRemove(resource: TResource<L>): Promise<void> {
method hydrate (line 633) | static hydrate<L2 extends TItemLocation>(obj: {
method getAncestorsOf (line 656) | static getAncestorsOf<L2 extends TItemLocation>(
type TItem (line 674) | type TItem<L extends TItemLocation> = Bookmark<L> | Folder<L>
function hydrate (line 676) | function hydrate<L extends TItemLocation>(obj: any) {
FILE: src/lib/adapters/Caching.ts
class CachingAdapter (line 17) | class CachingAdapter implements Adapter, BulkImportResource<TItemLocatio...
method constructor (line 24) | constructor(server: any) {
method resetCache (line 28) | resetCache() {
method getLabel (line 33) | getLabel():string {
method getBookmarksTree (line 38) | async getBookmarksTree(): Promise<Folder<TItemLocation>> {
method acceptsBookmark (line 42) | acceptsBookmark(bm:Bookmark<TItemLocation>):boolean {
method createBookmark (line 74) | async createBookmark(bm:Bookmark<TItemLocation>):Promise<string|number> {
method updateBookmark (line 87) | async updateBookmark(newBm: Bookmark<TItemLocation>): Promise<void> {
method removeBookmark (line 119) | async removeBookmark(bookmark:Bookmark<TItemLocation>): Promise<void> {
method createFolder (line 139) | async createFolder(folder:Folder<TItemLocation>): Promise<string|numbe...
method updateFolder (line 151) | async updateFolder(folder:Folder<TItemLocation>): Promise<void> {
method orderFolder (line 178) | async orderFolder(id:string|number, order:Ordering<TItemLocation>):Pro...
method removeFolder (line 209) | async removeFolder(folder:Folder<TItemLocation>):Promise<void> {
method bulkImportFolder (line 225) | async bulkImportFolder(id:string|number, folder:Folder<TItemLocation>)...
method setData (line 246) | setData(data:any):void {
method getData (line 250) | getData():any {
method onSyncStart (line 255) | async onSyncStart(needLock = true):Promise<void|boolean> { }
method onSyncFail (line 258) | async onSyncFail():Promise<void> { }
method onSyncComplete (line 261) | async onSyncComplete():Promise<void> { }
method cancel (line 263) | cancel() {
method isAvailable (line 267) | isAvailable(): Promise<boolean> {
method isAtomic (line 271) | isAtomic(): boolean {
method getCapabilities (line 275) | async getCapabilities(): Promise<ICapabilities> {
method setHashSettings (line 282) | setHashSettings(hashSettings: IHashSettings): void {
FILE: src/lib/adapters/Dropbox.ts
type CustomResponse (line 64) | interface CustomResponse {
constant LOCK_INTERVAL (line 72) | const LOCK_INTERVAL = 2 * 60 * 1000 // Lock every two minutes while syncing
constant LOCK_TIMEOUT (line 73) | const LOCK_TIMEOUT = 15 * 60 * 1000 // Override lock 15min after last ti...
constant HTTP_TIMEOUT (line 74) | const HTTP_TIMEOUT = 60000
class DropboxAdapter (line 75) | class DropboxAdapter extends CachingAdapter {
method constructor (line 86) | constructor(server) {
method authorize (line 91) | static async authorize(interactive = true) {
method getAccessToken (line 219) | async getAccessToken(refreshToken:string) {
method getLabel (line 248) | getLabel():string {
method getDefaultValues (line 252) | static getDefaultValues() {
method getUrl (line 263) | getUrl() :string {
method getContentUrl (line 267) | getContentUrl() :string {
method timeout (line 271) | timeout(ms) {
method getBookmarksTree (line 278) | async getBookmarksTree(): Promise<Folder<TItemLocation>> {
method onSyncStart (line 291) | async onSyncStart(needLock = true, forceLock = false) {
method onSyncFail (line 420) | async onSyncFail() {
method getXBELContent (line 434) | async getXBELContent() {
method onSyncComplete (line 448) | async onSyncComplete() {
method cancel (line 471) | cancel() {
method request (line 484) | async request(method: string, url: string, body: any = null, contentTy...
method requestWeb (line 488) | async requestWeb(method: string, url: string, body: any = null, conten...
method requestNative (line 530) | async requestNative(method: string, url: string, body: any = null, con...
method listFiles (line 593) | async listFiles(query: string, limit = 1) : Promise<any> {
method getFileMetadata (line 623) | async getFileMetadata(id: string): Promise<any> {
method downloadFile (line 665) | async downloadFile(path: string): Promise<string> {
method deleteFile (line 735) | async deleteFile(id: string): Promise<any> {
method setupTemplate (line 752) | async setupTemplate() {
method addTemplate (line 781) | async addTemplate(): Promise<any> {
method getTemplates (line 810) | async getTemplates(): Promise<string[]> {
method getTemplate (line 842) | async getTemplate(templateId:string): Promise<any> {
method getTemplateId (line 877) | async getTemplateId(): Promise<string> {
method freeLock (line 925) | async freeLock(id:string) {
method setLock (line 968) | async setLock(id:string) {
method createFile (line 998) | async createFile(xbel: string, path:string) {
method uploadFile (line 1032) | async uploadFile(id:string, xbel: string) {
function createXBEL (line 1060) | function createXBEL(rootFolder, highestId) {
FILE: src/lib/adapters/Fake.js
class FakeAdapter (line 3) | class FakeAdapter extends CachingAdapter {
method constructor (line 4) | constructor(server) {
method getDefaultValues (line 9) | static getDefaultValues() {
method setData (line 15) | setData(data) {
method getData (line 19) | getData() {
method getLabel (line 23) | getLabel() {
FILE: src/lib/adapters/Git.ts
constant LOCK_INTERVAL (line 22) | const LOCK_INTERVAL = 2 * 60 * 1000 // Lock every 2mins while syncing
constant LOCK_TIMEOUT (line 23) | const LOCK_TIMEOUT = 15 * 60 * 1000 // Override lock 0.25h after last ti...
class GitAdapter (line 24) | class GitAdapter extends CachingAdapter {
method constructor (line 34) | constructor(server) {
method getDefaultValues (line 41) | static getDefaultValues() {
method getLabel (line 56) | getLabel():string {
method getData (line 63) | getData() {
method cancel (line 67) | cancel() {
method getBookmarksTree (line 71) | async getBookmarksTree(): Promise<Folder<TItemLocation>> {
method onSyncStart (line 78) | async onSyncStart(needLock = true, forceLock = false) {
method onSyncFail (line 190) | async onSyncFail() {
method onSyncComplete (line 197) | async onSyncComplete() {
method cleanupIndexedDB (line 246) | async cleanupIndexedDB() {
method obtainLock (line 289) | async obtainLock() {
method setLock (line 302) | async setLock() {
method onAuth (line 317) | async onAuth() {
method freeLock (line 321) | async freeLock() {
method clearAllLocks (line 344) | async clearAllLocks(fs:FS = null): Promise<void> {
method pullFromServer (line 354) | async pullFromServer() {
method clearServer (line 397) | async clearServer() {
function createXBEL (line 455) | function createXBEL(rootFolder, highestId) {
function createHTML (line 475) | function createHTML(rootFolder, highestId) {
FILE: src/lib/adapters/GoogleDrive.ts
type CustomResponse (line 37) | interface CustomResponse {
constant LOCK_INTERVAL (line 45) | const LOCK_INTERVAL = 2 * 60 * 1000 // Lock every two minutes while syncing
constant LOCK_TIMEOUT (line 46) | const LOCK_TIMEOUT = 15 * 60 * 1000 // Override lock 15min after last ti...
constant HTTP_TIMEOUT (line 47) | const HTTP_TIMEOUT = 60000
class GoogleDriveAdapter (line 48) | class GoogleDriveAdapter extends CachingAdapter {
method constructor (line 60) | constructor(server) {
method authorize (line 65) | static async authorize(interactive = true) {
method getAccessToken (line 145) | async getAccessToken(refreshToken:string) {
method getLabel (line 169) | getLabel():string {
method getDefaultValues (line 173) | static getDefaultValues() {
method getUrl (line 184) | getUrl() :string {
method timeout (line 188) | timeout(ms) {
method getBookmarksTree (line 195) | async getBookmarksTree(): Promise<Folder<TItemLocation>> {
method onSyncStart (line 202) | async onSyncStart(needLock = true, forceLock = false) {
method onSyncFail (line 314) | async onSyncFail() {
method getXBELContent (line 325) | async getXBELContent() {
method onSyncComplete (line 336) | async onSyncComplete() {
method cancel (line 359) | cancel() {
method request (line 363) | async request(method: string, url: string, body: any = null, contentTy...
method requestWeb (line 367) | async requestWeb(method: string, url: string, body: any = null, conten...
method requestNative (line 400) | async requestNative(method: string, url: string, body: any = null, con...
method listFiles (line 454) | async listFiles(query: string, limit = 1) : Promise<any> {
method getFileMetadata (line 463) | async getFileMetadata(id: string, fields?:string): Promise<any> {
method downloadFile (line 472) | async downloadFile(id: string): Promise<string> {
method deleteFile (line 482) | async deleteFile(id: string): Promise<void> {
method freeLock (line 486) | async freeLock(id:string) {
method setLock (line 509) | async setLock(id:string) {
method createFile (line 522) | async createFile(xbel: string) {
method uploadFile (line 537) | async uploadFile(id:string, xbel: string) {
function createXBEL (line 547) | function createXBEL(rootFolder, highestId) {
FILE: src/lib/adapters/Karakeep.ts
type KarakeepConfig (line 19) | interface KarakeepConfig {
constant TIMEOUT (line 30) | const TIMEOUT = 300000
class KarakeepAdapter (line 32) | class KarakeepAdapter implements Adapter, IResource<typeof ItemLocation....
method constructor (line 39) | constructor(server: KarakeepConfig) {
method getDefaultValues (line 46) | static getDefaultValues(): KarakeepConfig {
method parseBookmarkId (line 58) | parseBookmarkId(id: string | number): [string, string] {
method acceptsBookmark (line 66) | acceptsBookmark(bm: Bookmark<typeof ItemLocation.SERVER>): boolean {
method cancel (line 74) | cancel(): void {
method setData (line 79) | setData(data: KarakeepConfig): void {
method getData (line 83) | getData(): KarakeepConfig {
method getLabel (line 87) | getLabel(): string {
method onSyncComplete (line 92) | onSyncComplete(): Promise<void> {
method onSyncFail (line 96) | onSyncFail(): Promise<void> {
method onSyncStart (line 100) | async onSyncStart(
method createBookmark (line 121) | async createBookmark(bookmark: {
method updateBookmark (line 158) | async updateBookmark(bookmark: {
method removeBookmark (line 197) | async removeBookmark(bookmark: {
method createFolder (line 227) | async createFolder(folder: {
method updateFolder (line 247) | async updateFolder(folder: {
method removeFolder (line 267) | async removeFolder(folder: { id: string | number }): Promise<void> {
method getBookmarksTree (line 322) | async getBookmarksTree(
method getListsOfBookmark (line 413) | async getListsOfBookmark(bookmarkId: string | number): Promise<Set<str...
method isAvailable (line 422) | async isAvailable(): Promise<boolean> {
method sendRequest (line 426) | async sendRequest(
method sendRequestNative (line 510) | private async sendRequestNative(
method getCapabilities (line 571) | async getCapabilities(): Promise<ICapabilities> {
method isAtomic (line 578) | isAtomic(): boolean {
method setHashSettings (line 583) | setHashSettings(hashSettings: IHashSettings): void {
FILE: src/lib/adapters/Linkwarden.ts
type LinkwardenConfig (line 17) | interface LinkwardenConfig {
constant TIMEOUT (line 29) | const TIMEOUT = 300000
class LinkwardenAdapter (line 31) | class LinkwardenAdapter implements Adapter, IResource<typeof ItemLocatio...
method constructor (line 38) | constructor(server: LinkwardenConfig) {
method getDefaultValues (line 45) | static getDefaultValues(): LinkwardenConfig {
method acceptsBookmark (line 58) | acceptsBookmark(bm: Bookmark<typeof ItemLocation.SERVER>):boolean {
method cancel (line 66) | cancel(): void {
method setData (line 71) | setData(data:LinkwardenConfig):void {
method getData (line 75) | getData(): LinkwardenConfig {
method getLabel (line 79) | getLabel(): string {
method onSyncComplete (line 84) | onSyncComplete(): Promise<void> {
method onSyncFail (line 88) | onSyncFail(): Promise<void> {
method onSyncStart (line 92) | async onSyncStart(needLock?: boolean, forceLock?: boolean): Promise<vo...
method createBookmark (line 110) | async createBookmark(bookmark: Bookmark<typeof ItemLocation.SERVER>): ...
method updateBookmark (line 125) | async updateBookmark(bookmark: Bookmark<typeof ItemLocation.SERVER>): ...
method removeBookmark (line 144) | async removeBookmark(bookmark: Bookmark<typeof ItemLocation.SERVER>): ...
method createFolder (line 149) | async createFolder(folder: Folder<typeof ItemLocation.SERVER>): Promis...
method updateFolder (line 161) | async updateFolder(folder: Folder<typeof ItemLocation.SERVER>): Promis...
method removeFolder (line 174) | async removeFolder(folder: Folder<typeof ItemLocation.SERVER>): Promis...
method getBookmarksTree (line 194) | async getBookmarksTree(loadAll?: boolean): Promise<Folder<typeof ItemL...
method isAvailable (line 240) | async isAvailable(): Promise<boolean> {
method sendRequest (line 244) | async sendRequest(verb:string, relUrl:string, type:string = null, body...
method sendRequestNative (line 320) | private async sendRequestNative(verb: string, url: string, type: strin...
method getCapabilities (line 373) | async getCapabilities(): Promise<ICapabilities> {
method isAtomic (line 380) | isAtomic(): boolean {
method setHashSettings (line 385) | setHashSettings(hashSettings: IHashSettings): void {
FILE: src/lib/adapters/NextcloudBookmarks.ts
constant PAGE_SIZE (line 36) | const PAGE_SIZE = 300
constant TIMEOUT (line 37) | const TIMEOUT = 300000
type NextcloudBookmarksConfig (line 39) | interface NextcloudBookmarksConfig {
type IChildFolder (line 51) | interface IChildFolder {
type IChildOrderItem (line 58) | interface IChildOrderItem {
constant LOCK_INTERVAL (line 64) | const LOCK_INTERVAL = 2 * 60 * 1000 // Set lock every two minutes while ...
class NextcloudBookmarksAdapter (line 66) | class NextcloudBookmarksAdapter implements Adapter, BulkImportResource<t...
method constructor (line 85) | constructor(server: NextcloudBookmarksConfig) {
method getDefaultValues (line 92) | static getDefaultValues(): NextcloudBookmarksConfig {
method setData (line 105) | setData(data:NextcloudBookmarksConfig):void {
method getData (line 111) | getData():NextcloudBookmarksConfig {
method getLabel (line 115) | getLabel():string {
method acceptsBookmark (line 120) | acceptsBookmark(bm: Bookmark<typeof ItemLocation.SERVER>):boolean {
method normalizeServerURL (line 128) | normalizeServerURL(input:string):string {
method onSyncStart (line 144) | async onSyncStart(needLock = true, forceLock = false): Promise<void> {
method onSyncComplete (line 185) | async onSyncComplete(): Promise<void> {
method onSyncFail (line 191) | async onSyncFail(): Promise<void> {
method cancel (line 197) | cancel() {
method getBookmarksList (line 203) | async getBookmarksList():Promise<Bookmark<typeof ItemLocation.SERVER>[...
method getBookmarksTree (line 249) | async getBookmarksTree(loadAll = false):Promise<Folder<typeof ItemLoca...
method _getChildFolders (line 259) | async _getChildFolders(folderId:string|number, layers = 0):Promise<ICh...
method _findServerRoot (line 270) | async _findServerRoot():Promise<Folder<typeof ItemLocation.SERVER>> {
method getCompleteBookmarksTree (line 304) | async getCompleteBookmarksTree():Promise<Folder<typeof ItemLocation.SE...
method getSparseBookmarksTree (line 315) | async getSparseBookmarksTree() :Promise<Folder<typeof ItemLocation.SER...
method _getFolderHash (line 330) | async _getFolderHash(folderId:string|number):Promise<string> {
method _getChildren (line 347) | async _getChildren(folderId:string|number, layers:number):Promise<TIte...
method loadFolderChildren (line 382) | async loadFolderChildren(folderId:string|number, all?: boolean): Promi...
method createFolder (line 416) | async createFolder(folder:Folder<typeof ItemLocation.SERVER>):Promise<...
method bulkImportFolder (line 450) | async bulkImportFolder(parentId:string|number, folder:Folder<typeof It...
method updateFolder (line 513) | async updateFolder(folder:Folder<typeof ItemLocation.SERVER>):Promise<...
method orderFolder (line 551) | async orderFolder(id:string|number, order:Ordering<typeof ItemLocation...
method removeFolder (line 567) | async removeFolder(folder:Folder<typeof ItemLocation.SERVER>):Promise<...
method _getBookmark (line 587) | async _getBookmark(id:string|number):Promise<Bookmark<typeof ItemLocat...
method getExistingBookmark (line 614) | async getExistingBookmark(url:string):Promise<false|Bookmark<typeof It...
method createBookmark (line 649) | async createBookmark(bm:Bookmark<typeof ItemLocation.SERVER>):Promise<...
method updateBookmark (line 708) | async updateBookmark(newBm:Bookmark<typeof ItemLocation.SERVER>):Promi...
method removeBookmark (line 773) | async removeBookmark(bookmark:Bookmark<typeof ItemLocation.SERVER>):Pr...
method getNextcloudCapabilities (line 797) | async getNextcloudCapabilities(): Promise<any> {
method checkFeatureJavascriptLinks (line 805) | async checkFeatureJavascriptLinks(): Promise<void> {
method sendOCSRequest (line 832) | async sendOCSRequest(verb: string, relUrl: string, type: string = null...
method sendRequest (line 854) | async sendRequest(verb:string, relUrl:string, type:string = null, orig...
method acquireLock (line 955) | private async acquireLock():Promise<boolean> {
method releaseLock (line 977) | private async releaseLock():Promise<boolean> {
method sendRequestNative (line 995) | private async sendRequestNative(verb: string, url: string, type: strin...
method isAvailable (line 1070) | isAvailable(): Promise<boolean> {
method getCapabilities (line 1074) | async getCapabilities(): Promise<ICapabilities> {
method countClick (line 1089) | async countClick(url: string): Promise<void> {
method isAtomic (line 1104) | isAtomic(): boolean {
method setHashSettings (line 1108) | setHashSettings(hashSettings: IHashSettings): void {
FILE: src/lib/adapters/WebDav.ts
constant LOCK_INTERVAL (line 21) | const LOCK_INTERVAL = 2 * 60 * 1000 // Lock every 2mins while syncing
constant LOCK_TIMEOUT (line 22) | const LOCK_TIMEOUT = 15 * 60 * 1000 // Override lock 0.25h after last ti...
class WebDavAdapter (line 23) | class WebDavAdapter extends CachingAdapter {
method constructor (line 32) | constructor(server) {
method getDefaultValues (line 40) | static getDefaultValues() {
method getData (line 55) | getData() {
method normalizeServerURL (line 59) | normalizeServerURL(input) {
method cancel (line 73) | cancel() {
method getBookmarkURL (line 78) | getBookmarkURL() {
method getBookmarkLockURL (line 82) | getBookmarkLockURL() {
method checkLock (line 86) | async checkLock() {
method timeout (line 94) | timeout(ms) {
method obtainLock (line 101) | async obtainLock() {
method setLock (line 128) | async setLock() {
method freeLock (line 148) | async freeLock() {
method pullFromServer (line 206) | async pullFromServer() {
method getBookmarksTree (line 295) | async getBookmarksTree(): Promise<Folder<TItemLocation>> {
method onSyncStart (line 302) | async onSyncStart(needLock = true, forceLock = false) {
method onSyncFail (line 359) | async onSyncFail() {
method onSyncComplete (line 366) | async onSyncComplete() {
method uploadFile (line 389) | async uploadFile(url, content_type, data) {
method uploadFileWeb (line 397) | async uploadFileWeb(url, content_type, data) {
method uploadFileNative (line 431) | async uploadFileNative(url, content_type, data) {
method downloadFile (line 465) | async downloadFile(url) {
method getFileSize (line 473) | async getFileSize(url) {
method getFileSizeWeb (line 481) | async getFileSizeWeb(url): Promise<number|null> {
method getFileSizeNative (line 519) | async getFileSizeNative(url): Promise<number|null> {
method downloadFileWeb (line 561) | async downloadFileWeb(url) {
method downloadFileNative (line 596) | async downloadFileNative(fullURL) {
function createXBEL (line 636) | function createXBEL(rootFolder, highestId) {
function createHTML (line 656) | function createHTML(rootFolder, highestId) {
FILE: src/lib/browser-api.js
function ChromePromise (line 8) | function ChromePromise(chrome, Promise) {
FILE: src/lib/browser/BrowserAccount.ts
class BrowserAccount (line 20) | class BrowserAccount extends Account {
method get (line 21) | static async get(id:string):Promise<Account> {
method create (line 30) | static async create(data):Promise<Account> {
method init (line 42) | async init():Promise<void> {
method isInitialized (line 62) | async isInitialized():Promise<boolean> {
method getResource (line 76) | async getResource():Promise<OrderFolderResource<typeof ItemLocation.LO...
method updateFromStorage (line 86) | async updateFromStorage():Promise<void> {
method stringifyError (line 92) | static async stringifyError(er:any):Promise<string> {
method getAllAccounts (line 155) | static async getAllAccounts():Promise<Account[]> {
method getAccountsContainingLocalId (line 163) | static async getAccountsContainingLocalId(localId:string, ancestors:st...
FILE: src/lib/browser/BrowserAccountStorage.js
class BrowserAccountStorage (line 11) | class BrowserAccountStorage {
method constructor (line 12) | constructor(id) {
method setEntry (line 16) | static async setEntry(entryName, value) {
method changeEntry (line 22) | static async changeEntry(entryName, fn, defaultVal) {
method getEntry (line 31) | static async getEntry(entryName, defaultVal) {
method deleteEntry (line 51) | static deleteEntry(entryName) {
method getAllAccounts (line 55) | static async getAllAccounts() {
method getAccountData (line 60) | async getAccountData(key) {
method setAccountData (line 89) | async setAccountData(data, key) {
method deleteAccountData (line 121) | async deleteAccountData() {
method initCache (line 130) | async initCache() {
method getCache (line 137) | async getCache() {
method setCache (line 146) | async setCache(data) {
method deleteCache (line 153) | async deleteCache() {
method initMappings (line 159) | async initMappings() {
method getMappings (line 166) | async getMappings() {
method setMappings (line 187) | async setMappings(data) {
method deleteMappings (line 194) | async deleteMappings() {
method getCurrentContinuation (line 200) | async getCurrentContinuation() {
method setCurrentContinuation (line 206) | async setCurrentContinuation(continuation) {
FILE: src/lib/browser/BrowserController.js
constant INACTIVITY_TIMEOUT (line 14) | const INACTIVITY_TIMEOUT = 7 * 1000 // 7 seconds
constant MAX_BACKOFF_INTERVAL (line 15) | const MAX_BACKOFF_INTERVAL = 1000 * 60 * 60 // 1 hour
constant DEFAULT_SYNC_INTERVAL (line 16) | const DEFAULT_SYNC_INTERVAL = 15 // 15 minutes
constant STALE_SYNC_TIME (line 17) | const STALE_SYNC_TIME = 1000 * 60 * 60 * 24 * 2 // two days
constant INTERVENTION_INTERVAL (line 18) | const INTERVENTION_INTERVAL = 1000 * 60 * 60 * 24 * 182 // 182 days
class AlarmManager (line 20) | class AlarmManager {
method constructor (line 21) | constructor(ctl) {
method checkStorage (line 25) | async checkStorage() {
method checkSync (line 29) | async checkSync() {
method getBackoffInterval (line 72) | getBackoffInterval(interval, errorCount, lastSync) {
class BrowserController (line 82) | class BrowserController {
method constructor (line 83) | constructor() {
method _receiveEvent (line 251) | async _receiveEvent(data, sendResponse) {
method setEnabled (line 260) | setEnabled(enabled) {
method unlock (line 270) | async unlock(key) {
method getUnlocked (line 301) | getUnlocked() {
method onchange (line 305) | async onchange(localId, details) {
method onTabsChanged (line 357) | async onTabsChanged() {
method scheduleSync (line 385) | async scheduleSync(accountId, wait) {
method scheduleAll (line 416) | async scheduleAll() {
method cancelSync (line 424) | async cancelSync(accountId, keepEnabled) {
method syncAccount (line 433) | async syncAccount(accountId, strategy, forceSync = false) {
method updateStatus (line 453) | async updateStatus() {
method onStatusChange (line 458) | onStatusChange(listener) {
method getStatus (line 468) | async getStatus() {
method updateBadge (line 497) | async updateBadge() {
method setStatusBadge (line 501) | async setStatusBadge(status) {
method onStartup (line 518) | async onStartup() {
method onLoad (line 535) | async onLoad() {
method onVisitUrl (line 555) | async onVisitUrl(historyItem) {
FILE: src/lib/browser/BrowserTree.ts
class BrowserTree (line 16) | class BrowserTree implements IResource<typeof ItemLocation.LOCAL> {
method constructor (line 30) | constructor(storage:unknown, rootId:string) {
method getBookmarksTree (line 39) | async getBookmarksTree():Promise<Folder<typeof ItemLocation.LOCAL>> {
method createBookmark (line 148) | async createBookmark(bookmark:Bookmark<typeof ItemLocation.LOCAL>): Pr...
method updateBookmark (line 179) | async updateBookmark(bookmark:Bookmark<typeof ItemLocation.LOCAL>):Pro...
method removeBookmark (line 208) | async removeBookmark(bookmark:Bookmark<typeof ItemLocation.LOCAL>): Pr...
method createFolder (line 225) | async createFolder(folder:Folder<typeof ItemLocation.LOCAL>): Promise<...
method orderFolder (line 246) | async orderFolder(id:string|number, order:Ordering<typeof ItemLocation...
method updateFolder (line 283) | async updateFolder(folder:Folder<typeof ItemLocation.LOCAL>):Promise<v...
method removeFolder (line 318) | async removeFolder(folder:Folder<typeof ItemLocation.LOCAL>):Promise<v...
method getPathFromLocalId (line 339) | static async getPathFromLocalId(localId:string, ancestors?:string[], r...
method getIdPathFromLocalId (line 368) | static async getIdPathFromLocalId(localId:string|null, path:string[] =...
method getAbsoluteRootFolder (line 381) | static async getAbsoluteRootFolder() {
method isAvailable (line 397) | isAvailable(): Promise<boolean> {
method getCapabilities (line 401) | async getCapabilities(): Promise<ICapabilities> {
method setHashSettings (line 409) | setHashSettings(hashSettings: IHashSettings): void {
method cancel (line 413) | cancel(): void {
method isAtomic (line 417) | isAtomic(): boolean {
method getHostname (line 421) | private getHostname(url: string): string {
FILE: src/lib/getFavicon.js
function getIcons (line 1) | function getIcons(html, pageUrl) {
FILE: src/lib/interfaces/Account.ts
type IAccount (line 4) | interface IAccount {
FILE: src/lib/interfaces/AccountStorage.ts
type TAccountStrategy (line 5) | type TAccountStrategy = 'default' | 'overwrite' | 'slave'
type IAccountData (line 7) | interface IAccountData {
type IAccountStorage (line 24) | interface IAccountStorage {
FILE: src/lib/interfaces/Adapter.ts
type IAdapter (line 5) | interface IAdapter {
type TAdapter (line 15) | type TAdapter = IAdapter & TResource<typeof ItemLocation.SERVER>
FILE: src/lib/interfaces/Controller.ts
type IController (line 1) | interface IController {
constant STATUS_ERROR (line 13) | const STATUS_ERROR = Symbol('error')
constant STATUS_SYNCING (line 14) | const STATUS_SYNCING = Symbol('syncing')
constant STATUS_ALLGOOD (line 15) | const STATUS_ALLGOOD = Symbol('allgood')
constant STATUS_DISABLED (line 16) | const STATUS_DISABLED = Symbol('disabled')
FILE: src/lib/interfaces/Ordering.ts
type OrderingItem (line 3) | interface OrderingItem<L extends TItemLocation> {
type Ordering (line 8) | type Ordering<L extends TItemLocation> = OrderingItem<L>[]
FILE: src/lib/interfaces/Resource.ts
type THashFunction (line 4) | type THashFunction = 'sha256' | 'murmur3' | 'xxhash3'
type ICapabilities (line 6) | interface ICapabilities {
type IHashSettings (line 11) | interface IHashSettings {
type IResource (line 16) | interface IResource<L extends TItemLocation> {
type CachingResource (line 33) | interface CachingResource <L extends TItemLocation> extends IResource<L> {
type BulkImportResource (line 38) | interface BulkImportResource<L extends TItemLocation> extends IResource<...
type LoadFolderChildrenResource (line 42) | interface LoadFolderChildrenResource<L extends TItemLocation> extends IR...
type OrderFolderResource (line 46) | interface OrderFolderResource<L extends TItemLocation> extends IResource...
type ClickCountResource (line 50) | interface ClickCountResource<L extends TItemLocation> extends IResource<...
type TLocalTree (line 54) | type TLocalTree = IResource<typeof ItemLocation.LOCAL> & OrderFolderReso...
type TResource (line 56) | type TResource<L extends TItemLocation> = IResource<L>|BulkImportResourc...
FILE: src/lib/interfaces/Serializer.ts
type Serializer (line 3) | interface Serializer {
FILE: src/lib/murmurhash3.js
function murmurhash3_32_gc (line 14) | function murmurhash3_32_gc(key, seed) {
FILE: src/lib/native/I18n.ts
type TranslationEntry (line 14) | interface TranslationEntry {
type Messages (line 17) | interface Messages {
class I18n (line 21) | class I18n {
method constructor (line 26) | constructor(locale: string) {
method setLocales (line 32) | setLocales(locales:string[]):void {
method load (line 36) | async load():Promise<void> {
method getMessage (line 64) | public getMessage(messageName: string, content?: any, formats?: any): ...
method getDefaultLocaleMessage (line 82) | private getDefaultLocaleMessage(messageName: string): TranslationEntry...
method doGetMessage (line 93) | private doGetMessage(messageName: string): TranslationEntry | null {
FILE: src/lib/native/NativeAccount.ts
class NativeAccount (line 19) | class NativeAccount extends Account {
method get (line 20) | static async get(id:string):Promise<Account> {
method create (line 32) | static async create(data: IAccountData):Promise<Account> {
method init (line 47) | async init():Promise<void> {
method isInitialized (line 56) | async isInitialized():Promise<boolean> {
method updateFromStorage (line 65) | async updateFromStorage():Promise<void> {
method stringifyError (line 69) | static async stringifyError(er:any):Promise<string> {
method getAllAccounts (line 129) | static async getAllAccounts():Promise<Account[]> {
FILE: src/lib/native/NativeAccountStorage.js
class NativeAccountStorage (line 11) | class NativeAccountStorage {
method constructor (line 12) | constructor(id) {
method changeEntry (line 16) | static async changeEntry(entryName, fn, defaultVal) {
method getEntry (line 25) | static async getEntry(entryName, defaultVal) {
method deleteEntry (line 43) | static deleteEntry(entryName) {
method getAllAccounts (line 47) | static async getAllAccounts() {
method getAccountData (line 52) | async getAccountData(key) {
method setAccountData (line 69) | async setAccountData(data, key) {
method deleteAccountData (line 91) | async deleteAccountData() {
method initCache (line 100) | async initCache() {
method getCache (line 107) | async getCache() {
method setCache (line 114) | async setCache(data) {
method deleteCache (line 121) | async deleteCache() {
method initMappings (line 125) | async initMappings() {
method getMappings (line 132) | async getMappings() {
method setMappings (line 153) | async setMappings(data) {
method deleteMappings (line 160) | async deleteMappings() {
method getCurrentContinuation (line 164) | async getCurrentContinuation() {
method setCurrentContinuation (line 168) | async setCurrentContinuation(continuation) {
FILE: src/lib/native/NativeController.js
constant INACTIVITY_TIMEOUT (line 11) | const INACTIVITY_TIMEOUT = 1000 * 7
constant MAX_BACKOFF_INTERVAL (line 12) | const MAX_BACKOFF_INTERVAL = 1000 * 60 * 60 // 1 hour
constant DEFAULT_SYNC_INTERVAL (line 13) | const DEFAULT_SYNC_INTERVAL = 15
class AlarmManager (line 15) | class AlarmManager {
method constructor (line 16) | constructor(ctl) {
method checkStorage (line 31) | async checkStorage() {
method checkSync (line 35) | async checkSync() {
method getBackoffInterval (line 81) | getBackoffInterval(interval, errorCount, lastSync) {
class NativeController (line 91) | class NativeController {
method constructor (line 92) | constructor() {
method setEnabled (line 119) | setEnabled(enabled) {
method unlock (line 123) | async unlock(key) {
method getUnlocked (line 142) | getUnlocked() {
method scheduleAll (line 146) | async scheduleAll() {
method scheduleSync (line 153) | async scheduleSync(accountId, wait) {
method cancelSync (line 184) | async cancelSync(accountId, keepEnabled) {
method syncAccount (line 193) | async syncAccount(accountId, strategy, forceSync = false) {
method updateStatus (line 248) | async updateStatus() {
method getStatus (line 252) | async getStatus() {
method onStatusChange (line 277) | onStatusChange(listener) {
method onLoad (line 287) | async onLoad() {
FILE: src/lib/native/NativeTree.ts
class NativeTree (line 8) | class NativeTree extends CachingAdapter implements BulkImportResource<ty...
method constructor (line 15) | constructor(storage:IAccountStorage) {
method load (line 21) | async load():Promise<boolean> {
method save (line 36) | async save():Promise<void> {
method triggerSave (line 41) | triggerSave():void {
method getBookmarksTree (line 48) | async getBookmarksTree(): Promise<Folder<typeof ItemLocation.LOCAL>> {
method createBookmark (line 54) | async createBookmark(bookmark:Bookmark<typeof ItemLocation.LOCAL>): Pr...
method updateBookmark (line 59) | async updateBookmark(bookmark:Bookmark<typeof ItemLocation.LOCAL>):Pro...
method removeBookmark (line 64) | async removeBookmark(bookmark:Bookmark<typeof ItemLocation.LOCAL>): Pr...
method createFolder (line 69) | async createFolder(folder:Folder<typeof ItemLocation.LOCAL>): Promise<...
method orderFolder (line 74) | async orderFolder(id:string|number, order:Ordering<typeof ItemLocation...
method updateFolder (line 79) | async updateFolder(folder:Folder<typeof ItemLocation.LOCAL>):Promise<v...
method removeFolder (line 84) | async removeFolder(folder:Folder<typeof ItemLocation.LOCAL>):Promise<v...
method bulkImportFolder (line 89) | async bulkImportFolder(id: number|string, folder:Folder<typeof ItemLoc...
method isAvailable (line 103) | isAvailable(): Promise<boolean> {
FILE: src/lib/on-wake-up.ts
constant CLOCK (line 1) | const CLOCK = 1000
constant TIMEOUT (line 2) | const TIMEOUT = 2 * 60 * 1000 // 2 mins
function onWakeUp (line 4) | function onWakeUp(fn: () => void) {
FILE: src/lib/sentry.ts
function initEmpty (line 9) | function initEmpty() {
function initSharp (line 19) | function initSharp() {
FILE: src/lib/serializers/Html.ts
class HtmlSerializer (line 5) | class HtmlSerializer implements Serializer {
method serialize (line 6) | serialize(folder) {
method _htmlentities_encode (line 10) | _htmlentities_encode(string) {
method _serializeFolder (line 14) | _serializeFolder(folder, indent) {
method deserialize (line 35) | deserialize(html): Folder<typeof ItemLocation.SERVER> {
FILE: src/lib/serializers/Xbel.ts
class XbelSerializer (line 7) | class XbelSerializer implements Serializer {
method serialize (line 8) | serialize(folder: Folder<typeof ItemLocation.SERVER>) {
method deserialize (line 14) | deserialize(xbel: string) {
method _parseFolder (line 43) | _parseFolder(xbelObj, folder: Folder<typeof ItemLocation.SERVER>) {
method _serializeFolder (line 73) | _serializeFolder(folder: Folder<typeof ItemLocation.SERVER>) {
FILE: src/lib/strategies/Default.ts
constant ACTION_CONCURRENCY (line 38) | const ACTION_CONCURRENCY = 5
class SyncProcess (line 40) | class SyncProcess {
method constructor (line 90) | constructor(
method getMembersToPersist (line 108) | getMembersToPersist() {
method getMappingsInstance (line 153) | getMappingsInstance(): Mappings {
method setCacheTree (line 157) | setCacheTree(cacheTree: Folder<typeof ItemLocation.LOCAL>) {
method getCacheTree (line 161) | getCacheTree(): Folder<typeof ItemLocation.LOCAL> {
method getTargetTree (line 165) | public getTargetTree<L1 extends TItemLocation>(targetLocation: L1): Fo...
method cancel (line 169) | async cancel() :Promise<void> {
method updateProgress (line 177) | async updateProgress():Promise<void> {
method setProgress (line 197) | async setProgress(json: any) {
method setDirection (line 227) | setDirection(direction:TItemLocation):void {
method sync (line 231) | async sync(): Promise<void> {
method prepareSync (line 447) | protected async prepareSync() {
method applyDeletionFailsafe (line 516) | protected applyDeletionFailsafe(direction: TItemLocation, tree: Folder...
method applyAdditionFailsafe (line 539) | protected applyAdditionFailsafe(direction: TItemLocation, tree: Folder...
method filterOutUnacceptedBookmarks (line 558) | filterOutUnacceptedBookmarks(tree: Folder<TItemLocation>): void {
method filterOutInvalidBookmarks (line 569) | filterOutInvalidBookmarks(tree: Folder<TItemLocation>): void {
method filterOutDuplicatesInTheSameFolder (line 600) | async filterOutDuplicatesInTheSameFolder(tree: Folder<TItemLocation>):...
method getDiffs (line 622) | async getDiffs():Promise<{localScanResult:ScanResult<typeof ItemLocati...
method reconcileDiffs (line 698) | async reconcileDiffs<L1 extends TItemLocation, L2 extends TItemLocatio...
method executeStage2 (line 969) | async executeStage2<L1 extends TItemLocation>(
method executeStage3 (line 1001) | async executeStage3<L1 extends TItemLocation>(
method executeCreate (line 1027) | async executeCreate<L1 extends TItemLocation>(
method executeRemove (line 1235) | async executeRemove<L1 extends TItemLocation>(
method executeUpdate (line 1259) | async executeUpdate<L1 extends TItemLocation>(
method reconcileReorderings (line 1288) | reconcileReorderings<L1 extends TItemLocation, L2 extends TItemLocation>(
method executeReorderings (line 1384) | async executeReorderings(resource:OrderFolderResource<TItemLocation>, ...
method addMapping (line 1430) | async addMapping(resource:TResource<TItemLocation>, item:TItem<TItemLo...
method removeMapping (line 1447) | async removeMapping(resource:TResource<TItemLocation>, item:TItem<TIte...
method loadChildren (line 1465) | async loadChildren(
method folderHasChanged (line 1507) | async folderHasChanged(localItem: TItem<typeof ItemLocation.LOCAL>, ca...
method filterOutUnmappedItems (line 1530) | filterOutUnmappedItems(tree: Folder<TItemLocation>, mapping: MappingSn...
method removeItemFromReorders (line 1545) | static removeItemFromReorders(
method toJSONAsync (line 1556) | async toJSONAsync(): Promise<ISerializedSyncProcess> {
method fromJSON (line 1625) | static async fromJSON(mappings:Mappings,
type ISerializedSyncProcess (line 1663) | interface ISerializedSyncProcess {
FILE: src/lib/strategies/Merge.ts
class MergeSyncProcess (line 12) | class MergeSyncProcess extends DefaultSyncProcess {
method getDiffs (line 13) | async getDiffs(): Promise<{
method reconcileDiffs (line 67) | async reconcileDiffs<
method loadChildren (line 357) | async loadChildren(
method toJSONAsync (line 366) | async toJSONAsync(): Promise<ISerializedSyncProcess> {
FILE: src/lib/strategies/Unidirectional.ts
class UnidirectionalSyncProcess (line 12) | class UnidirectionalSyncProcess extends DefaultStrategy {
method setDirection (line 29) | setDirection(direction: TItemLocation): void {
method getMembersToPersist (line 33) | getMembersToPersist() {
method setProgress (line 53) | async setProgress(json: any) {
method getDiff (line 86) | async getDiff(): Promise<ScanResult<TItemLocation, TItemLocation>> {
method loadChildren (line 147) | async loadChildren(
method sync (line 156) | async sync(): Promise<void> {
method revertDiff (line 290) | async revertDiff<L1 extends TItemLocation, L2 extends TItemLocation>(
method translateCompleteItem (line 370) | private async translateCompleteItem<
method executeRevert (line 402) | async executeRevert<L1 extends TItemLocation>(
method toJSONAsync (line 514) | async toJSONAsync(): Promise<ISerializedSyncProcess> {
FILE: src/lib/yieldToEventLoop.ts
function yieldToEventLoop (line 1) | async function yieldToEventLoop() {
FILE: src/test/reporter.js
function createWebdriverAndHtmlReporter (line 10) | function createWebdriverAndHtmlReporter(html_reporter) {
function stringifyException (line 61) | function stringifyException(exception) {
FILE: src/test/test.js
function hasNoBookmarks (line 8901) | function hasNoBookmarks(child) {
function getAllBookmarks (line 8906) | async function getAllBookmarks(account) {
function withSyncConnection (line 8914) | async function withSyncConnection(account, fn) {
function randomlyManipulateTree (line 8923) | async function randomlyManipulateTree(account, folders, bookmarks, itera...
function randomlyManipulateTreeWithDeletions (line 8982) | async function randomlyManipulateTreeWithDeletions(account, folders, boo...
function syncAccountWithInterrupts (line 9060) | async function syncAccountWithInterrupts(account) {
function stringifyAccountData (line 9075) | function stringifyAccountData(ACCOUNT_DATA) {
function awaitTabsUpdated (line 9089) | function awaitTabsUpdated() {
function filterBookmarksInTree (line 9101) | function filterBookmarksInTree(tree, fn) {
FILE: src/ui/plugins/capacitor.js
method isBrowser (line 8) | isBrowser() {
method mounted (line 12) | mounted() {
FILE: src/ui/plugins/i18n.js
method t (line 5) | t(messageName, substitutions) {
FILE: src/ui/store/actions.js
method [actions.LOAD_LOCKED] (line 11) | async [actions.LOAD_LOCKED]({ commit, dispatch, state }) {
method [actions.UNLOCK] (line 16) | async [actions.UNLOCK]({commit, dispatch, state}, key) {
method [actions.LOAD_ACCOUNTS] (line 26) | async [actions.LOAD_ACCOUNTS]({ commit, dispatch, state }) {
method [actions.CREATE_ACCOUNT] (line 43) | async [actions.CREATE_ACCOUNT]({commit, dispatch, state}, data) {
method [actions.IMPORT_ACCOUNTS] (line 48) | async [actions.IMPORT_ACCOUNTS]({commit, dispatch, state}, accounts) {
method [actions.EXPORT_ACCOUNTS] (line 52) | async [actions.EXPORT_ACCOUNTS]({commit, dispatch, state}, accountIds) {
method [actions.DELETE_ACCOUNT] (line 60) | async [actions.DELETE_ACCOUNT]({commit, dispatch, state}, id) {
method [actions.RESET_ACCOUNT] (line 65) | async [actions.RESET_ACCOUNT]({commit, dispatch, state}, id) {
method [actions.STORE_ACCOUNT] (line 70) | async [actions.STORE_ACCOUNT]({ commit, dispatch, state }, { id,data }) {
method [actions.TRIGGER_SYNC] (line 88) | async [actions.TRIGGER_SYNC]({ commit, dispatch, state }, accountId) {
method [actions.FORCE_SYNC] (line 92) | async [actions.FORCE_SYNC]({ commit, dispatch, state }, accountId) {
method [actions.TRIGGER_SYNC_ALL] (line 96) | async [actions.TRIGGER_SYNC_ALL]({ commit, dispatch, state }, accountId) {
method [actions.TRIGGER_SYNC_DOWN] (line 100) | async [actions.TRIGGER_SYNC_DOWN]({ commit, dispatch, state }, accountId) {
method [actions.TRIGGER_SYNC_UP] (line 104) | async [actions.TRIGGER_SYNC_UP]({ commit, dispatch, state }, accountId) {
method [actions.CANCEL_SYNC] (line 108) | async [actions.CANCEL_SYNC]({ commit, dispatch, state }, accountId) {
method [actions.DOWNLOAD_LOGS] (line 112) | async [actions.DOWNLOAD_LOGS]({ commit, dispatch, state }, anonymous) {
method [actions.TEST_WEBDAV_SERVER] (line 115) | async [actions.TEST_WEBDAV_SERVER]({commit, dispatch, state}, {rootUrl, ...
method [actions.TEST_NEXTCLOUD_SERVER] (line 133) | async [actions.TEST_NEXTCLOUD_SERVER]({commit, dispatch, state}, rootUrl) {
method [actions.TEST_LINKWARDEN_SERVER] (line 141) | async [actions.TEST_LINKWARDEN_SERVER]({commit, dispatch, state}, {rootU...
method [actions.TEST_KARAKEEP_SERVER] (line 156) | async [actions.TEST_KARAKEEP_SERVER]({commit, dispatch, state}, {rootUrl...
method [actions.START_LOGIN_FLOW] (line 171) | async [actions.START_LOGIN_FLOW]({commit, dispatch, state}, rootUrl) {
method [actions.STOP_LOGIN_FLOW] (line 208) | async [actions.STOP_LOGIN_FLOW]({commit}) {
method [actions.REQUEST_NETWORK_PERMISSIONS] (line 211) | async [actions.REQUEST_NETWORK_PERMISSIONS]() {
method [actions.REQUEST_HISTORY_PERMISSIONS] (line 218) | async [actions.REQUEST_HISTORY_PERMISSIONS]() {
FILE: src/ui/store/mutations.js
method [mutations.SET_LOCKED] (line 5) | [mutations.SET_LOCKED](state, locked) {
method [mutations.LOAD_ACCOUNTS] (line 8) | [mutations.LOAD_ACCOUNTS](state, accounts) {
method [mutations.STORE_ACCOUNT_DATA] (line 11) | [mutations.STORE_ACCOUNT_DATA](state, {id, data}) {
method [mutations.REMOVE_ACCOUNT] (line 14) | [mutations.REMOVE_ACCOUNT](state, id) {
method [mutations.SET_LOGIN_FLOW_STATE] (line 17) | [mutations.SET_LOGIN_FLOW_STATE](state, running) {
method [mutations.LOADING_START] (line 20) | [mutations.LOADING_START](state, label) {
method [mutations.LOADING_END] (line 23) | [mutations.LOADING_END](state, label) {
FILE: src/ui/store/native/actions.js
method [actions.LOAD_ACCOUNTS] (line 15) | async [actions.LOAD_ACCOUNTS]({ commit, dispatch, state }) {
method [actions.LOAD_TREE] (line 39) | async [actions.LOAD_TREE]({ commit, dispatch, state }, id) {
method [actions.LOAD_TREE_FROM_DISK] (line 46) | async [actions.LOAD_TREE_FROM_DISK]({ commit, dispatch, state }, id) {
method [actions.CREATE_BOOKMARK] (line 59) | async [actions.CREATE_BOOKMARK]({commit}, {accountId, bookmark}) {
method [actions.EDIT_BOOKMARK] (line 68) | async [actions.EDIT_BOOKMARK]({commit}, {accountId, bookmark}) {
method [actions.COUNT_BOOKMARK_CLICK] (line 75) | async [actions.COUNT_BOOKMARK_CLICK]({state}, {accountId, bookmark}) {
method [actions.DELETE_BOOKMARK] (line 86) | async [actions.DELETE_BOOKMARK]({commit}, {accountId, bookmark}) {
method [actions.SHARE_BOOKMARK] (line 95) | async [actions.SHARE_BOOKMARK]({commit}, bookmark) {
method [actions.CREATE_FOLDER] (line 101) | async [actions.CREATE_FOLDER]({commit}, {accountId, folder}) {
method [actions.EDIT_FOLDER] (line 110) | async [actions.EDIT_FOLDER]({commit}, {accountId, folder}) {
method [actions.DELETE_FOLDER] (line 119) | async [actions.DELETE_FOLDER]({commit}, {accountId, folder}) {
method [actions.IMPORT_BOOKMARKS] (line 128) | async [actions.IMPORT_BOOKMARKS]({ commit }, {accountId, parentFolder, h...
method [actions.CREATE_ACCOUNT] (line 145) | async [actions.CREATE_ACCOUNT]({commit, dispatch, state}, data) {
method [actions.IMPORT_ACCOUNTS] (line 151) | async [actions.IMPORT_ACCOUNTS]({commit, dispatch, state}, accounts) {
method [actions.EXPORT_ACCOUNTS] (line 164) | async [actions.EXPORT_ACCOUNTS]({commit, dispatch, state}, accountIds) {
method [actions.DELETE_ACCOUNT] (line 172) | async [actions.DELETE_ACCOUNT]({commit, dispatch, state}, id) {
method [actions.RESET_ACCOUNT] (line 177) | async [actions.RESET_ACCOUNT]({commit, dispatch, state}, id) {
method [actions.STORE_ACCOUNT] (line 182) | async [actions.STORE_ACCOUNT]({ commit, dispatch, state }, { id,data }) {
method [actions.TRIGGER_SYNC] (line 197) | async [actions.TRIGGER_SYNC]({ commit, dispatch, state }, accountId) {
method [actions.FORCE_SYNC] (line 201) | async [actions.FORCE_SYNC]({ commit, dispatch, state }, accountId) {
method [actions.TRIGGER_SYNC_DOWN] (line 205) | async [actions.TRIGGER_SYNC_DOWN]({ commit, dispatch, state }, accountId) {
method [actions.TRIGGER_SYNC_UP] (line 209) | async [actions.TRIGGER_SYNC_UP]({ commit, dispatch, state }, accountId) {
method [actions.CANCEL_SYNC] (line 213) | async [actions.CANCEL_SYNC]({ commit, dispatch, state }, accountId) {
method [actions.DOWNLOAD_LOGS] (line 217) | async [actions.DOWNLOAD_LOGS]({ commit, dispatch, state }, anonymous) {
method [actions.EXPORT_BOOKMARKS] (line 220) | async [actions.EXPORT_BOOKMARKS]({commit, dispatch, state}, accountId) {
method [actions.TEST_WEBDAV_SERVER] (line 230) | async [actions.TEST_WEBDAV_SERVER]({commit, dispatch, state}, {rootUrl, ...
method [actions.TEST_LINKWARDEN_SERVER] (line 234) | async [actions.TEST_LINKWARDEN_SERVER]({commit, dispatch, state}, {rootU...
method [actions.TEST_KARAKEEP_SERVER] (line 248) | async [actions.TEST_KARAKEEP_SERVER]({commit, dispatch, state}, {rootUrl...
method [actions.TEST_NEXTCLOUD_SERVER] (line 262) | async [actions.TEST_NEXTCLOUD_SERVER]({commit, dispatch, state}, rootUrl) {
method [actions.START_LOGIN_FLOW] (line 273) | async [actions.START_LOGIN_FLOW]({commit, dispatch, state}, rootUrl) {
method [actions.STOP_LOGIN_FLOW] (line 309) | async [actions.STOP_LOGIN_FLOW]({commit}) {
method [actions.SET_SORTBY] (line 312) | async [actions.SET_SORTBY]({state}, {accountId, sortBy}) {
method [actions.SET_LAST_FOLDER] (line 316) | async [actions.SET_LAST_FOLDER]({commit}, {accountId, folderId}) {
method [actions.SET_LAST_ACCOUNT] (line 323) | async [actions.SET_LAST_ACCOUNT]({commit}, accountId) {
FILE: src/ui/store/native/mutations.js
method [mutations.SET_LOCKED] (line 5) | [mutations.SET_LOCKED](state, locked) {
method [mutations.LOAD_ACCOUNTS] (line 8) | [mutations.LOAD_ACCOUNTS](state, accounts) {
method [mutations.STORE_ACCOUNT_DATA] (line 11) | [mutations.STORE_ACCOUNT_DATA](state, {id, data}) {
method [mutations.REMOVE_ACCOUNT] (line 14) | [mutations.REMOVE_ACCOUNT](state, id) {
method [mutations.LOAD_TREE] (line 17) | [mutations.LOAD_TREE](state, tree) {
method [mutations.SET_LOGIN_FLOW_STATE] (line 20) | [mutations.SET_LOGIN_FLOW_STATE](state, running) {
method [mutations.LOADING_START] (line 23) | [mutations.LOADING_START](state, label) {
method [mutations.LOADING_END] (line 26) | [mutations.LOADING_END](state, label) {
method [mutations.SET_LAST_FOLDER] (line 29) | [mutations.SET_LAST_FOLDER](state, {accountId, folderId}) {
method [mutations.SET_LAST_ACCOUNT] (line 32) | [mutations.SET_LAST_ACCOUNT](state, accountId) {
FILE: test/save-stats.js
constant GIST_ID (line 4) | const GIST_ID = '51b4015641802f4f275574ca98beed61'
function save (line 6) | async function save(sha, label, data) {
FILE: test/selenium-runner.js
constant VERSION (line 13) | const VERSION = require('../package.json').version
Condensed preview — 268 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (2,428K chars).
[
{
"path": ".all-contributorsrc",
"chars": 6553,
"preview": "{\n \"projectName\": \"floccus\",\n \"projectOwner\": \"floccusaddon\",\n \"repoType\": \"github\",\n \"repoHost\": \"https://github.co"
},
{
"path": ".eslintrc.json",
"chars": 7430,
"preview": "{\n \"env\": {\n \"browser\": true,\n \"commonjs\": true,\n \"es6\": true,\n \"node\": true,\n \"mocha\": true\n },\n \"par"
},
{
"path": ".github/FUNDING.yml",
"chars": 303,
"preview": "# These are supported funding model platforms\n\ngithub: marcelklehr # Replace with up to 4 GitHub Sponsors-enabled userna"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.yml",
"chars": 3815,
"preview": "name: Bug Report\ndescription: Create a bug report for floccus\nlabels: ['bug']\nbody:\n - type: markdown\n attributes:\n "
},
{
"path": ".github/ISSUE_TEMPLATE/config.yml",
"chars": 195,
"preview": "blank_issues_enabled: false\ncontact_links:\n - name: Ask a question\n url: https://github.com/floccusAddon/floccus/dis"
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.yml",
"chars": 916,
"preview": "name: Feature Request\ndescription: Create a feature request for floccus\nlabels: ['enhancement']\nbody:\n - type: markdown"
},
{
"path": ".github/dependabot.yml",
"chars": 430,
"preview": "# To get started with Dependabot version updates, you'll need to specify which\n# package ecosystems to update and where "
},
{
"path": ".github/workflows/build.yml",
"chars": 7982,
"preview": "name: Build\n\non:\n pull_request:\n push:\n branches:\n - develop\n - master\n\njobs:\n js:\n runs-on: ubuntu-l"
},
{
"path": ".github/workflows/codeql-analysis.yml",
"chars": 2787,
"preview": "# For most projects, this workflow file will not need changing; you simply need\n# to commit it to your repository.\n#\n# Y"
},
{
"path": ".github/workflows/dependabot-approve.yml",
"chars": 307,
"preview": "name: Dependabot auto approve\non: pull_request\n\njobs:\n build:\n runs-on: ubuntu-latest\n steps:\n - uses: hmarr"
},
{
"path": ".github/workflows/issues.yml",
"chars": 3136,
"preview": "name: New issue workflow\n\non:\n issues:\n types: [opened]\nenv:\n GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n\njobs:\n as"
},
{
"path": ".github/workflows/lock-threads.yml",
"chars": 483,
"preview": "name: 'Lock Threads'\n\non:\n schedule:\n - cron: '0 0 * * *'\n workflow_dispatch:\n\npermissions:\n issues: write\n pull-"
},
{
"path": ".github/workflows/stale.yml",
"chars": 1062,
"preview": "name: 'Close stale issues and PRs'\non:\n schedule:\n - cron: '30 1 * * *'\n\njobs:\n stale:\n runs-on: ubuntu-latest\n "
},
{
"path": ".github/workflows/tests.yml",
"chars": 9673,
"preview": "name: Tests\n\non:\n pull_request:\n push:\n branches:\n - master\n - develop\n paths:\n - 'src/**'\n "
},
{
"path": ".gitignore",
"chars": 103,
"preview": ".*.sw*\ndist\nnode_modules\nbuilds\nkey.pem\n.idea\n.DS_STORE\n\n# Sentry Config File\n.env.sentry-build-plugin\n"
},
{
"path": ".prettierrc",
"chars": 73,
"preview": "{\n \"semi\": false,\n \"singleQuote\": true,\n \"jsxBracketSameLine\": true\n}\n"
},
{
"path": "CHANGELOG.md",
"chars": 54795,
"preview": "# Changelog\n\n## [5.8.6] - 2026-01-23\n\n### Fixed\n\n- fix(Tree): Revert incremental index updates (Would break initial sync"
},
{
"path": "CONSIDERATIONS.md",
"chars": 2437,
"preview": "# Considerations aka. Is this a good idea?\n\nAs there have been debates about whether this software product is a good ide"
},
{
"path": "LICENSE.txt",
"chars": 14778,
"preview": "Floccus\nCopyright (c) 2016 by Marcel Klehr <mklehr@gmx.net>\n\nMozilla Public License, version 2.0\n1. Definitions\n1.1. Con"
},
{
"path": "PRIVACY_POLICY.md",
"chars": 1532,
"preview": "# Privacy policy\n\nThe Floccus browser extension (\"Floccus\") provides browser bookmarks synchronization functionality (“F"
},
{
"path": "README.md",
"chars": 21317,
"preview": "#  Floccus\n\n users:\n# Gradle settings configured through the IDE *will o"
},
{
"path": "android/gradlew",
"chars": 5766,
"preview": "#!/usr/bin/env sh\n\n#\n# Copyright 2015 the original author or authors.\n#\n# Licensed under the Apache License, Version 2.0"
},
{
"path": "android/gradlew.bat",
"chars": 2674,
"preview": "@rem\n@rem Copyright 2015 the original author or authors.\n@rem\n@rem Licensed under the Apache License, Version 2.0 (the \""
},
{
"path": "android/settings.gradle",
"chars": 208,
"preview": "include ':app'\ninclude ':capacitor-cordova-android-plugins'\nproject(':capacitor-cordova-android-plugins').projectDir = n"
},
{
"path": "android/variables.gradle",
"chars": 498,
"preview": "ext {\n minSdkVersion = 23\n compileSdkVersion = 35\n targetSdkVersion = 35\n androidxActivityVersion = '1.9.2'\n"
},
{
"path": "capacitor.config.json",
"chars": 572,
"preview": "{\n \"appId\": \"org.handmadeideas.floccus\",\n \"appName\": \"floccus\",\n \"bundledWebRuntime\": false,\n \"npmClient\": \"npm\",\n "
},
{
"path": "doc/Adapters.md",
"chars": 8616,
"preview": "# Adapters\n\nAn adapter in the context of floccus is a module that implements support for a specific syncing backend. It "
},
{
"path": "doiuse-report.baseline.txt",
"chars": 1408,
"preview": "\n\n\n\n5:4: CSS overflow property only partially supported by: Safari on iOS (15.6-15.8), QQ Browser (14.9) (css-overflow)\n"
},
{
"path": "dropbox-api.credentials.json",
"chars": 998,
"preview": "{\n \"web\": {\n \"client_id\": \"apzybhhq0x0o0gk\",\n \"project_id\": \"apzybhhq0x0o0gk\",\n \"auth_uri\": \"https://www.dropb"
},
{
"path": "fastlane/metadata/android/en-US/full_description.txt",
"chars": 954,
"preview": "Manage and synchronize your bookmarks via Nextcloud, or any WebDAV service, or any Git service, or Google Drive, or Drop"
},
{
"path": "fastlane/metadata/android/en-US/short_description.txt",
"chars": 58,
"preview": "Sync your bookmarks privately across browsers and devices\n"
},
{
"path": "google-api.credentials.json",
"chars": 1022,
"preview": "{\n \"web\":{\n \"client_id\":\"305459871054-4rr6n0jmsdvvprtjqbma5oeksshis2bn.apps.googleusercontent.com\",\"project_id\":\"flo"
},
{
"path": "gulpfile.js",
"chars": 9083,
"preview": "var gulp = require('gulp')\nvar fs = require('fs')\nvar webpack = require('webpack')\nvar config = require('./webpack.prod'"
},
{
"path": "html/background.html",
"chars": 181,
"preview": "<!DOCTYPE html>\n<html>\n<head>\n <meta charset=\"utf-8\">\n <title>Floccus</title>\n</head>\n<body>\n<script src=\"../../li"
},
{
"path": "html/index.html",
"chars": 464,
"preview": "<!DOCTYPE html>\n<html>\n <head>\n <meta charset=\"utf-8\" />\n <meta\n http-equiv=\"Content-Security-Poli"
},
{
"path": "html/options.html",
"chars": 576,
"preview": "<!DOCTYPE html>\n<html>\n <head>\n <meta charset=\"utf-8\" />\n <meta\n name=\"viewport\"\n content=\"user-scalabl"
},
{
"path": "html/test.html",
"chars": 232,
"preview": "<html>\n<head>\n <meta charset=\"utf-8\">\n <title>Mocha Tests</title>\n <link href=\"../css/mocha.css\" rel=\"stylesheet\" />\n"
},
{
"path": "ios/.gitignore",
"chars": 121,
"preview": "App/build\nApp/Pods\nApp/App/public\nDerivedData\nxcuserdata\n\n# Cordova plugins for Capacitor\ncapacitor-cordova-ios-plugins\n"
},
{
"path": "ios/App/App/App.entitlements",
"chars": 308,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ios/App/App/AppDelegate.swift",
"chars": 4131,
"preview": "import UIKit\nimport Capacitor\nimport SendIntent\n\n@UIApplicationMain\nclass AppDelegate: UIResponder, UIApplicationDelegat"
},
{
"path": "ios/App/App/Assets.xcassets/AppIcon.appiconset/Contents.json",
"chars": 241,
"preview": "{\n \"images\" : [\n {\n \"filename\" : \"AppIcon-512@2x.png\",\n \"idiom\" : \"universal\",\n \"platform\" "
},
{
"path": "ios/App/App/Assets.xcassets/Contents.json",
"chars": 62,
"preview": "{\n \"info\" : {\n \"version\" : 1,\n \"author\" : \"xcode\"\n }\n}"
},
{
"path": "ios/App/App/Assets.xcassets/Splash.imageset/Contents.json",
"chars": 403,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"filename\" : \"splash-2732x2732-2.png\",\n \"scale\" : \"1x\"\n "
},
{
"path": "ios/App/App/Base.lproj/LaunchScreen.storyboard",
"chars": 1994,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3"
},
{
"path": "ios/App/App/Base.lproj/Main.storyboard",
"chars": 1019,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3"
},
{
"path": "ios/App/App/Info.plist",
"chars": 2006,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ios/App/App/capacitor.config.json",
"chars": 808,
"preview": "{\n\t\"appId\": \"org.handmadeideas.floccus\",\n\t\"appName\": \"floccus\",\n\t\"bundledWebRuntime\": false,\n\t\"npmClient\": \"npm\",\n\t\"webD"
},
{
"path": "ios/App/App/config.xml",
"chars": 185,
"preview": "<?xml version='1.0' encoding='utf-8'?>\n<widget version=\"1.0.0\" xmlns=\"http://www.w3.org/ns/widgets\" xmlns:cdv=\"http://co"
},
{
"path": "ios/App/App.xcodeproj/project.pbxproj",
"chars": 25993,
"preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 48;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
},
{
"path": "ios/App/App.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
"chars": 148,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n version = \"1.0\">\n <FileRef\n location = \"self:App.xcodeproj\">"
},
{
"path": "ios/App/App.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
"chars": 238,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ios/App/App.xcodeproj/xcshareddata/xcschemes/Floccus New Bookmark.xcscheme",
"chars": 3538,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n LastUpgradeVersion = \"1420\"\n wasCreatedForAppExtension = \"YES\"\n ve"
},
{
"path": "ios/App/App.xcodeproj/xcshareddata/xcschemes/Floccus.xcscheme",
"chars": 2828,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n LastUpgradeVersion = \"1420\"\n version = \"1.3\">\n <BuildAction\n "
},
{
"path": "ios/App/App.xcworkspace/contents.xcworkspacedata",
"chars": 221,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n version = \"1.0\">\n <FileRef\n location = \"group:App.xcodeproj\""
},
{
"path": "ios/App/App.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
"chars": 238,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ios/App/App.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings",
"chars": 226,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ios/App/Floccus New Bookmark/Base.lproj/MainInterface.storyboard",
"chars": 1656,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3"
},
{
"path": "ios/App/Floccus New Bookmark/Floccus New Bookmark.entitlements",
"chars": 308,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ios/App/Floccus New Bookmark/Info.plist",
"chars": 1066,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ios/App/Floccus New Bookmark/ShareViewController.swift",
"chars": 7825,
"preview": "//\n// ShareViewController.swift\n// mindlib\n//\n// Created by Carsten Klaffke on 05.07.20.\n//\n\nimport MobileCoreService"
},
{
"path": "ios/App/Floccus.entitlements",
"chars": 308,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ios/App/Podfile",
"chars": 1566,
"preview": "require_relative '../../node_modules/@capacitor/ios/scripts/pods_helpers'\n\nplatform :ios, '14.0'\nuse_frameworks!\n\n# work"
},
{
"path": "ios/App/PrivacyInfo.xcprivacy",
"chars": 513,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "lib/gulp-crx.js",
"chars": 1341,
"preview": "'use strict'\n\nvar ChromeExtension = require('crx')\nvar through = require('through2')\nvar merge = require('merge')\nvar Fi"
},
{
"path": "manifest-firefox-override.sh",
"chars": 1356,
"preview": "#!/usr/bin/sh\n\n# Local development workaround for Firefox.\n#\n# Once you build this extension (with `npm install` and `np"
},
{
"path": "manifest.chrome.json",
"chars": 949,
"preview": "{\n \"manifest_version\": 3,\n \"name\": \"floccus bookmarks sync\",\n \"short_name\": \"floccus\",\n \"version\": \"5.8.6\",\n \"descr"
},
{
"path": "manifest.firefox.json",
"chars": 1020,
"preview": "{\n \"manifest_version\": 2,\n \"name\": \"floccus bookmarks sync\",\n \"short_name\": \"floccus\",\n \"version\": \"5.8.6\",\n \"descr"
},
{
"path": "manifest.json",
"chars": 936,
"preview": "{\n \"manifest_version\": 3,\n \"name\": \"floccus bookmarks sync\",\n \"short_name\": \"floccus\",\n \"version\": \"5.4.4\",\n \"descr"
},
{
"path": "package.json",
"chars": 4571,
"preview": "{\n \"name\": \"floccus\",\n \"version\": \"5.8.6\",\n \"description\": \"Sync your bookmarks privately across browsers and devices"
},
{
"path": "src/build-fixtures/lazyLoadIntegration.js",
"chars": 100,
"preview": "export function lazyLoadIntegration() {\n throw new Error('Cannot lazy load sources from network')\n}"
},
{
"path": "src/entries/background-script.js",
"chars": 127,
"preview": "import BrowserController from '../lib/browser/BrowserController'\n\nconst controller = new BrowserController\ncontroller.on"
},
{
"path": "src/entries/native.js",
"chars": 41,
"preview": "import app from '../ui/native.js'\n\napp()\n"
},
{
"path": "src/entries/options.js",
"chars": 30,
"preview": "import app from '../ui'\napp()\n"
},
{
"path": "src/entries/test.js",
"chars": 28,
"preview": "require('../test/index.js')\n"
},
{
"path": "src/errors/Error.ts",
"chars": 16305,
"preview": "import { Bookmark, TItemLocation } from '../lib/Tree'\nimport { statusCodes } from '../lib/statusCodes'\n\nexport class Flo"
},
{
"path": "src/lib/Account.ts",
"chars": 17648,
"preview": "import AdapterFactory from './AdapterFactory'\nimport Logger from './Logger'\nimport { ItemLocation, TItemLocation } from "
},
{
"path": "src/lib/AdapterFactory.ts",
"chars": 589,
"preview": "import { TAdapter } from './interfaces/Adapter'\nimport { IAccountData } from './interfaces/AccountStorage'\n\nexport defau"
},
{
"path": "src/lib/CacheTree.ts",
"chars": 782,
"preview": "import CachingAdapter from './adapters/Caching'\nimport { IResource } from './interfaces/Resource'\nimport { Folder, ItemL"
},
{
"path": "src/lib/CachingTreeWrapper.ts",
"chars": 3590,
"preview": "import { CachingResource, ICapabilities, IHashSettings, OrderFolderResource } from './interfaces/Resource'\nimport { Book"
},
{
"path": "src/lib/Controller.ts",
"chars": 5404,
"preview": "import IController from './interfaces/Controller'\n\ndeclare const IS_BROWSER: boolean\n\ninterface FloccusWorker {\n postMe"
},
{
"path": "src/lib/Crypto.ts",
"chars": 3365,
"preview": "import { fromUint8Array, toUint8Array } from 'js-base64'\nimport { murmurhash3_32_gc } from './murmurhash3'\nimport { XXHa"
},
{
"path": "src/lib/DefunctCrypto.js",
"chars": 1946,
"preview": "export default class Crypto {\n static async sha256(message) {\n const msgBuffer = new TextEncoder('utf-8').encode(mes"
},
{
"path": "src/lib/Diff.ts",
"chars": 15709,
"preview": "import { Folder, TItem, ItemType, TItemLocation, ItemLocation, hydrate } from './Tree'\nimport Mappings, { MappingSnapsho"
},
{
"path": "src/lib/LocalTabs.ts",
"chars": 18555,
"preview": "import browser from './browser-api'\nimport Logger from './Logger'\nimport { ICapabilities, IHashSettings, OrderFolderReso"
},
{
"path": "src/lib/Logger.js",
"chars": 4441,
"preview": "/* global DEBUG, IS_BROWSER */\nimport util from 'util'\nimport * as Parallel from 'async-parallel'\nimport packageJson fro"
},
{
"path": "src/lib/Mappings.ts",
"chars": 4503,
"preview": "import { Folder, ItemLocation, ItemType, TItem, TItemLocation, TItemType } from './Tree'\n\ntype InternalItemTypeMapping ="
},
{
"path": "src/lib/PathHelper.js",
"chars": 569,
"preview": "export default class PathHelper {\n static reverseStr(str) {\n return str\n .split('')\n .reverse()\n .joi"
},
{
"path": "src/lib/Scanner.ts",
"chars": 13645,
"preview": "import * as Parallel from 'async-parallel'\nimport Diff, { ActionType, CreateAction, MoveAction, RemoveAction, ReorderAct"
},
{
"path": "src/lib/Tree.ts",
"chars": 18598,
"preview": "import Crypto from './Crypto'\nimport Logger from './Logger'\nimport TResource, { IHashSettings } from './interfaces/Resou"
},
{
"path": "src/lib/adapters/Caching.ts",
"chars": 9005,
"preview": "import * as Tree from '../Tree'\nimport { Bookmark, Folder, ItemLocation, TItemLocation } from '../Tree'\nimport Logger fr"
},
{
"path": "src/lib/adapters/Dropbox.ts",
"chars": 34723,
"preview": "import CachingAdapter from './Caching'\nimport Logger from '../Logger'\nimport XbelSerializer from '../serializers/Xbel'\ni"
},
{
"path": "src/lib/adapters/Fake.js",
"chars": 410,
"preview": "import CachingAdapter from './Caching'\n\nexport default class FakeAdapter extends CachingAdapter {\n constructor(server) "
},
{
"path": "src/lib/adapters/Git.ts",
"chars": 15181,
"preview": "import * as git from 'isomorphic-git'\nimport http from 'isomorphic-git/http/web'\n// eslint-disable-next-line @typescript"
},
{
"path": "src/lib/adapters/GoogleDrive.ts",
"chars": 18658,
"preview": "import CachingAdapter from './Caching'\nimport Logger from '../Logger'\nimport XbelSerializer from '../serializers/Xbel'\ni"
},
{
"path": "src/lib/adapters/Karakeep.ts",
"chars": 15113,
"preview": "import Adapter from '../interfaces/Adapter'\nimport { Bookmark, Folder, ItemLocation } from '../Tree'\nimport PQueue from "
},
{
"path": "src/lib/adapters/Linkwarden.ts",
"chars": 11278,
"preview": "import Adapter from '../interfaces/Adapter'\nimport { Bookmark, Folder, ItemLocation } from '../Tree'\nimport PQueue from "
},
{
"path": "src/lib/adapters/NextcloudBookmarks.ts",
"chars": 34725,
"preview": "// Nextcloud ADAPTER\nimport { CapacitorHttp as Http } from '@capacitor/core'\nimport Adapter from '../interfaces/Adapter'"
},
{
"path": "src/lib/adapters/WebDav.ts",
"chars": 18641,
"preview": "import CachingAdapter from './Caching'\nimport XbelSerializer from '../serializers/Xbel'\nimport Logger from '../Logger'\ni"
},
{
"path": "src/lib/browser/BrowserAccount.ts",
"chars": 7110,
"preview": "import BrowserAccountStorage from './BrowserAccountStorage'\nimport BrowserTree from './BrowserTree'\nimport browser from "
},
{
"path": "src/lib/browser/BrowserAccountStorage.js",
"chars": 5087,
"preview": "import browser from '../browser-api'\nimport Cryptography from '../Crypto'\nimport DefunctCryptography from '../DefunctCry"
},
{
"path": "src/lib/browser/BrowserController.js",
"chars": 18305,
"preview": "import browser from '../browser-api'\nimport Controller from '../Controller'\nimport BrowserAccount from './BrowserAccount"
},
{
"path": "src/lib/browser/BrowserDetection.ts",
"chars": 226,
"preview": "export const isVivaldi = async() => {\n const {default: browser} = await import('../browser-api.js')\n const tabs = awai"
},
{
"path": "src/lib/browser/BrowserTree.ts",
"chars": 14920,
"preview": "import browser from '../browser-api'\nimport Logger from '../Logger'\nimport * as Tree from '../Tree'\nimport { ICapabiliti"
},
{
"path": "src/lib/browser-api.js",
"chars": 2055,
"preview": "/* global chrome browser */\n\nconst ChromePromise = (function(root) {\n 'use strict'\n var push = Array.prototype.push,\n "
},
{
"path": "src/lib/getFavicon.js",
"chars": 2451,
"preview": "export function getIcons(html, pageUrl) {\n const url = new URL(pageUrl)\n const parser = new DOMParser()\n const docume"
},
{
"path": "src/lib/interfaces/Account.ts",
"chars": 492,
"preview": "import { IAccountData } from './AccountStorage'\nimport Account from '../Account'\n\nexport default interface IAccount {\n "
},
{
"path": "src/lib/interfaces/AccountStorage.ts",
"chars": 1232,
"preview": "import Mappings from '../Mappings'\nimport { Folder, ItemLocation } from '../Tree'\nimport { ISerializedSyncProcess } from"
},
{
"path": "src/lib/interfaces/Adapter.ts",
"chars": 541,
"preview": "import { Bookmark, ItemLocation, TItemLocation } from '../Tree'\nimport TResource from './Resource'\nimport { IAccountData"
},
{
"path": "src/lib/interfaces/Controller.ts",
"chars": 586,
"preview": "export default interface IController {\n setEnabled(enabled:boolean): void;\n unlock(key):Promise<void>;\n scheduleSync("
},
{
"path": "src/lib/interfaces/Ordering.ts",
"chars": 233,
"preview": "import { TItemLocation, TItemType } from '../Tree'\n\nexport interface OrderingItem<L extends TItemLocation> {\n type: TIt"
},
{
"path": "src/lib/interfaces/Resource.ts",
"chars": 2044,
"preview": "import { Bookmark, Folder, ItemLocation, TItem, TItemLocation } from '../Tree'\nimport Ordering from './Ordering'\n\nexport"
},
{
"path": "src/lib/interfaces/Serializer.ts",
"chars": 213,
"preview": "import { Folder, ItemLocation } from '../Tree'\n\nexport default interface Serializer {\n serialize(folder:Folder<typeof I"
},
{
"path": "src/lib/isTest.ts",
"chars": 113,
"preview": "export const isTest = typeof window !== 'undefined' && (new URL(window.location.href)).pathname.includes('test')\n"
},
{
"path": "src/lib/murmurhash3.js",
"chars": 2113,
"preview": "/**\n * JS Implementation of MurmurHash3 (r136) (as of May 20, 2011)\n *\n * @author <a href=\"mailto:gary.court@gmail.com\">"
},
{
"path": "src/lib/native/I18n.ts",
"chars": 2849,
"preview": "import IntlMessageFormat from 'intl-messageformat'\nimport DEFAULT_MESSAGES from '../../../_locales/en/messages.json'\n\n//"
},
{
"path": "src/lib/native/NativeAccount.ts",
"chars": 5200,
"preview": "import NativeAccountStorage from './NativeAccountStorage'\nimport NativeTree from './NativeTree'\nimport AdapterFactory fr"
},
{
"path": "src/lib/native/NativeAccountStorage.js",
"chars": 4577,
"preview": "import { Preferences as Storage } from '@capacitor/preferences'\nimport Cryptography from '../Crypto'\nimport DefunctCrypt"
},
{
"path": "src/lib/native/NativeController.js",
"chars": 9210,
"preview": "import { Preferences as Storage } from '@capacitor/preferences'\nimport { Network } from '@capacitor/network'\nimport Cryp"
},
{
"path": "src/lib/native/NativeTree.ts",
"chars": 3788,
"preview": "import { Preferences as Storage } from '@capacitor/preferences'\nimport { Bookmark, Folder, ItemLocation, TItemLocation }"
},
{
"path": "src/lib/on-wake-up.ts",
"chars": 343,
"preview": "const CLOCK = 1000\nconst TIMEOUT = 2 * 60 * 1000 // 2 mins\n\nexport function onWakeUp(fn: () => void) {\n let then = Date"
},
{
"path": "src/lib/sentry.ts",
"chars": 607,
"preview": "import packageJson from '../../package.json'\nimport { setTag, init } from '@sentry/browser'\nimport { Capacitor } from '@"
},
{
"path": "src/lib/serializers/Html.ts",
"chars": 3575,
"preview": "import Serializer from '../interfaces/Serializer'\nimport { Bookmark, Folder, ItemLocation, TItem } from '../Tree'\nimport"
},
{
"path": "src/lib/serializers/Xbel.ts",
"chars": 3098,
"preview": "import Serializer from '../interfaces/Serializer'\nimport { Bookmark, Folder, ItemLocation } from '../Tree'\nimport { XMLP"
},
{
"path": "src/lib/statusCodes.ts",
"chars": 509,
"preview": "export const statusCodes = {\n 100: 'Continue',\n 101: 'Switching Protocols',\n 200: 'OK',\n 201: 'Created',\n 204: 'No "
},
{
"path": "src/lib/strategies/Default.ts",
"chars": 66083,
"preview": "import {\n Bookmark,\n Folder,\n TItem,\n ItemType,\n ItemLocation,\n TItemLocation,\n TOppositeLocation,\n} from '../Tre"
},
{
"path": "src/lib/strategies/Merge.ts",
"chars": 11833,
"preview": "import { Folder, ItemLocation, TItem, TItemLocation, TOppositeLocation } from '../Tree'\nimport Diff, { CreateAction, Mov"
},
{
"path": "src/lib/strategies/Unidirectional.ts",
"chars": 16517,
"preview": "import DefaultStrategy, { ISerializedSyncProcess , ACTION_CONCURRENCY } from './Default'\nimport Diff, { Action, ActionTy"
},
{
"path": "src/lib/yieldToEventLoop.ts",
"chars": 99,
"preview": "export async function yieldToEventLoop() {\n await new Promise(resolve => setTimeout(resolve, 0))\n}"
},
{
"path": "src/test/index.js",
"chars": 526,
"preview": "import { createWebdriverAndHtmlReporter } from './reporter'\nimport util from 'util'\n\n// Make logs accessible to travis s"
},
{
"path": "src/test/reporter.js",
"chars": 2403,
"preview": "/* global Mocha */\nconst {\n EVENT_RUN_END,\n EVENT_TEST_BEGIN,\n EVENT_TEST_FAIL,\n EVENT_TEST_PASS,\n EVENT_SUITE_BEGI"
},
{
"path": "src/test/test.js",
"chars": 327050,
"preview": "import chai from 'chai'\nimport chaiAsPromised from 'chai-as-promised'\nimport random from 'random'\nimport seedrandom from"
},
{
"path": "src/ui/App.vue",
"chars": 5398,
"preview": "<template>\n <v-app\n id=\"app\"\n :style=\"appStyle\">\n <v-banner\n v-if=\"isBrowser\"\n color=\"primary\"\n "
},
{
"path": "src/ui/NativeApp.vue",
"chars": 1727,
"preview": "<template>\n <v-app\n id=\"app\"\n :style=\"{ background }\">\n <router-view />\n </v-app>\n</template>\n\n<script>\nimpor"
},
{
"path": "src/ui/NativeRouter.js",
"chars": 2009,
"preview": "import Vue from 'vue'\nimport Router from 'vue-router'\nimport Tree from './views/native/Tree'\nimport Home from './views/n"
},
{
"path": "src/ui/components/AccountCard.vue",
"chars": 10498,
"preview": "<template>\n <v-card\n :loading=\"Boolean(account.data.syncing)\"\n color=\"light-blue-lighten-5\">\n <template #progr"
},
{
"path": "src/ui/components/NextcloudLogin.vue",
"chars": 2231,
"preview": "<template>\n <div>\n <v-text-field\n :value=\"username\"\n :label=\"t('LabelUsername')\"\n :loading=\"isRunning"
},
{
"path": "src/ui/components/OptionAllowRedirects.vue",
"chars": 546,
"preview": "<template>\n <div>\n <div class=\"text-h6\">\n {{ t('LabelAllowredirects') }}\n </div>\n <div class=\"caption\">\n "
},
{
"path": "src/ui/components/OptionAutoSync.vue",
"chars": 542,
"preview": "<template>\n <div>\n <div class=\"text-h6\">\n {{ t('LabelAutosync') }}\n </div>\n <div class=\"caption\">\n {"
},
{
"path": "src/ui/components/OptionClientCert.vue",
"chars": 530,
"preview": "<template>\n <div>\n <div class=\"text-h6\">\n {{ t('LabelClientcert') }}\n </div>\n <div class=\"caption\">\n "
},
{
"path": "src/ui/components/OptionDeleteAccount.vue",
"chars": 579,
"preview": "<template>\n <div>\n <div class=\"text-h6\">\n {{ t('LabelRemoveaccount') }}\n </div>\n <div class=\"caption\">\n "
},
{
"path": "src/ui/components/OptionDownloadLogs.vue",
"chars": 780,
"preview": "<template>\n <div>\n <div class=\"text-h6\">\n {{ t('LabelDownloadlogs') }}\n </div>\n <div class=\"caption\">\n "
},
{
"path": "src/ui/components/OptionExportBookmarks.vue",
"chars": 519,
"preview": "<template>\n <div>\n <div class=\"text-h6\">\n {{ t('LabelExportBookmarks') }}\n </div>\n <div class=\"caption\">\n"
},
{
"path": "src/ui/components/OptionFailsafe.vue",
"chars": 609,
"preview": "<template>\n <div>\n <div class=\"text-h6\">\n {{ t('LabelFailsafe') }}\n </div>\n <div class=\"caption\">\n {"
},
{
"path": "src/ui/components/OptionFileType.vue",
"chars": 610,
"preview": "<template>\n <div>\n <div class=\"text-h6\">\n {{ t('LabelFiletype') }}\n </div>\n <div class=\"caption\">\n {"
},
{
"path": "src/ui/components/OptionNestedSync.vue",
"chars": 620,
"preview": "<template>\n <div>\n <div class=\"text-h6\">\n {{ t('LabelNestedSync') }}\n </div>\n <div class=\"caption\">\n "
},
{
"path": "src/ui/components/OptionPassphrase.vue",
"chars": 1595,
"preview": "<template>\n <div>\n <div class=\"text-h6\">\n {{ t('LabelPassphrase') }}\n </div>\n <div class=\"caption\">\n "
},
{
"path": "src/ui/components/OptionResetCache.vue",
"chars": 408,
"preview": "<template>\n <div>\n <div class=\"text-h6\">\n {{ t('LabelSyncfromscratch') }}\n </div>\n <div class=\"caption\">\n"
}
]
// ... and 68 more files (download for full content)
About this extraction
This page contains the full source code of the floccusaddon/floccus GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 268 files (2.2 MB), approximately 583.0k tokens, and a symbol index with 942 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.